PageSourceSearch

https://azurecdn.toastmasters.org/cassette.axd/asset/skins/scripts…?5cb2498e3629a4282db3938be3f363fa388c415b

js toastmasters.org collected 2026-10-01 07:14:51 UTC 758,716 bytes, 20,874 lines download raw bytes

1/**
2 * @license AngularJS v1.2.13
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.13/' +
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    -hasOwnProperty,
164
165*/
166
167////////////////////////////////////
168
169/**
170 * @ngdoc function
171 * @name angular.lowercase
172 * @function
173 *
174 * @description Converts the specified string to lowercase.
175 * @param {string} string String to be converted to lowercase.
176 * @returns {string} Lowercased string.
177 */
178var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
179var hasOwnProperty = Object.prototype.hasOwnProperty;
180
181/**
182 * @ngdoc function
183 * @name angular.uppercase
184 * @function
185 *
186 * @description Converts the specified string to uppercase.
187 * @param {string} string String to be converted to uppercase.
188 * @returns {string} Uppercased string.
189 */
190var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
191
192
193var manualLowercase = function(s) {
194  /* jshint bitwise: false */
195  return isString(s)
196      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
197      : s;
198};
199var manualUppercase = function(s) {
200  /* jshint bitwise: false */
201  return isString(s)
202      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
203      : s;
204};
205
206
207// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
208// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
209// with correct but slower alternatives.
210if ('i' !== 'I'.toLowerCase()) {
211  lowercase = manualLowercase;
212  uppercase = manualUppercase;
213}
214
215
216var /** holds major version number for IE or NaN for real browsers */
217    msie,
218    jqLite,           // delay binding since jQuery could be loaded after us.
219    jQuery,           // delay binding
220    slice             = [].slice,
221    push              = [].push,
222    toString          = Object.prototype.toString,
223    ngMinErr          = minErr('ng'),
224
225
226    _angular          = window.angular,
227    /** @name angular */
228    angular           = window.angular || (window.angular = {}),
229    angularModule,
230    nodeName_,
231    uid               = ['0', '0', '0'];
232
233/**
234 * IE 11 changed the format of the UserAgent string.
235 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
236 */
237msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
238if (isNaN(msie)) {
239  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
240}
241
242
243/**
244 * @private
245 * @param {*} obj
246 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
247 *                   String ...)
248 */
249function isArrayLike(obj) {
250  if (obj == null || isWindow(obj)) {
251    return false;
252  }
253
254  var length = obj.length;
255
256  if (obj.nodeType === 1 && length) {
257    return true;
258  }
259
260  return isString(obj) || isArray(obj) || length === 0 ||
261         typeof length === 'number' && length > 0 && (length - 1) in obj;
262}
263
264/**
265 * @ngdoc function
266 * @name angular.forEach
267 * @function
268 *
269 * @description
270 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
271 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
272 * is the value of an object property or an array element and `key` is the object property key or
273 * array element index. Specifying a `context` for the function is optional.
274 *
275 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
276 * using the `hasOwnProperty` method.
277 *
278   <pre>
279     var values = {name: 'misko', gender: 'male'};
280     var log = [];
281     angular.forEach(values, function(value, key){
282       this.push(key + ': ' + value);
283     }, log);
284     expect(log).toEqual(['name: misko', 'gender: male']);
285   </pre>
286 *
287 * @param {Object|Array} obj Object to iterate over.
288 * @param {Function} iterator Iterator function.
289 * @param {Object=} context Object to become context (`this`) for the iterator function.
290 * @returns {Object|Array} Reference to `obj`.
291 */
292function forEach(obj, iterator, context) {
293  var key;
294  if (obj) {
295    if (isFunction(obj)){
296      for (key in obj) {
297        // Need to check if hasOwnProperty exists,
298        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
299        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
300          iterator.call(context, obj[key], key);
301        }
302      }
303    }
303 else if (obj.forEach && obj.forEach !== forEach) {
304      obj.forEach(iterator, context);
305    } else if (isArrayLike(obj)) {
306      for (key = 0; key < obj.length; key++)
307        iterator.call(context, obj[key], key);
308    } else {
309      for (key in obj) {
310        if (obj.hasOwnProperty(key)) {
311          iterator.call(context, obj[key], key);
312        }
313      }
314    }
315  }
316  return obj;
317}
318
319function sortedKeys(obj) {
320  var keys = [];
321  for (var key in obj) {
322    if (obj.hasOwnProperty(key)) {
323      keys.push(key);
324    }
325  }
326  return keys.sort();
327}
328
329function forEachSorted(obj, iterator, context) {
330  var keys = sortedKeys(obj);
331  for ( var i = 0; i < keys.length; i++) {
332    iterator.call(context, obj[keys[i]], keys[i]);
333  }
334  return keys;
335}
336
337
338/**
339 * when using forEach the params are value, key, but it is often useful to have key, value.
340 * @param {function(string, *)} iteratorFn
341 * @returns {function(*, string)}
342 */
343function reverseParams(iteratorFn) {
344  return function(value, key) { iteratorFn(key, value); };
345}
346
347/**
348 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
349 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
350 * the number string gets longer over time, and it can also overflow, where as the nextId
351 * will grow much slower, it is a string, and it will never overflow.
352 *
353 * @returns an unique alpha-numeric string
354 */
355function nextUid() {
356  var index = uid.length;
357  var digit;
358
359  while(index) {
360    index--;
361    digit = uid[index].charCodeAt(0);
362    if (digit == 57 /*'9'*/) {
363      uid[index] = 'A';
364      return uid.join('');
365    }
366    if (digit == 90  /*'Z'*/) {
367      uid[index] = '0';
368    } else {
369      uid[index] = String.fromCharCode(digit + 1);
370      return uid.join('');
371    }
372  }
373  uid.unshift('0');
374  return uid.join('');
375}
376
377
378/**
379 * Set or clear the hashkey for an object.
380 * @param obj object
381 * @param h the hashkey (!truthy to delete the hashkey)
382 */
383function setHashKey(obj, h) {
384  if (h) {
385    obj.$$hashKey = h;
386  }
387  else {
388    delete obj.$$hashKey;
389  }
390}
391
392/**
393 * @ngdoc function
394 * @name angular.extend
395 * @function
396 *
397 * @description
398 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
399 * to `dst`. You can specify multiple `src` objects.
400 *
401 * @param {Object} dst Destination object.
402 * @param {...Object} src Source object(s).
403 * @returns {Object} Reference to `dst`.
404 */
405function extend(dst) {
406  var h = dst.$$hashKey;
407  forEach(arguments, function(obj){
408    if (obj !== dst) {
409      forEach(obj, function(value, key){
410        dst[key] = value;
411      });
412    }
413  });
414
415  setHashKey(dst,h);
416  return dst;
417}
418
419function int(str) {
420  return parseInt(str, 10);
421}
422
423
424function inherit(parent, extra) {
425  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
426}
427
428/**
429 * @ngdoc function
430 * @name angular.noop
431 * @function
432 *
433 * @description
434 * A function that performs no operations. This function can be useful when writing code in the
435 * functional style.
436   <pre>
437     function foo(callback) {
438       var result = calculateResult();
439       (callback || angular.noop)(result);
440     }
441   </pre>
442 */
443function noop() {}
444noop.$inject = [];
445
446
447/**
448 * @ngdoc function
449 * @name angular.identity
450 * @function
451 *
452 * @description
453 * A function that returns its first argument. This function is useful when writing code in the
454 * functional style.
455 *
456   <pre>
457     function transformer(transformationFn, value) {
458       return (transformationFn || angular.identity)(value);
459     };
460   </pre>
461 */
462function identity($) {return $;}
463identity.$inject = [];
464
465
466function valueFn(value) {return function() {return value;};}
467
468/**
469 * @ngdoc function
470 * @name angular.isUndefined
471 * @function
472 *
473 * @description
474 * Determines if a reference is undefined.
475 *
476 * @param {*} value Reference to check.
477 * @returns {boolean} True if `value` is undefined.
478 */
479function isUndefined(value){return typeof value === 'undefined';}
480
481
482/**
483 * @ngdoc function
484 * @name angular.isDefined
485 * @function
486 *
487 * @description
488 * Determines if a reference is defined.
489 *
490 * @param {*} value Reference to check.
491 * @returns {boolean} True if `value` is defined.
492 */
493function isDefined(value){return typeof value !== 'undefined';}
494
495
496/**
497 * @ngdoc function
498 * @name angular.isObject
499 * @function
500 *
501 * @description
502 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
503 * considered to be objects.
504 *
505 * @param {*} value Reference to check.
506 * @returns {boolean} True if `value` is an `Object` but not `null`.
507 */
508function isObject(value){return value != null && typeof value === 'object';}
509
510
511/**
512 * @ngdoc function
513 * @name angular.isString
514 * @function
515 *
516 * @description
517 * Determines if a reference is a `String`.
518 *
519 * @param {*} value Reference to check.
520 * @returns {boolean} True if `value` is a `String`.
521 */
522function isString(value){return typeof value === 'string';}
523
524
525/**
526 * @ngdoc function
527 * @name angular.isNumber
528 * @function
529 *
530 * @description
531 * Determines if a reference is a `Number`.
532 *
533 * @param {*} value Reference to check.
534 * @returns {boolean} True if `value` is a `Number`.
535 */
536function isNumber(value){return typeof value === 'number';}
537
538
539/**
540 * @ngdoc function
541 * @name angular.isDate
542 * @function
543 *
544 * @description
545 * Determines if a value is a date.
546 *
547 * @param {*} value Reference to check.
548 * @returns {boolean} True if `value` is a `Date`.
549 */
550function isDate(value){
551  return toString.call(value) === '[object Date]';
552}
553
554
555/**
556 * @ngdoc function
557 * @name angular.isArray
558 * @function
559 *
560 * @description
561 * Determines if a reference is an `Array`.
562 *
563 * @param {*} value Reference to check.
564 * @returns {boolean} True if `value` is an `Array`.
565 */
566function isArray(value) {
567  return toString.call(value) === '[object Array]';
568}
569
570
571/**
572 * @ngdoc function
573 * @name angular.isFunction
574 * @function
575 *
576 * @description
577 * Determines if a reference is a `Function`.
578 *
579 * @param {*} value Reference to check.
580 * @returns {boolean} True if `value` is a `Function`.
581 */
582function isFunction(value){return typeof value === 'function';}
583
584
585/**
586 * Determines if a value is a regular expression object.
587 *
588 * @private
589 * @param {*} value Reference to check.
590 * @returns {boolean} True if `value` is a `RegExp`.
591 */
592function isRegExp(value) {
593  return toString.call(value) === '[object RegExp]';
594}
595
596
597/**
598 * Checks if `obj` is a window object.
599 *
600 * @private
601 * @param {*} obj Object to check
602 * @returns {boolean} True if `obj` is a window obj.
603 */
604function isWindow(obj) {
605  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
606}
607
608
609function isScope(obj) {
610  return obj && obj.$evalAsync && obj.$watch;
611}
612
613
614function isFile(obj) {
615  return toString.call(obj) === '[object File]';
616}
617
618
619function isBoolean(value) {
620  return typeof value === 'boolean';
621}
622
623
624var trim = (function() {
625  // native trim is way faster: http://jsperf.com/angular-trim-test
626  // but IE doesn't have it... :-(
627  // TODO: we should move this into IE/ES5 polyfill
628  if (!String.prototype.trim) {
629    return function(value) {
630      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
631    };
632  }
633  return function(value) {
634    return isString(value) ? value.trim() : value;
635  };
636})();
637
638
639/**
640 * @ngdoc function
641 * @name angular.isElement
642 * @function
643 *
644 * @description
645 * Determines if a reference is a DOM element (or wrapped jQuery element).
646 *
647 * @param {*} value Reference to check.
648 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
649 */
650function isElement(node) {
651  return !!(node &&
652    (node.nodeName  // we are a direct element
653    || (node.on && node.find)));  // we have an on and find method part of jQuery API
654}
655
656/**
657 * @param str 'key1,key2,...'
658 * @returns {object} in the form of {key1:true, key2:true, ...}
659 */
660function makeMap(str){
661  var obj = {}, items = str.split(","), i;
662  for ( i = 0; i < items.length; i++ )
663    obj[ items[i] ] = true;
664  return obj;
665}
666
667
668if (msie < 9) {
669  nodeName_ = function(element) {
670    element = element.nodeName ? element : element[0];
671    return (element.scopeName && element.scopeName != 'HTML')
672      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
673  };
674} else {
675  nodeName_ = function(element) {
676    return element.nodeName ? element.nodeName : element[0].nodeName;
677  };
678}
679
680
681function map(obj, iterator, context) {
682  var results = [];
683  forEach(obj, function(value, index, list) {
684    results.push(iterator.call(context, value, index, list));
685  });
686  return results;
687}
688
689
690/**
691 * @description
692 * Determines the number of elements in an array, the number of properties an object has, or
693 * the length of a string.
694 *
695 * Note: This function is used to augment the Object type in Angular expressions. See
696 * {@link angular.Object} for more information about Angular arrays.
697 *
698 * @param {Object|Array|string} obj Object, array, or string to inspect.
699 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
700 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
701 */
702function size(obj, ownPropsOnly) {
703  var count = 0, key;
704
705  if (isArray(obj) || isString(obj)) {
706    return obj.length;
707  } else if (isObject(obj)){
708    for (key in obj)
709      if (!ownPropsOnly || obj.hasOwnProperty(key))
710        count++;
711  }
712
713  return count;
714}
715
716
717function includes(array, obj) {
718  return indexOf(array, obj) != -1;
719}
720
721function indexOf(array, obj) {
722  if (array.indexOf) return array.indexOf(obj);
723
724  for (var i = 0; i < array.length; i++) {
725    if (obj === array[i]) return i;
726  }
727  return -1;
728}
729
730function arrayRemove(array, value) {
731  var index = indexOf(array, value);
732  if (index >=0)
733    array.splice(index, 1);
734  return value;
735}
736
737function isLeafNode (node) {
738  if (node) {
739    switch (node.nodeName) {
740    case "OPTION":
741    case "PRE":
742    case "TITLE":
743      return true;
744    }
745  }
746  return false;
747}
748
749/**
750 * @ngdoc function
751 * @name angular.copy
752 * @function
753 *
754 * @description
755 * Creates a deep copy of `source`, which should be an object or an array.
756 *
757 * * If no destination is supplied, a copy of the object or array is created.
758 * * If a destination is provided, all of its elements (for array) or properties (for objects)
759 *   are deleted and then all elements/properties from the source are copied to it.
760 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
761 * * If `source` is identical to 'destination' an exception will be thrown.
762 *
763 * @param {*} source The source that will be used to make a copy.
764 *                   Can be any type, including primitives, `null`, and `undefined`.
765 * @param {(Object|Array)=} destination Destination into which the source is copied. If
766 *     provided, must be of the same type as `source`.
767 * @returns {*} The copy or updated `destination`, if `destination` was specified.
768 *
769 * @example
770 <doc:example>
771 <doc:source>
772 <div ng-controller="Controller">
773 <form novalidate class="simple-form">
774 Name: <input type="text" ng-model="user.name" /><br />
775 E-mail: <input type="email" ng-model="user.email" /><br />
776 Gender: <input type="radio" ng-model="user.gender" value="male" />male
777 <input type="radio" ng-model="user.gender" value="female" />female<br />
778 <button ng-click="reset()">RESET</button>
779 <button ng-click="update(user)">SAVE</button>
780 </form>
781 <pre>form = {{user | json}}</pre>
782 <pre>master = {{master | json}}</pre>
783 </div>
784
785 <script>
786 function Controller($scope) {
787    $scope.master= {};
788
789    $scope.update = function(user) {
790      // Example with 1 argument
791      $scope.master= angular.copy(user);
792    };
793
794    $scope.reset = function() {
795      // Example with 2 arguments
796      angular.copy($scope.master, $scope.user);
797    };
798
799    $scope.reset();
800  }
801 </script>
802 </doc:source>
803 </doc:example>
804 */
805function copy(source, destination){
806  if (isWindow(source) || isScope(source)) {
807    throw ngMinErr('cpws',
808      "Can't copy! Making copies of Window or Scope instances is not supported.");
809  }
810
811  if (!destination) {
812    destination = source;
813    if (source) {
814      if (isArray(source)) {
815        destination = copy(source, []);
816      } else if (isDate(source)) {
817        destination = new Date(source.getTime());
818      } else if (isRegExp(source)) {
819        destination = new RegExp(source.source);
820      } else if (isObject(source)) {
821        destination = copy(source, {});
822      }
823    }
824  } else {
825    if (source === destination) throw ngMinErr('cpi',
826      "Can't copy! Source and destination are identical.");
827    if (isArray(source)) {
828      destination.length = 0;
829      for ( var i = 0; i < source.length; i++) {
830        destination.push(copy(source[i]));
831      }
832    } else {
833      var h = destination.$$hashKey;
834      forEach(destination, function(value, key){
835        delete destination[key];
836      });
837      for ( var key in source) {
838        destination[key] = copy(source[key]);
839      }
840      setHashKey(destination,h);
841    }
842  }
843  return destination;
844}
845
846/**
847 * Create a shallow copy of an object
848 */
849function shallowCopy(src, dst) {
850  dst = dst || {};
851
852  for(var key in src) {
853    // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
854    // so we don't need to worry about using our custom hasOwnProperty here
855    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
856      dst[key] = src[key];
857    }
858  }
859
860  return dst;
861}
862
863
864/**
865 * @ngdoc function
866 * @name angular.equals
867 * @function
868 *
869 * @description
870 * Determines if two objects or two values are equivalent. Supports value types, regular
871 * expressions, arrays and objects.
872 *
873 * Two objects or values are considered equivalent if at least one of the following is true:
874 *
875 * * Both objects or values pass `===` comparison.
876 * * Both objects or values are of the same type and all of their properties are equal by
877 *   comparing them with `angular.equals`.
878 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
879 * * Both values represent the same regular expression (In JavasScript,
880 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
881 *   representation matches).
882 *
883 * During a property comparison, properties of `function` type and properties with names
884 * that begin with `$` are ignored.
885 *
886 * Scope and DOMWindow objects are being compared only by identify (`===`).
887 *
888 * @param {*} o1 Object or value to compare.
889 * @param {*} o2 Object or value to compare.
890 * @returns {boolean} True if arguments are equal.
891 */
892function equals(o1, o2) {
893  if (o1 === o2) return true;
894  if (o1 === null || o2 === null) return false;
895  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
896  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
897  if (t1 == t2) {
898    if (t1 == 'object') {
899      if (isArray(o1)) {
900        if (!isArray(o2)) return false;
901        if ((length = o1.length) == o2.length) {
902          for(key=0; key<length; key++) {
903            if (!equals(o1[key], o2[key])) return false;
904          }
905          return true;
906        }
907      } else if (isDate(o1)) {
908        return isDate(o2) && o1.getTime() == o2.getTime();
909      } else if (isRegExp(o1) && isRegExp(o2)) {
910        return o1.toString() == o2.toString();
911      } else {
912        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
913        keySet = {};
914        for(key in o1) {
915          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
916          if (!equals(o1[key], o2[key])) return false;
917          keySet[key] = true;
918        }
919        for(key in o2) {
920          if (!keySet.hasOwnProperty(key) &&
921              key.charAt(0) !== '$' &&
922              o2[key] !== undefined &&
923              !isFunction(o2[key])) return false;
924        }
925        return true;
926      }
927    }
928  }
929  return false;
930}
931
932
933function csp() {
934  return (document.securityPolicy && document.securityPolicy.isActive) ||
935      (document.querySelector &&
936      !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
937}
938
939
940function concat(array1, array2, index) {
941  return array1.concat(slice.call(array2, index));
942}
943
944function sliceArgs(args, startIndex) {
945  return slice.call(args, startIndex || 0);
946}
947
948
949/* jshint -W101 */
950/**
951 * @ngdoc function
952 * @name angular.bind
953 * @function
954 *
955 * @description
956 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
957 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
958 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
959 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
960 *
961 * @param {Object} self Context which `fn` should be evaluated in.
962 * @param {function()} fn Function to be bound.
963 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
964 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
965 */
966/* jshint +W101 */
967function bind(self, fn) {
968  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
969  if (isFunction(fn) && !(fn instanceof RegExp)) {
970    return curryArgs.length
971      ? function() {
972          return arguments.length
973            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
974            : fn.apply(self, curryArgs);
975        }
976      : function() {
977          return arguments.length
978            ? fn.apply(self, arguments)
979            : fn.call(self);
980        };
981  } else {
982    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
983    return fn;
984  }
985}
986
987
988function toJsonReplacer(key, value) {
989  var val = value;
990
991  if (typeof key === 'string' && key.charAt(0) === '$') {
992    val = undefined;
993  } else if (isWindow(value)) {
994    val = '$WINDOW';
995  } else if (value &&  document === value) {
996    val = '$DOCUMENT';
997  } else if (isScope(value)) {
998    val = '$SCOPE';
999  }
1000
1001  return val;
1002}
1003
1004
1005/**
1006 * @ngdoc function
1007 * @name angular.toJson
1008 * @function
1009 *
1010 * @description
1011 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1012 * stripped since angular uses this notation internally.
1013 *
1014 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1015 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
1016 * @returns {string|undefined} JSON-ified string representing `obj`.
1017 */
1018function toJson(obj, pretty) {
1019  if (typeof obj === 'undefined') return undefined;
1020  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1021}
1022
1023
1024/**
1025 * @ngdoc function
1026 * @name angular.fromJson
1027 * @function
1028 *
1029 * @description
1030 * Deserializes a JSON string.
1031 *
1032 * @param {string} json JSON string to deserialize.
1033 * @returns {Object|Array|Date|string|number} Deserialized thingy.
1034 */
1035function fromJson(json) {
1036  return isString(json)
1037      ? JSON.parse(json)
1038      : json;
1039}
1040
1041
1042function toBoolean(value) {
1043  if (typeof value === 'function') {
1044    value = true;
1045  } else if (value && value.length !== 0) {
1046    var v = lowercase("" + value);
1047    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1048  } else {
1049    value = false;
1050  }
1051  return value;
1052}
1053
1054/**
1055 * @returns {string} Returns the string representation of the element.
1056 */
1057function startingTag(element) {
1058  element = jqLite(element).clone();
1059  try {
1060    // turns out IE does not let you set .html() on elements which
1061    // are not allowed to have children. So we just ignore it.
1062    element.empty();
1063  } catch(e) {}
1064  // As Per DOM Standards
1065  var TEXT_NODE = 3;
1066  var elemHtml = jqLite('<div>').append(element).html();
1067  try {
1068    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1069        elemHtml.
1070          match(/^(<[^>]+>)/)[1].
1071          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1072  } catch(e) {
1073    return lowercase(elemHtml);
1074  }
1075
1076}
1077
1078
1079/////////////////////////////////////////////////
1080
1081/**
1082 * Tries to decode the URI component without throwing an exception.
1083 *
1084 * @private
1085 * @param str value potential URI component to check.
1086 * @returns {boolean} True if `value` can be decoded
1087 * with the decodeURIComponent function.
1088 */
1089function tryDecodeURIComponent(value) {
1090  try {
1091    return decodeURIComponent(value);
1092  } catch(e) {
1093    // Ignore any invalid uri component
1094  }
1095}
1096
1097
1098/**
1099 * Parses an escaped url query string into key-value pairs.
1100 * @returns Object.<(string|boolean)>
1101 */
1102function parseKeyValue(/**string*/keyValue) {
1103  var obj = {}, key_value, key;
1104  forEach((keyValue || "").split('&'), function(keyValue){
1105    if ( keyValue ) {
1106      key_value = keyValue.split('=');
1107      key = tryDecodeURIComponent(key_value[0]);
1108      if ( isDefined(key) ) {
1109        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1110        if (!obj[key]) {
1111          obj[key] = val;
1112        } else if(isArray(obj[key])) {
1113          obj[key].push(val);
1114        } else {
1115          obj[key] = [obj[key],val];
1116        }
1117      }
1118    }
1119  });
1120  return obj;
1121}
1122
1123function toKeyValue(obj) {
1124  var parts = [];
1125  forEach(obj, function(value, key) {
1126    if (isArray(value)) {
1127      forEach(value, function(arrayValue) {
1128        parts.push(encodeUriQuery(key, true) +
1129                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1130      });
1131    } else {
1132    parts.push(encodeUriQuery(key, true) +
1133               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1134    }
1135  });
1136  return parts.length ? parts.join('&') : '';
1137}
1138
1139
1140/**
1141 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1142 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1143 * segments:
1144 *    segment       = *pchar
1145 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1146 *    pct-encoded   = "%" HEXDIG HEXDIG
1147 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1148 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1149 *                     / "*" / "+" / "," / ";" / "="
1150 */
1151function encodeUriSegment(val) {
1152  return encodeUriQuery(val, true).
1153             replace(/%26/gi, '&').
1154             replace(/%3D/gi, '=').
1155             replace(/%2B/gi, '+');
1156}
1157
1158
1159/**
1160 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1161 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1162 * encoded per http://tools.ietf.org/html/rfc3986:
1163 *    query       = *( pchar / "/" / "?" )
1164 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1165 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1166 *    pct-encoded   = "%" HEXDIG HEXDIG
1167 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1168 *                     / "*" / "+" / "," / ";" / "="
1169 */
1170function encodeUriQuery(val, pctEncodeSpaces) {
1171  return encodeURIComponent(val).
1172             replace(/%40/gi, '@').
1173             replace(/%3A/gi, ':').
1174             replace(/%24/g, '$').
1175             replace(/%2C/gi, ',').
1176             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1177}
1178
1179
1180/**
1181 * @ngdoc directive
1182 * @name ng.directive:ngApp
1183 *
1184 * @element ANY
1185 * @param {angular.Module} ngApp an optional application
1186 *   {@link angular.module module} name to load.
1187 *
1188 * @description
1189 *
1190 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1191 * designates the **root element** of the application and is typically placed near the root element
1192 * of the page - e.g. on the `<body>` or `<html>` tags.
1193 *
1194 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1195 * found in the document will be used to define the root element to auto-bootstrap as an
1196 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1197 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1198 *
1199 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1200 * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
1201 * should contain the application code needed or have dependencies on other modules that will
1202 * contain the code. See {@link angular.module} for more information.
1203 *
1204 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1205 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1206 * would not be resolved to `3`.
1207 *
1208 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1209 *
1210 <example module="ngAppDemo">
1211   <file name="index.html">
1212   <div ng-controller="ngAppDemoController">
1213     I can add: {{a}} + {{b}} =  {{ a+b }}
1214   </div>
1215   </file>
1216   <file name="script.js">
1217   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1218     $scope.a = 1;
1219     $scope.b = 2;
1220   });
1221   </file>
1222 </example>
1223 *
1224 */
1225function angularInit(element, bootstrap) {
1226  var elements = [element],
1227      appElement,
1228      module,
1229      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1230      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1231
1232  function append(element) {
1233    element && elements.push(element);
1234  }
1235
1236  forEach(names, function(name) {
1237    names[name] = true;
1238    append(document.getElementById(name));
1239    name = name.replace(':', '\\:');
1240    if (element.querySelectorAll) {
1241      forEach(element.querySelectorAll('.' + name), append);
1242      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1243      forEach(element.querySelectorAll('[' + name + ']'), append);
1244    }
1245  });
1246
1247  forEach(elements, function(element) {
1248    if (!appElement) {
1249      var className = ' ' + element.className + ' ';
1250      var match = NG_APP_CLASS_REGEXP.exec(className);
1251      if (match) {
1252        appElement = element;
1253        module = (match[2] || '').replace(/\s+/g, ',');
1254      } else {
1255        forEach(element.attributes, function(attr) {
1256          if (!appElement && names[attr.name]) {
1257            appElement = element;
1258            module = attr.value;
1259          }
1260        });
1261      }
1262    }
1263  });
1264  if (appElement) {
1265    bootstrap(appElement, module ? [module] : []);
1266  }
1267}
1268
1269/**
1270 * @ngdoc function
1271 * @name angular.bootstrap
1272 * @description
1273 * Use this function to manually start up angular application.
1274 *
1275 * See: {@link guide/bootstrap Bootstrap}
1276 *
1277 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1278 * They must use {@link api/ng.directive:ngApp ngApp}.
1279 *
1280 * @param {Element} element DOM element which is the root of angular application.
1281 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1282 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1283 *     function that will be invoked by the injector as a run block.
1284 *     See: {@link angular.module modules}
1285 * @returns {AUTO.$injector} Returns the newly created injector for this app.
1286 */
1287function bootstrap(element, modules) {
1288  var doBootstrap = function() {
1289    element = jqLite(element);
1290
1291    if (element.injector()) {
1292      var tag = (element[0] === document) ? 'document' : startingTag(element);
1293      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1294    }
1295
1296    modules = modules || [];
1297    modules.unshift(['$provide', function($provide) {
1298      $provide.value('$rootElement', element);
1299    }]);
1300    modules.unshift('ng');
1301    var injector = createInjector(modules);
1302    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1303       function(scope, element, compile, injector, animate) {
1304        scope.$apply(function() {
1305          element.data('$injector', injector);
1306          compile(element)(scope);
1307        });
1308      }]
1309    );
1310    return injector;
1311  };
1312
1313  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1314
1315  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1316    return doBootstrap();
1317  }
1318
1319  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1320  angular.resumeBootstrap = function(extraModules) {
1321    forEach(extraModules, function(module) {
1322      modules.push(module);
1323    });
1324    doBootstrap();
1325  };
1326}
1327
1328var SNAKE_CASE_REGEXP = /[A-Z]/g;
1329function snake_case(name, separator){
1330  separator = separator || '_';
1331  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1332    return (pos ? separator : '') + letter.toLowerCase();
1333  });
1334}
1335
1336function bindJQuery() {
1337  // bind to jQuery if present;
1338  jQuery = window.jQuery;
1339  // reset to jQuery or default to us.
1340  if (jQuery) {
1341    jqLite = jQuery;
1342    extend(jQuery.fn, {
1343      scope: JQLitePrototype.scope,
1344      isolateScope: JQLitePrototype.isolateScope,
1345      controller: JQLitePrototype.controller,
1346      injector: JQLitePrototype.injector,
1347      inheritedData: JQLitePrototype.inheritedData
1348    });
1349    // Method signature:
1350    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1351    jqLitePatchJQueryRemove('remove', true, true, false);
1352    jqLitePatchJQueryRemove('empty', false, false, false);
1353    jqLitePatchJQueryRemove('html', false, false, true);
1354  } else {
1355    jqLite = JQLite;
1356  }
1357  angular.element = jqLite;
1358}
1359
1360/**
1361 * throw error if the argument is falsy.
1362 */
1363function assertArg(arg, name, reason) {
1364  if (!arg) {
1365    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1366  }
1367  return arg;
1368}
1369
1370function assertArgFn(arg, name, acceptArrayAnnotation) {
1371  if (acceptArrayAnnotation && isArray(arg)) {
1372      arg = arg[arg.length - 1];
1373  }
1374
1375  assertArg(isFunction(arg), name, 'not a function, got ' +
1376      (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
vendor: 5,258 bytes, lines 1377-1535
1377  return arg;
1378}
1379
1380/**
1381 * throw error if the name given is hasOwnProperty
1382 * @param  {String} name    the name to test
1383 * @param  {String} context the context in which the name is used, such as module or directive
1384 */
1385function assertNotHasOwnProperty(name, context) {
1386  if (name === 'hasOwnProperty') {
1387    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1388  }
1389}
1390
1391/**
1392 * Return the value accessible from the object by path. Any undefined traversals are ignored
1393 * @param {Object} obj starting object
1394 * @param {string} path path to traverse
1395 * @param {boolean=true} bindFnToScope
1396 * @returns value as accessible by path
1397 */
1398//TODO(misko): this function needs to be removed
1399function getter(obj, path, bindFnToScope) {
1400  if (!path) return obj;
1401  var keys = path.split('.');
1402  var key;
1403  var lastInstance = obj;
1404  var len = keys.length;
1405
1406  for (var i = 0; i < len; i++) {
1407    key = keys[i];
1408    if (obj) {
1409      obj = (lastInstance = obj)[key];
1410    }
1411  }
1412  if (!bindFnToScope && isFunction(obj)) {
1413    return bind(lastInstance, obj);
1414  }
1415  return obj;
1416}
1417
1418/**
1419 * Return the DOM siblings between the first and last node in the given array.
1420 * @param {Array} array like object
1421 * @returns jQlite object containing the elements
1422 */
1423function getBlockElements(nodes) {
1424  var startNode = nodes[0],
1425      endNode = nodes[nodes.length - 1];
1426  if (startNode === endNode) {
1427    return jqLite(startNode);
1428  }
1429
1430  var element = startNode;
1431  var elements = [element];
1432
1433  do {
1434    element = element.nextSibling;
1435    if (!element) break;
1436    elements.push(element);
1437  } while (element !== endNode);
1438
1439  return jqLite(elements);
1440}
1441
1442/**
1443 * @ngdoc interface
1444 * @name angular.Module
1445 * @description
1446 *
1447 * Interface for configuring angular {@link angular.module modules}.
1448 */
1449
1450function setupModuleLoader(window) {
1451
1452  var $injectorMinErr = minErr('$injector');
1453  var ngMinErr = minErr('ng');
1454
1455  function ensure(obj, name, factory) {
1456    return obj[name] || (obj[name] = factory());
1457  }
1458
1459  var angular = ensure(window, 'angular', Object);
1460
1461  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1462  angular.$$minErr = angular.$$minErr || minErr;
1463
1464  return ensure(angular, 'module', function() {
1465    /** @type {Object.<string, angular.Module>} */
1466    var modules = {};
1467
1468    /**
1469     * @ngdoc function
1470     * @name angular.module
1471     * @description
1472     *
1473     * The `angular.module` is a global place for creating, registering and retrieving Angular
1474     * modules.
1475     * All modules (angular core or 3rd party) that should be available to an application must be
1476     * registered using this mechanism.
1477     *
1478     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1479     * existing module (the name passed as the first argument to `module`) is retrieved.
1480     *
1481     *
1482     * # Module
1483     *
1484     * A module is a collection of services, directives, filters, and configuration information.
1485     * `angular.module` is used to configure the {@link AUTO.$injector $injector}.
1486     *
1487     * <pre>
1488     * // Create a new module
1489     * var myModule = angular.module('myModule', []);
1490     *
1491     * // register a new service
1492     * myModule.value('appName', 'MyCoolApp');
1493     *
1494     * // configure existing services inside initialization blocks.
1495     * myModule.config(function($locationProvider) {
1496     *   // Configure existing providers
1497     *   $locationProvider.hashPrefix('!');
1498     * });
1499     * </pre>
1500     *
1501     * Then you can create an injector and load your modules like this:
1502     *
1503     * <pre>
1504     * var injector = angular.injector(['ng', 'MyModule'])
1505     * </pre>
1506     *
1507     * However it's more likely that you'll just use
1508     * {@link ng.directive:ngApp ngApp} or
1509     * {@link angular.bootstrap} to simplify this process for you.
1510     *
1511     * @param {!string} name The name of the module to create or retrieve.
1512     * @param {Array.<string>=} requires If specified then new module is being created. If
1513     *        unspecified then the the module is being retrieved for further configuration.
1514     * @param {Function} configFn Optional configuration function for the module. Same as
1515     *        {@link angular.Module#methods_config Module#config()}.
1516     * @returns {module} new module with the {@link angular.Module} api.
1517     */
1518    return function module(name, requires, configFn) {
1519      var assertNotHasOwnProperty = function(name, context) {
1520        if (name === 'hasOwnProperty') {
1521          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1522        }
1523      };
1524
1525      assertNotHasOwnProperty(name, 'module');
1526      if (requires && modules.hasOwnProperty(name)) {
1527        modules[name] = null;
1528      }
1529      return ensure(modules, name, function() {
1530        if (!requires) {
1531          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1532             "the module name or forgot to load it. If registering a module ensure that you " +
1533             "specify the dependencies as the second argument.", name);
1534        }
1535
1536        /** @type {!Array.<Array.<*>>} */
1537        var invokeQueue = [];
1538
1539        /** @type {!Array.<Function>} */
1540        var runBlocks = [];
1541
1542        var config = invokeLater('$injector', 'invoke');
1543
1544        /** @type {angular.Module} */
1545        var moduleInstance = {
1546          // Private state
1547          _invokeQueue: invokeQueue,
1548          _runBlocks: runBlocks,
1549
1550          /**
1551           * @ngdoc property
1552           * @name angular.Module#requires
1553           * @propertyOf angular.Module
1554           * @returns {Array.<string>} List of module names which must be loaded before this module.
1555           * @description
1556           * Holds the list of modules which the injector will load before the current module is
1557           * loaded.
1558           */
1559          requires: requires,
1560
1561          /**
1562           * @ngdoc property
1563           * @name angular.Module#name
1564           * @propertyOf angular.Module
1565           * @returns {string} Name of the module.
1566           * @description
1567           */
1568          name: name,
1569
1570
1571          /**
1572           * @ngdoc method
1573           * @name angular.Module#provider
1574           * @methodOf angular.Module
1575           * @param {string} name service name
1576           * @param {Function} providerType Construction function for creating new instance of the
1577           *                                service.
1578           * @description
1579           * See {@link AUTO.$provide#provider $provide.provider()}.
1580           */
1581          provider: invokeLater('$provide', 'provider'),
1582
1583          /**
1584           * @ngdoc method
1585           * @name angular.Module#factory
1586           * @methodOf angular.Module
1587           * @param {string} name service name
1588           * @param {Function} providerFunction Function for creating new instance of the service.
1589           * @description
1590           * See {@link AUTO.$provide#factory $provide.factory()}.
1591           */
1592          factory: invokeLater('$provide', 'factory'),
1593
1594          /**
1595           * @ngdoc method
1596           * @name angular.Module#service
1597           * @methodOf angular.Module
1598           * @param {string} name service name
1599           * @param {Function} constructor A constructor function that will be instantiated.
1600           * @description
1601           * See {@link AUTO.$provide#service $provide.service()}.
1602           */
1603          service: invokeLater('$provide', 'service'),
1604
1605          /**
1606           * @ngdoc method
1607           * @name angular.Module#value
1608           * @methodOf angular.Module
1609           * @param {string} name service name
1610           * @param {*} object Service instance object.
1611           * @description
1612           * See {@link AUTO.$provide#value $provide.value()}.
1613           */
1614          value: invokeLater('$provide', 'value'),
1615
1616          /**
1617           * @ngdoc method
1618           * @name angular.Module#constant
1619           * @methodOf angular.Module
1620           * @param {string} name constant name
1621           * @param {*} object Constant value.
1622           * @description
1623           * Because the constant are fixed, they get applied before other provide methods.
1624           * See {@link AUTO.$provide#constant $provide.constant()}.
1625           */
1626          constant: invokeLater('$provide', 'constant', 'unshift'),
1627
1628          /**
1629           * @ngdoc method
1630           * @name angular.Module#animation
1631           * @methodOf angular.Module
1632           * @param {string} name animation name
1633           * @param {Function} animationFactory Factory function for creating new instance of an
1634           *                                    animation.
1635           * @description
1636           *
1637           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1638           *
1639           *
1640           * Defines an animation hook that can be later used with
1641           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1642           *
1643           * <pre>
1644           * module.animation('.animation-name', function($inject1, $inject2) {
1645           *   return {
1646           *     eventName : function(element, done) {
1647           *       //code to run the animation
1648           *       //once complete, then run done()
1649           *       return function cancellationFunction(element) {
1650           *         //code to cancel the animation
1651           *       }
1652           *     }
1653           *   }
1654           * })
1655           * </pre>
1656           *
1657           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1658           * {@link ngAnimate ngAnimate module} for more information.
1659           */
1660          animation: invokeLater('$animateProvider', 'register'),
1661
1662          /**
1663           * @ngdoc method
1664           * @name angular.Module#filter
1665           * @methodOf angular.Module
1666           * @param {string} name Filter name.
1667           * @param {Function} filterFactory Factory function for creating new instance of filter.
1668           * @description
1669           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1670           */
1671          filter: invokeLater('$filterProvider', 'register'),
1672
1673          /**
1674           * @ngdoc method
1675           * @name angular.Module#controller
1676           * @methodOf angular.Module
1677           * @param {string|Object} name Controller name, or an object map of controllers where the
1678           *    keys are the names and the values are the constructors.
1679           * @param {Function} constructor Controller constructor function.
1680           * @description
1681           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1682           */
1683          controller: invokeLater('$controllerProvider', 'register'),
1684
1685          /**
1686           * @ngdoc method
1687           * @name angular.Module#directive
1688           * @methodOf angular.Module
1689           * @param {string|Object} name Directive name, or an object map of directives where the
1690           *    keys are the names and the values are the factories.
1691           * @param {Function} directiveFactory Factory function for creating new instance of
1692           * directives.
1693           * @description
1694           * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
1695           */
1696          directive: invokeLater('$compileProvider', 'directive'),
1697
1698          /**
1699           * @ngdoc method
1700           * @name angular.Module#config
1701           * @methodOf angular.Module
1702           * @param {Function} configFn Execute this function on module load. Useful for service
1703           *    configuration.
1704           * @description
1705           * Use this method to register work which needs to be performed on module loading.
1706           */
1707          config: config,
1708
1709          /**
1710           * @ngdoc method
1711           * @name angular.Module#run
1712           * @methodOf angular.Module
1713           * @param {Function} initializationFn Execute this function after injector creation.
1714           *    Useful for application initialization.
1715           * @description
1716           * Use this method to register work which should be performed when the injector is done
1717           * loading all modules.
1718           */
1719          run: function(block) {
1720            runBlocks.push(block);
1721            return this;
1722          }
1723        };
1724
1725        if (configFn) {
1726          config(configFn);
1727        }
1728
1729        return  moduleInstance;
1730
1731        /**
1732         * @param {string} provider
1733         * @param {string} method
1734         * @param {String=} insertMethod
1735         * @returns {angular.Module}
1736         */
1737        function invokeLater(provider, method, insertMethod) {
1738          return function() {
1739            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1740            return moduleInstance;
1741          };
1742        }
1743      });
1744    };
1745  });
1746
1747}
1748
1749/* global
1750    angularModule: true,
1751    version: true,
1752    
1753    $LocaleProvider,
1754    $CompileProvider,
1755    
1756    htmlAnchorDirective,
1757    inputDirective,
1758    inputDirective,
1759    formDirective,
1760    scriptDirective,
1761    selectDirective,
1762    styleDirective,
1763    optionDirective,
1764    ngBindDirective,
1765    ngBindHtmlDirective,
1766    ngBindTemplateDirective,
1767    ngClassDirective,
1768    ngClassEvenDirective,
1769    ngClassOddDirective,
1770    ngCspDirective,
1771    ngCloakDirective,
1772    ngControllerDirective,
1773    ngFormDirective,
1774    ngHideDirective,
1775    ngIfDirective,
1776    ngIncludeDirective,
1777    ngIncludeFillContentDirective,
1778    ngInitDirective,
1779    ngNonBindableDirective,
1780    ngPluralizeDirective,
1781    ngRepeatDirective,
1782    ngShowDirective,
1783    ngStyleDirective,
1784    ngSwitchDirective,
1785    ngSwitchWhenDirective,
1786    ngSwitchDefaultDirective,
1787    ngOptionsDirective,
1788    ngTranscludeDirective,
1789    ngModelDirective,
1790    ngListDirective,
1791    ngChangeDirective,
1792    requiredDirective,
1793    requiredDirective,
1794    ngValueDirective,
1795    ngAttributeAliasDirectives,
1796    ngEventDirectives,
1797
1798    $AnchorScrollProvider,
1799    $AnimateProvider,
1800    $BrowserProvider,
1801    $CacheFactoryProvider,
1802    $ControllerProvider,
1803    $DocumentProvider,
1804    $ExceptionHandlerProvider,
1805    $FilterProvider,
1806    $InterpolateProvider,
1807    $IntervalProvider,
1808    $HttpProvider,
1809    $HttpBackendProvider,
1810    $LocationProvider,
1811    $LogProvider,
1812    $ParseProvider,
1813    $RootScopeProvider,
1814    $QProvider,
1815    $$SanitizeUriProvider,
1816    $SceProvider,
1817    $SceDelegateProvider,
1818    $SnifferProvider,
1819    $TemplateCacheProvider,
1820    $TimeoutProvider,
1821    $WindowProvider
1822*/
1823
1824
1825/**
1826 * @ngdoc property
1827 * @name angular.version
1828 * @description
1829 * An object that contains information about the current AngularJS version. This object has the
1830 * following properties:
1831 *
1832 * - `full` – `{string}` – Full version string, such as "0.9.18".
1833 * - `major` – `{number}` – Major version number, such as "0".
1834 * - `minor` – `{number}` – Minor version number, such as "9".
1835 * - `dot` – `{number}` – Dot version number, such as "18".
1836 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1837 */
1838var version = {
1839  full: '1.2.13',    // all of these placeholder strings will be replaced by grunt's
1840  major: 1,    // package task
1841  minor: 2,
1842  dot: 13,
1843  codeName: 'romantic-transclusion'
1844};
1845
1846
1847function publishExternalAPI(angular){
1848  extend(angular, {
1849    'bootstrap': bootstrap,
1850    'copy': copy,
1851    'extend': extend,
1852    'equals': equals,
1853    'element': jqLite,
1854    'forEach': forEach,
1855    'injector': createInjector,
1856    'noop':noop,
1857    'bind':bind,
1858    'toJson': toJson,
1859    'fromJson': fromJson,
1860    'identity':identity,
1861    'isUndefined': isUndefined,
1862    'isDefined': isDefined,
1863    'isString': isString,
1864    'isFunction': isFunction,
1865    'isObject': isObject,
1866    'isNumber': isNumber,
1867    'isElement': isElement,
1868    'isArray': isArray,
1869    'version': version,
1870    'isDate': isDate,
1871    'lowercase': lowercase,
1872    'uppercase': uppercase,
1873    'callbacks': {counter: 0},
1874    '$$minErr': minErr,
1875    '$$csp': csp
1876  });
1877
1878  angularModule = setupModuleLoader(window);
1879  try {
1880    angularModule('ngLocale');
1881  } catch (e) {
1882    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
1883  }
1884
1885  angularModule('ng', ['ngLocale'], ['$provide',
1886    function ngModule($provide) {
1887      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
1888      $provide.provider({
1889        $$sanitizeUri: $$SanitizeUriProvider
1890      });
1891      $provide.provider('$compile', $CompileProvider).
1892        directive({
1893            a: htmlAnchorDirective,
1894            input: inputDirective,
1895            textarea: inputDirective,
1896            form: formDirective,
1897            script: scriptDirective,
1898            select: selectDirective,
1899            style: styleDirective,
1900            option: optionDirective,
1901            ngBind: ngBindDirective,
1902            ngBindHtml: ngBindHtmlDirective,
1903            ngBindTemplate: ngBindTemplateDirective,
1904            ngClass: ngClassDirective,
1905            ngClassEven: ngClassEvenDirective,
1906            ngClassOdd: ngClassOddDirective,
1907            ngCloak: ngCloakDirective,
1908            ngController: ngControllerDirective,
1909            ngForm: ngFormDirective,
1910            ngHide: ngHideDirective,
1911            ngIf: ngIfDirective,
1912            ngInclude: ngIncludeDirective,
1913            ngInit: ngInitDirective,
1914            ngNonBindable: ngNonBindableDirective,
1915            ngPluralize: ngPluralizeDirective,
1916            ngRepeat: ngRepeatDirective,
1917            ngShow: ngShowDirective,
1918            ngStyle: ngStyleDirective,
1919            ngSwitch: ngSwitchDirective,
1920            ngSwitchWhen: ngSwitchWhenDirective,
1921            ngSwitchDefault: ngSwitchDefaultDirective,
1922            ngOptions: ngOptionsDirective,
1923            ngTransclude: ngTranscludeDirective,
1924            ngModel: ngModelDirective,
1925            ngList: ngListDirective,
1926            ngChange: ngChangeDirective,
1927            required: requiredDirective,
1928            ngRequired: requiredDirective,
1929            ngValue: ngValueDirective
1930        }).
1931        directive({
1932          ngInclude: ngIncludeFillContentDirective
1933        }).
1934        directive(ngAttributeAliasDirectives).
1935        directive(ngEventDirectives);
1936      $provide.provider({
1937        $anchorScroll: $AnchorScrollProvider,
1938        $animate: $AnimateProvider,
1939        $browser: $BrowserProvider,
1940        $cacheFactory: $CacheFactoryProvider,
1941        $controller: $ControllerProvider,
1942        $document: $DocumentProvider,
1943        $exceptionHandler: $ExceptionHandlerProvider,
1944        $filter: $FilterProvider,
1945        $interpolate: $InterpolateProvider,
1946        $interval: $IntervalProvider,
1947        $http: $HttpProvider,
1948        $httpBackend: $HttpBackendProvider,
1949        $location: $LocationProvider,
1950        $log: $LogProvider,
1951        $parse: $ParseProvider,
1952        $rootScope: $RootScopeProvider,
1953        $q: $QProvider,
1954        $sce: $SceProvider,
1955        $sceDelegate: $SceDelegateProvider,
1956        $sniffer: $SnifferProvider,
1957        $templateCache: $TemplateCacheProvider,
1958        $timeout: $TimeoutProvider,
1959        $window: $WindowProvider
1960      });
1961    }
1962  ]);
1963}
1964
1965/* global
1966
1967  -JQLitePrototype,
1968  -addEventListenerFn,
1969  -removeEventListenerFn,
1970  -BOOLEAN_ATTR
1971*/
1972
1973//////////////////////////////////
1974//JQLite
1975//////////////////////////////////
1976
1977/**
1978 * @ngdoc function
1979 * @name angular.element
1980 * @function
1981 *
1982 * @description
1983 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
1984 *
1985 * If jQuery is available, `angular.element` is an alias for the
1986 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
1987 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
1988 *
1989 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
1990 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
1991 * commonly needed functionality with the goal of having a very small footprint.</div>
1992 *
1993 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
1994 *
1995 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
1996 * jqLite; they are never raw DOM references.</div>
1997 *
1998 * ## Angular's jqLite
1999 * jqLite provides only the following jQuery methods:
2000 *
2001 * - [`addClass()`](http://api.jquery.com/addClass/)
2002 * - [`after()`](http://api.jquery.com/after/)
2003 * - [`append()`](http://api.jquery.com/append/)
2004 * - [`attr()`](http://api.jquery.com/attr/)
2005 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2006 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2007 * - [`clone()`](http://api.jquery.com/clone/)
2008 * - [`contents()`](http://api.jquery.com/contents/)
2009 * - [`css()`](http://api.jquery.com/css/)
2010 * - [`data()`](http://api.jquery.com/data/)
2011 * - [`empty()`](http://api.jquery.com/empty/)
2012 * - [`eq()`](http://api.jquery.com/eq/)
2013 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2014 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2015 * - [`html()`](http://api.jquery.com/html/)
2016 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2017 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2018 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2019 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2020 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2021 * - [`prepend()`](http://api.jquery.com/prepend/)
2022 * - [`prop()`](http://api.jquery.com/prop/)
2023 * - [`ready()`](http://api.jquery.com/ready/)
2024 * - [`remove()`](http://api.jquery.com/remove/)
2025 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2026 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2027 * - [`removeData()`](http://api.jquery.com/removeData/)
2028 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2029 * - [`text()`](http://api.jquery.com/text/)
2030 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2031 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2032 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2033 * - [`val()`](http://api.jquery.com/val/)
2034 * - [`wrap()`](http://api.jquery.com/wrap/)
2035 *
2036 * ## jQuery/jqLite Extras
2037 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2038 *
2039 * ### Events
2040 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2040pis and fires this event
2041 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2042 *    element before it is removed.
2043 *
2044 * ### Methods
2045 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2046 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2047 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2048 *   `'ngModel'`).
2049 * - `injector()` - retrieves the injector of the current element or its parent.
2050 * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
2051 *   element or its parent.
2052 * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the
2053 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2054 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2055 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2056 *   parent element is reached.
2057 *
2058 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2059 * @returns {Object} jQuery object.
2060 */
2061
2062var jqCache = JQLite.cache = {},
2063    jqName = JQLite.expando = 'ng-' + new Date().getTime(),
2064    jqId = 1,
2065    addEventListenerFn = (window.document.addEventListener
2066      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2067      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2068    removeEventListenerFn = (window.document.removeEventListener
2069      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2070      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2071
2072/*
2073 * !!! This is an undocumented "private" function !!!
2074 */
2075var jqData = JQLite._data = function(node) {
2076  //jQuery always returns an object on cache miss
2077  return this.cache[node[this.expando]] || {};
2078};
2079
2080function jqNextId() { return ++jqId; }
2081
2082
2083var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2084var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2085var jqLiteMinErr = minErr('jqLite');
2086
2087/**
2088 * Converts snake_case to camelCase.
2089 * Also there is special case for Moz prefix starting with upper case letter.
2090 * @param name Name to normalize
2091 */
2092function camelCase(name) {
2093  return name.
2094    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2095      return offset ? letter.toUpperCase() : letter;
2096    }).
2097    replace(MOZ_HACK_REGEXP, 'Moz$1');
2098}
2099
2100/////////////////////////////////////////////
2101// jQuery mutation patch
2102//
2103// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2104// $destroy event on all DOM nodes being removed.
2105//
2106/////////////////////////////////////////////
2107
2108function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2109  var originalJqFn = jQuery.fn[name];
2110  originalJqFn = originalJqFn.$original || originalJqFn;
2111  removePatch.$original = originalJqFn;
2112  jQuery.fn[name] = removePatch;
2113
2114  function removePatch(param) {
2115    // jshint -W040
2116    var list = filterElems && param ? [this.filter(param)] : [this],
2117        fireEvent = dispatchThis,
2118        set, setIndex, setLength,
2119        element, childIndex, childLength, children;
2120
2121    if (!getterIfNoArguments || param != null) {
2122      while(list.length) {
2123        set = list.shift();
2124        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2125          element = jqLite(set[setIndex]);
2126          if (fireEvent) {
2127            element.triggerHandler('$destroy');
2128          } else {
2129            fireEvent = !fireEvent;
2130          }
2131          for(childIndex = 0, childLength = (children = element.children()).length;
2132              childIndex < childLength;
2133              childIndex++) {
2134            list.push(jQuery(children[childIndex]));
2135          }
2136        }
2137      }
2138    }
2139    return originalJqFn.apply(this, arguments);
2140  }
2141}
2142
2143/////////////////////////////////////////////
2144function JQLite(element) {
2145  if (element instanceof JQLite) {
2146    return element;
2147  }
2148  if (isString(element)) {
2149    element = trim(element);
2150  }
2151  if (!(this instanceof JQLite)) {
2152    if (isString(element) && element.charAt(0) != '<') {
2153      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2154    }
2155    return new JQLite(element);
2156  }
2157
2158  if (isString(element)) {
2159    var div = document.createElement('div');
2160    // Read about the NoScope elements here:
2161    // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
2162    div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
2163    div.removeChild(div.firstChild); // remove the superfluous div
2164    jqLiteAddNodes(this, div.childNodes);
2165    var fragment = jqLite(document.createDocumentFragment());
2166    fragment.append(this); // detach the elements from the temporary DOM div.
2167  } else {
2168    jqLiteAddNodes(this, element);
2169  }
2170}
2171
2172function jqLiteClone(element) {
2173  return element.cloneNode(true);
2174}
2175
2176function jqLiteDealoc(element){
2177  jqLiteRemoveData(element);
2178  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2179    jqLiteDealoc(children[i]);
2180  }
2181}
2182
2183function jqLiteOff(element, type, fn, unsupported) {
2184  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2185
2186  var events = jqLiteExpandoStore(element, 'events'),
2187      handle = jqLiteExpandoStore(element, 'handle');
2188
2189  if (!handle) return; //no listeners registered
2190
2191  if (isUndefined(type)) {
2192    forEach(events, function(eventHandler, type) {
2193      removeEventListenerFn(element, type, eventHandler);
2194      delete events[type];
2195    });
2196  } else {
2197    forEach(type.split(' '), function(type) {
2198      if (isUndefined(fn)) {
2199        removeEventListenerFn(element, type, events[type]);
2200        delete events[type];
2201      } else {
2202        arrayRemove(events[type] || [], fn);
2203      }
2204    });
2205  }
2206}
2207
2208function jqLiteRemoveData(element, name) {
2209  var expandoId = element[jqName],
2210      expandoStore = jqCache[expandoId];
2211
2212  if (expandoStore) {
2213    if (name) {
2214      delete jqCache[expandoId].data[name];
2215      return;
2216    }
2217
2218    if (expandoStore.handle) {
2219      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2220      jqLiteOff(element);
2221    }
2222    delete jqCache[expandoId];
2223    element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
2224  }
2225}
2226
2227function jqLiteExpandoStore(element, key, value) {
2228  var expandoId = element[jqName],
2229      expandoStore = jqCache[expandoId || -1];
2230
2231  if (isDefined(value)) {
2232    if (!expandoStore) {
2233      element[jqName] = expandoId = jqNextId();
2234      expandoStore = jqCache[expandoId] = {};
2235    }
2236    expandoStore[key] = value;
2237  } else {
2238    return expandoStore && expandoStore[key];
2239  }
2240}
2241
2242function jqLiteData(element, key, value) {
2243  var data = jqLiteExpandoStore(element, 'data'),
2244      isSetter = isDefined(value),
2245      keyDefined = !isSetter && isDefined(key),
2246      isSimpleGetter = keyDefined && !isObject(key);
2247
2248  if (!data && !isSimpleGetter) {
2249    jqLiteExpandoStore(element, 'data', data = {});
2250  }
2251
2252  if (isSetter) {
2253    data[key] = value;
2254  } else {
2255    if (keyDefined) {
2256      if (isSimpleGetter) {
2257        // don't create data in this case.
2258        return data && data[key];
2259      } else {
2260        extend(data, key);
2261      }
2262    } else {
2263      return data;
2264    }
2265  }
2266}
2267
2268function jqLiteHasClass(element, selector) {
2269  if (!element.getAttribute) return false;
2270  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2271      indexOf( " " + selector + " " ) > -1);
2272}
2273
2274function jqLiteRemoveClass(element, cssClasses) {
2275  if (cssClasses && element.setAttribute) {
2276    forEach(cssClasses.split(' '), function(cssClass) {
2277      element.setAttribute('class', trim(
2278          (" " + (element.getAttribute('class') || '') + " ")
2279          .replace(/[\n\t]/g, " ")
2280          .replace(" " + trim(cssClass) + " ", " "))
2281      );
2282    });
2283  }
2284}
2285
2286function jqLiteAddClass(element, cssClasses) {
2287  if (cssClasses && element.setAttribute) {
2288    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2289                            .replace(/[\n\t]/g, " ");
2290
2291    forEach(cssClasses.split(' '), function(cssClass) {
2292      cssClass = trim(cssClass);
2293      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2294        existingClasses += cssClass + ' ';
2295      }
2296    });
2297
2298    element.setAttribute('class', trim(existingClasses));
2299  }
2300}
2301
2302function jqLiteAddNodes(root, elements) {
2303  if (elements) {
2304    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2305      ? elements
2306      : [ elements ];
2307    for(var i=0; i < elements.length; i++) {
2308      root.push(elements[i]);
2309    }
2310  }
2311}
2312
2313function jqLiteController(element, name) {
2314  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2315}
2316
2317function jqLiteInheritedData(element, name, value) {
2318  element = jqLite(element);
2319
2320  // if element is the document object work with the html element instead
2321  // this makes $(document).scope() possible
2322  if(element[0].nodeType == 9) {
2323    element = element.find('html');
2324  }
2325  var names = isArray(name) ? name : [name];
2326
2327  while (element.length) {
2328
2329    for (var i = 0, ii = names.length; i < ii; i++) {
2330      if ((value = element.data(names[i])) !== undefined) return value;
2331    }
2332    element = element.parent();
2333  }
2334}
2335
2336function jqLiteEmpty(element) {
2337  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2338    jqLiteDealoc(childNodes[i]);
2339  }
2340  while (element.firstChild) {
2341    element.removeChild(element.firstChild);
2342  }
2343}
2344
2345//////////////////////////////////////////
2346// Functions which are declared directly.
2347//////////////////////////////////////////
2348var JQLitePrototype = JQLite.prototype = {
2349  ready: function(fn) {
2350    var fired = false;
2351
2352    function trigger() {
2353      if (fired) return;
2354      fired = true;
2355      fn();
2356    }
2357
2358    // check if document already is loaded
2359    if (document.readyState === 'complete'){
2360      setTimeout(trigger);
2361    } else {
2362      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2363      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2364      // jshint -W064
2365      JQLite(window).on('load', trigger); // fallback to window.onload for others
2366      // jshint +W064
2367    }
2368  },
2369  toString: function() {
2370    var value = [];
2371    forEach(this, function(e){ value.push('' + e);});
2372    return '[' + value.join(', ') + ']';
2373  },
2374
2375  eq: function(index) {
2376      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2377  },
2378
2379  length: 0,
2380  push: push,
2381  sort: [].sort,
2382  splice: [].splice
2383};
2384
2385//////////////////////////////////////////
2386// Functions iterating getter/setters.
2387// these functions return self on setter and
2388// value on get.
2389//////////////////////////////////////////
2390var BOOLEAN_ATTR = {};
2391forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2392  BOOLEAN_ATTR[lowercase(value)] = value;
2393});
2394var BOOLEAN_ELEMENTS = {};
2395forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2396  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2397});
2398
2399function getBooleanAttrName(element, name) {
2400  // check dom last since we will most likely fail on name
2401  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2402
2403  // booleanAttr is here twice to minimize DOM access
2404  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2405}
2406
2407forEach({
2408  data: jqLiteData,
2409  inheritedData: jqLiteInheritedData,
2410
2411  scope: function(element) {
2412    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2413    return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2414  },
2415
2416  isolateScope: function(element) {
2417    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2418    return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
2419  },
2420
2421  controller: jqLiteController ,
2422
2423  injector: function(element) {
2424    return jqLiteInheritedData(element, '$injector');
2425  },
2426
2427  removeAttr: function(element,name) {
2428    element.removeAttribute(name);
2429  },
2430
2431  hasClass: jqLiteHasClass,
2432
2433  css: function(element, name, value) {
2434    name = camelCase(name);
2435
2436    if (isDefined(value)) {
2437      element.style[name] = value;
2438    } else {
2439      var val;
2440
2441      if (msie <= 8) {
2442        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2443        val = element.currentStyle && element.currentStyle[name];
2444        if (val === '') val = 'auto';
2445      }
2446
2447      val = val || element.style[name];
2448
2449      if (msie <= 8) {
2450        // jquery weirdness :-/
2451        val = (val === '') ? undefined : val;
2452      }
2453
2454      return  val;
2455    }
2456  },
2457
2458  attr: function(element, name, value){
2459    var lowercasedName = lowercase(name);
2460    if (BOOLEAN_ATTR[lowercasedName]) {
2461      if (isDefined(value)) {
2462        if (!!value) {
2463          element[name] = true;
2464          element.setAttribute(name, lowercasedName);
2465        } else {
2466          element[name] = false;
2467          element.removeAttribute(lowercasedName);
2468        }
2469      } else {
2470        return (element[name] ||
2471                 (element.attributes.getNamedItem(name)|| noop).specified)
2472               ? lowercasedName
2473               : undefined;
2474      }
2475    } else if (isDefined(value)) {
2476      element.setAttribute(name, value);
2477    } else if (element.getAttribute) {
2478      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2479      // some elements (e.g. Document) don't have get attribute, so return undefined
2480      var ret = element.getAttribute(name, 2);
2481      // normalize non-existing attributes to undefined (as jQuery)
2482      return ret === null ? undefined : ret;
2483    }
2484  },
2485
2486  prop: function(element, name, value) {
2487    if (isDefined(value)) {
2488      element[name] = value;
2489    } else {
2490      return element[name];
2491    }
2492  },
2493
2494  text: (function() {
2495    var NODE_TYPE_TEXT_PROPERTY = [];
2496    if (msie < 9) {
2497      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2498      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2499    } else {
2500      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2501      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2502    }
2503    getText.$dv = '';
2504    return getText;
2505
2506    function getText(element, value) {
2507      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2508      if (isUndefined(value)) {
2509        return textProp ? element[textProp] : '';
2510      }
2511      element[textProp] = value;
2512    }
2513  })(),
2514
2515  val: function(element, value) {
2516    if (isUndefined(value)) {
2517      if (nodeName_(element) === 'SELECT' && element.multiple) {
2518        var result = [];
2519        forEach(element.options, function (option) {
2520          if (option.selected) {
2521            result.push(option.value || option.text);
2522          }
2523        });
2524        return result.length === 0 ? null : result;
2525      }
2526      return element.value;
2527    }
2528    element.value = value;
2529  },
2530
2531  html: function(element, value) {
2532    if (isUndefined(value)) {
2533      return element.innerHTML;
2534    }
2535    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2536      jqLiteDealoc(childNodes[i]);
2537    }
2538    element.innerHTML = value;
2539  },
2540
2541  empty: jqLiteEmpty
2542}, function(fn, name){
2543  /**
2544   * Properties: writes return selection, reads return first value
2545   */
2546  JQLite.prototype[name] = function(arg1, arg2) {
2547    var i, key;
2548
2549    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2550    // in a way that survives minification.
2551    // jqLiteEmpty takes no arguments but is a setter.
2552    if (fn !== jqLiteEmpty &&
2553        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2554      if (isObject(arg1)) {
2555
2556        // we are a write, but the object properties are the key/values
2557        for (i = 0; i < this.length; i++) {
2558          if (fn === jqLiteData) {
2559            // data() takes the whole object in jQuery
2560            fn(this[i], arg1);
2561          } else {
2562            for (key in arg1) {
2563              fn(this[i], key, arg1[key]);
2564            }
2565          }
2566        }
2567        // return self for chaining
2568        return this;
2569      } else {
2570        // we are a read, so read the first child.
2571        var value = fn.$dv;
2572        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2573        var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
2574        for (var j = 0; j < jj; j++) {
2575          var nodeValue = fn(this[j], arg1, arg2);
2576          value = value ? value + nodeValue : nodeValue;
2577        }
2578        return value;
2579      }
2580    } else {
2581      // we are a write, so apply to all children
2582      for (i = 0; i < this.length; i++) {
2583        fn(this[i], arg1, arg2);
2584      }
2585      // return self for chaining
2586      return this;
2587    }
2588  };
2589});
2590
2591function createEventHandler(element, events) {
2592  var eventHandler = function (event, type) {
2593    if (!event.preventDefault) {
2594      event.preventDefault = function() {
2595        event.returnValue = false; //ie
2596      };
2597    }
2598
2599    if (!event.stopPropagation) {
2600      event.stopPropagation = function() {
2601        event.cancelBubble = true; //ie
2602      };
2603    }
2604
2605    if (!event.target) {
2606      event.target = event.srcElement || document;
2607    }
2608
2609    if (isUndefined(event.defaultPrevented)) {
2610      var prevent = event.preventDefault;
2611      event.preventDefault = function() {
2612        event.defaultPrevented = true;
2613        prevent.call(event);
2614      };
2615      event.defaultPrevented = false;
2616    }
2617
2618    event.isDefaultPrevented = function() {
2619      return event.defaultPrevented || event.returnValue === false;
2620    };
2621
2622    // Copy event handlers in case event handlers array is modified during execution.
2623    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2624
2625    forEach(eventHandlersCopy, function(fn) {
2626      fn.call(element, event);
2627    });
2628
2629    // Remove monkey-patched methods (IE),
2630    // as they would cause memory leaks in IE8.
2631    if (msie <= 8) {
2632      // IE7/8 does not allow to delete property on native object
2633      event.preventDefault = null;
2634      event.stopPropagation = null;
2635      event.isDefaultPrevented = null;
2636    } else {
2637      // It shouldn't affect normal browsers (native methods are defined on prototype).
2638      delete event.preventDefault;
2639      delete event.stopPropagation;
2640      delete event.isDefaultPrevented;
2641    }
2642  };
2643  eventHandler.elem = element;
2644  return eventHandler;
2645}
2646
2647//////////////////////////////////////////
2648// Functions iterating traversal.
2649// These functions chain results into a single
2650// selector.
2651//////////////////////////////////////////
2652forEach({
2653  removeData: jqLiteRemoveData,
2654
2655  dealoc: jqLiteDealoc,
2656
2657  on: function onFn(element, type, fn, unsupported){
2658    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2659
2660    var events = jqLiteExpandoStore(element, 'events'),
2661        handle = jqLiteExpandoStore(element, 'handle');
2662
2663    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2664    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2665
2666    forEach(type.split(' '), function(type){
2667      var eventFns = events[type];
2668
2669      if (!eventFns) {
2670        if (type == 'mouseenter' || type == 'mouseleave') {
2671          var contains = document.body.contains || document.body.compareDocumentPosition ?
2672          function( a, b ) {
2673            // jshint bitwise: false
2674            var adown = a.nodeType === 9 ? a.documentElement : a,
2675            bup = b && b.parentNode;
2676            return a === bup || !!( bup && bup.nodeType === 1 && (
2677              adown.contains ?
2678              adown.contains( bup ) :
2679              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2680              ));
2681            } :
2682            function( a, b ) {
2683              if ( b ) {
2684                while ( (b = b.parentNode) ) {
2685                  if ( b === a ) {
2686                    return true;
2687                  }
2688                }
2689              }
2690              return false;
2691            };
2692
2693          events[type] = [];
2694
2695          // Refer to jQuery's implementation of mouseenter & mouseleave
2696          // Read about mouseenter and mouseleave:
2697          // http://www.quirksmode.org/js/events_mouse.html#link8
2698          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2699
2700          onFn(element, eventmap[type], function(event) {
2701            var target = this, related = event.relatedTarget;
2702            // For mousenter/leave call the handler if related is outside the target.
2703            // NB: No relatedTarget if the mouse left/entered the browser window
2704            if ( !related || (related !== target && !contains(target, related)) ){
2705              handle(event, type);
2706            }
2707          });
2708
2709        } else {
2710          addEventListenerFn(element, type, handle);
2711          events[type] = [];
2712        }
2713        eventFns = events[type];
2714      }
2715      eventFns.push(fn);
2716    });
2717  },
2718
2719  off: jqLiteOff,
2720
2721  one: function(element, type, fn) {
2722    element = jqLite(element);
2723
2724    //add the listener twice so that when it is called
2725    //you can remove the original function and still be
2726    //able to call element.off(ev, fn) normally
2727    element.on(type, function onFn() {
2728      element.off(type, fn);
2729      element.off(type, onFn);
2730    });
2731    element.on(type, fn);
2732  },
2733
2734  replaceWith: function(element, replaceNode) {
2735    var index, parent = element.parentNode;
2736    jqLiteDealoc(element);
2737    forEach(new JQLite(replaceNode), function(node){
2738      if (index) {
2739        parent.insertBefore(node, index.nextSibling);
2740      } else {
2741        parent.replaceChild(node, element);
2742      }
2743      index = node;
2744    });
2745  },
2746
2747  children: function(element) {
2748    var children = [];
2749    forEach(element.childNodes, function(element){
2750      if (element.nodeType === 1)
2751        children.push(element);
2752    });
2753    return children;
2754  },
2755
2756  contents: function(element) {
2757    return element.childNodes || [];
2758  },
2759
2760  append: function(element, node) {
2761    forEach(new JQLite(node), function(child){
2762      if (element.nodeType === 1 || element.nodeType === 11) {
2763        element.appendChild(child);
2764      }
2765    });
2766  },
2767
2768  prepend: function(element, node) {
2769    if (element.nodeType === 1) {
2770      var index = element.firstChild;
2771      forEach(new JQLite(node), function(child){
2772        element.insertBefore(child, index);
2773      });
2774    }
2775  },
2776
2777  wrap: function(element, wrapNode) {
2778    wrapNode = jqLite(wrapNode)[0];
2779    var parent = element.parentNode;
2780    if (parent) {
2781      parent.replaceChild(wrapNode, element);
2782    }
2783    wrapNode.appendChild(element);
2784  },
2785
2786  remove: function(element) {
2787    jqLiteDealoc(element);
2788    var parent = element.parentNode;
2789    if (parent) parent.removeChild(element);
2790  },
2791
2792  after: function(element, newElement) {
2793    var index = element, parent = element.parentNode;
2794    forEach(new JQLite(newElement), function(node){
2795      parent.insertBefore(node, index.nextSibling);
2796      index = node;
2797    });
2798  },
2799
2800  addClass: jqLiteAddClass,
2801  removeClass: jqLiteRemoveClass,
2802
2803  toggleClass: function(element, selector, condition) {
2804    if (isUndefined(condition)) {
2805      condition = !jqLiteHasClass(element, selector);
2806    }
2807    (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector);
2808  },
2809
2810  parent: function(element) {
2811    var parent = element.parentNode;
2812    return parent && parent.nodeType !== 11 ? parent : null;
2813  },
2814
2815  next: function(element) {
2816    if (element.nextElementSibling) {
2817      return element.nextElementSibling;
2818    }
2819
2820    // IE8 doesn't have nextElementSibling
2821    var elm = element.nextSibling;
2822    while (elm != null && elm.nodeType !== 1) {
2823      elm = elm.nextSibling;
2824    }
2825    return elm;
2826  },
2827
2828  find: function(element, selector) {
2829    if (element.getElementsByTagName) {
2830      return element.getElementsByTagName(selector);
2831    } else {
2832      return [];
2833    }
2834  },
2835
2836  clone: jqLiteClone,
2837
2838  triggerHandler: function(element, eventName, eventData) {
2839    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
2840
2841    eventData = eventData || [];
2842
2843    var event = [{
2844      preventDefault: noop,
2845      stopPropagation: noop
2846    }];
2847
2848    forEach(eventFns, function(fn) {
2849      fn.apply(element, event.concat(eventData));
2850    });
2851  }
2852}, function(fn, name){
2853  /**
2854   * chaining functions
2855   */
2856  JQLite.prototype[name] = function(arg1, arg2, arg3) {
2857    var value;
2858    for(var i=0; i < this.length; i++) {
2859      if (isUndefined(value)) {
2860        value = fn(this[i], arg1, arg2, arg3);
2861        if (isDefined(value)) {
2862          // any function which returns a value needs to be wrapped
2863          value = jqLite(value);
2864        }
2865      } else {
2866        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
2867      }
2868    }
2869    return isDefined(value) ? value : this;
2870  };
2871
2872  // bind legacy bind/unbind to on/off
2873  JQLite.prototype.bind = JQLite.prototype.on;
2874  JQLite.prototype.unbind = JQLite.prototype.off;
2875});
2876
2877/**
2878 * Computes a hash of an 'obj'.
2879 * Hash of a:
2880 *  string is string
2881 *  number is number as string
2882 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
2883 *         that is also assigned to the $$hashKey property of the object.
2884 *
2885 * @param obj
2886 * @returns {string} hash string such that the same input will have the same hash string.
2887 *         The resulting string key is in 'type:hashKey' format.
2888 */
2889function hashKey(obj) {
2890  var objType = typeof obj,
2891      key;
2892
2893  if (objType == 'object' && obj !== null) {
2894    if (typeof (key = obj.$$hashKey) == 'function') {
2895      // must invoke on object to keep the right this
2896      key = obj.$$hashKey();
2897    } else if (key === undefined) {
2898      key = obj.$$hashKey = nextUid();
2899    }
2900  } else {
2901    key = obj;
2902  }
2903
2904  return objType + ':' + key;
2905}
2906
2907/**
2908 * HashMap which can use objects as keys
2909 */
2910function HashMap(array){
2911  forEach(array, this.put, this);
2912}
2913HashMap.prototype = {
2914  /**
2915   * Store key value pair
2916   * @param key key to store can be any type
2917   * @param value value to store can be any type
2918   */
2919  put: function(key, value) {
2920    this[hashKey(key)] = value;
2921  },
2922
2923  /**
2924   * @param key
2925   * @returns the value for the key
2926   */
2927  get: function(key) {
2928    return this[hashKey(key)];
2929  },
2930
2931  /**
2932   * Remove the key/value pair
2933   * @param key
2934   */
2935  remove: function(key) {
2936    var value = this[key = hashKey(key)];
2937    delete this[key];
2938    return value;
2939  }
2940};
2941
2942/**
2943 * @ngdoc function
2944 * @name angular.injector
2945 * @function
2946 *
2947 * @description
2948 * Creates an injector function that can be used for retrieving services as well as for
2949 * dependency injection (see {@link guide/di dependency injection}).
2950 *
2951
2952 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
2953 *        {@link angular.module}. The `ng` module must be explicitly added.
2954 * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
2955 *
2956 * @example
2957 * Typical usage
2958 * <pre>
2959 *   // create an injector
2960 *   var $injector = angular.injector(['ng']);
2961 *
2962 *   // use the injector to kick off your application
2963 *   // use the type inference to auto inject arguments, or use impl
2963icit injection
2964 *   $injector.invoke(function($rootScope, $compile, $document){
2965 *     $compile($document)($rootScope);
2966 *     $rootScope.$digest();
2967 *   });
2968 * </pre>
2969 *
2970 * Sometimes you want to get access to the injector of a currently running Angular app
2971 * from outside Angular. Perhaps, you want to inject and compile some markup after the
2972 * application has been bootstrapped. You can do this using extra `injector()` added
2973 * to JQuery/jqLite elements. See {@link angular.element}.
2974 *
2975 * *This is fairly rare but could be the case if a third party library is injecting the
2976 * markup.*
2977 *
2978 * In the following example a new block of HTML containing a `ng-controller`
2979 * directive is added to the end of the document body by JQuery. We then compile and link
2980 * it into the current AngularJS scope.
2981 *
2982 * <pre>
2983 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
2984 * $(document.body).append($div);
2985 *
2986 * angular.element(document).injector().invoke(function($compile) {
2987 *   var scope = angular.element($div).scope();
2988 *   $compile($div)(scope);
2989 * });
2990 * </pre>
2991 */
2992
2993
2994/**
2995 * @ngdoc overview
2996 * @name AUTO
2997 * @description
2998 *
2999 * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
3000 */
3001
3002var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3003var FN_ARG_SPLIT = /,/;
3004var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3005var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3006var $injectorMinErr = minErr('$injector');
3007function annotate(fn) {
3008  var $inject,
3009      fnText,
3010      argDecl,
3011      last;
3012
3013  if (typeof fn == 'function') {
3014    if (!($inject = fn.$inject)) {
3015      $inject = [];
3016      if (fn.length) {
3017        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3018        argDecl = fnText.match(FN_ARGS);
3019        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3020          arg.replace(FN_ARG, function(all, underscore, name){
3021            $inject.push(name);
3022          });
3023        });
3024      }
3025      fn.$inject = $inject;
3026    }
3027  } else if (isArray(fn)) {
3028    last = fn.length - 1;
3029    assertArgFn(fn[last], 'fn');
3030    $inject = fn.slice(0, last);
3031  } else {
3032    assertArgFn(fn, 'fn', true);
3033  }
3034  return $inject;
3035}
3036
3037///////////////////////////////////////
3038
3039/**
3040 * @ngdoc object
3041 * @name AUTO.$injector
3042 * @function
3043 *
3044 * @description
3045 *
3046 * `$injector` is used to retrieve object instances as defined by
3047 * {@link AUTO.$provide provider}, instantiate types, invoke methods,
3048 * and load modules.
3049 *
3050 * The following always holds true:
3051 *
3052 * <pre>
3053 *   var $injector = angular.injector();
3054 *   expect($injector.get('$injector')).toBe($injector);
3055 *   expect($injector.invoke(function($injector){
3056 *     return $injector;
3057 *   }).toBe($injector);
3058 * </pre>
3059 *
3060 * # Injection Function Annotation
3061 *
3062 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3063 * following are all valid ways of annotating function with injection arguments and are equivalent.
3064 *
3065 * <pre>
3066 *   // inferred (only works if code not minified/obfuscated)
3067 *   $injector.invoke(function(serviceA){});
3068 *
3069 *   // annotated
3070 *   function explicit(serviceA) {};
3071 *   explicit.$inject = ['serviceA'];
3072 *   $injector.invoke(explicit);
3073 *
3074 *   // inline
3075 *   $injector.invoke(['serviceA', function(serviceA){}]);
3076 * </pre>
3077 *
3078 * ## Inference
3079 *
3080 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3081 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3082 * minification, and obfuscation tools since these tools change the argument names.
3083 *
3084 * ## `$inject` Annotation
3085 * By adding a `$inject` property onto a function the injection parameters can be specified.
3086 *
3087 * ## Inline
3088 * As an array of injection names, where the last item in the array is the function to call.
3089 */
3090
3091/**
3092 * @ngdoc method
3093 * @name AUTO.$injector#get
3094 * @methodOf AUTO.$injector
3095 *
3096 * @description
3097 * Return an instance of the service.
3098 *
3099 * @param {string} name The name of the instance to retrieve.
3100 * @return {*} The instance.
3101 */
3102
3103/**
3104 * @ngdoc method
3105 * @name AUTO.$injector#invoke
3106 * @methodOf AUTO.$injector
3107 *
3108 * @description
3109 * Invoke the method and supply the method arguments from the `$injector`.
3110 *
3111 * @param {!function} fn The function to invoke. Function parameters are injected according to the
3112 *   {@link guide/di $inject Annotation} rules.
3113 * @param {Object=} self The `this` for the invoked method.
3114 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3115 *                         object first, before the `$injector` is consulted.
3116 * @returns {*} the value returned by the invoked `fn` function.
3117 */
3118
3119/**
3120 * @ngdoc method
3121 * @name AUTO.$injector#has
3122 * @methodOf AUTO.$injector
3123 *
3124 * @description
3125 * Allows the user to query if the particular service exist.
3126 *
3127 * @param {string} Name of the service to query.
3128 * @returns {boolean} returns true if injector has given service.
3129 */
3130
3131/**
3132 * @ngdoc method
3133 * @name AUTO.$injector#instantiate
3134 * @methodOf AUTO.$injector
3135 * @description
3136 * Create a new instance of JS type. The method takes a constructor function invokes the new
3137 * operator and supplies all of the arguments to the constructor function as specified by the
3138 * constructor annotation.
3139 *
3140 * @param {function} Type Annotated constructor function.
3141 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3142 * object first, before the `$injector` is consulted.
3143 * @returns {Object} new instance of `Type`.
3144 */
3145
3146/**
3147 * @ngdoc method
3148 * @name AUTO.$injector#annotate
3149 * @methodOf AUTO.$injector
3150 *
3151 * @description
3152 * Returns an array of service names which the function is requesting for injection. This API is
3153 * used by the injector to determine which services need to be injected into the function when the
3154 * function is invoked. There are three ways in which the function can be annotated with the needed
3155 * dependencies.
3156 *
3157 * # Argument names
3158 *
3159 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3160 * by converting the function into a string using `toString()` method and extracting the argument
3161 * names.
3162 * <pre>
3163 *   // Given
3164 *   function MyController($scope, $route) {
3165 *     // ...
3166 *   }
3167 *
3168 *   // Then
3169 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3170 * </pre>
3171 *
3172 * This method does not work with code minification / obfuscation. For this reason the following
3173 * annotation strategies are supported.
3174 *
3175 * # The `$inject` property
3176 *
3177 * If a function has an `$inject` property and its value is an array of strings, then the strings
3178 * represent names of services to be injected into the function.
3179 * <pre>
3180 *   // Given
3181 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3182 *     // ...
3183 *   }
3184 *   // Define function dependencies
3185 *   MyController['$inject'] = ['$scope', '$route'];
3186 *
3187 *   // Then
3188 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3189 * </pre>
3190 *
3191 * # The array notation
3192 *
3193 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3194 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3195 * a way that survives minification is a better choice:
3196 *
3197 * <pre>
3198 *   // We wish to write this (not minification / obfuscation safe)
3199 *   injector.invoke(function($compile, $rootScope) {
3200 *     // ...
3201 *   });
3202 *
3203 *   // We are forced to write break inlining
3204 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3205 *     // ...
3206 *   };
3207 *   tmpFn.$inject = ['$compile', '$rootScope'];
3208 *   injector.invoke(tmpFn);
3209 *
3210 *   // To better support inline function the inline annotation is supported
3211 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3212 *     // ...
3213 *   }]);
3214 *
3215 *   // Therefore
3216 *   expect(injector.annotate(
3217 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3218 *    ).toEqual(['$compile', '$rootScope']);
3219 * </pre>
3220 *
3221 * @param {function|Array.<string|Function>} fn Function for which dependent service names need to
3222 * be retrieved as described above.
3223 *
3224 * @returns {Array.<string>} The names of the services which the function requires.
3225 */
3226
3227
3228
3229
3230/**
3231 * @ngdoc object
3232 * @name AUTO.$provide
3233 *
3234 * @description
3235 *
3236 * The {@link AUTO.$provide $provide} service has a number of methods for registering components
3237 * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on
3238 * {@link angular.Module}.
3239 *
3240 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3241 * factories** are functions which, in turn, are created by a **service provider**.
3242 * The **service providers** are constructor functions. When instantiated they must contain a
3243 * property called `$get`, which holds the **service factory** function.
3244 *
3245 * When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
3246 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3247 * function to get the instance of the **service**.
3248 *
3249 * Often services have no configuration options and there is no need to add methods to the service
3250 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3251 * these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
3252 * services without specifying a provider.
3253 *
3254 * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the
3255 *     {@link AUTO.$injector $injector}
3256 * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by
3257 *     providers and services.
3258 * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by
3259 *     services, not providers.
3260 * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`,
3261 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3262 *     given factory function.
3263 * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that
3264 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3265 *      a new object using the given constructor function.
3266 *
3267 * See the individual methods for more information and examples.
3268 */
3269
3270/**
3271 * @ngdoc method
3272 * @name AUTO.$provide#provider
3273 * @methodOf AUTO.$provide
3274 * @description
3275 *
3276 * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions
3277 * are constructor functions, whose instances are responsible for "providing" a factory for a
3278 * service.
3279 *
3280 * Service provider names start with the name of the service they provide followed by `Provider`.
3281 * For example, the {@link ng.$log $log} service has a provider called
3282 * {@link ng.$logProvider $logProvider}.
3283 *
3284 * Service provider objects can have additional methods which allow configuration of the provider
3285 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3286 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3287 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3288 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3289 * console or not.
3290 *
3291 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3292                        'Provider'` key.
3293 * @param {(Object|function())} provider If the provider is:
3294 *
3295 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3296 *     {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
3297 *   - `Constructor`: a new instance of the provider will be created using                     
3298 *     {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3299 *
3300 * @returns {Object} registered provider instance
3301
3302 * @example
3303 *
3304 * The following example shows how to create a simple event tracking service and register it using
3305 * {@link AUTO.$provide#methods_provider $provide.provider()}.
3306 *
3307 * <pre>
3308 *  // Define the eventTracker provider
3309 *  function EventTrackerProvider() {
3310 *    var trackingUrl = '/track';
3311 *
3312 *    // A provider method for configuring where the tracked events should been saved
3313 *    this.setTrackingUrl = function(url) {
3314 *      trackingUrl = url;
3315 *    };
3316 *
3317 *    // The service factory function
3318 *    this.$get = ['$http', function($http) {
3319 *      var trackedEvents = {};
3320 *      return {
3321 *        // Call this to track an event
3322 *        event: function(event) {
3323 *          var count = trackedEvents[event] || 0;
3324 *          count += 1;
3325 *          trackedEvents[event] = count;
3326 *          return count;
3327 *        },
3328 *        // Call this to save the tracked events to the trackingUrl
3329 *        save: function() {
3330 *          $http.post(trackingUrl, trackedEvents);
3331 *        }
3332 *      };
3333 *    }];
3334 *  }
3335 *
3336 *  describe('eventTracker', function() {
3337 *    var postSpy;
3338 *
3339 *    beforeEach(module(function($provide) {
3340 *      // Register the eventTracker provider
3341 *      $provide.provider('eventTracker', EventTrackerProvider);
3342 *    }));
3343 *
3344 *    beforeEach(module(function(eventTrackerProvider) {
3345 *      // Configure eventTracker provider
3346 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3347 *    }));
3348 *
3349 *    it('tracks events', inject(function(eventTracker) {
3350 *      expect(eventTracker.event('login')).toEqual(1);
3351 *      expect(eventTracker.event('login')).toEqual(2);
3352 *    }));
3353 *
3354 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3355 *      postSpy = spyOn($http, 'post');
3356 *      eventTracker.event('login');
3357 *      eventTracker.save();
3358 *      expect(postSpy).toHaveBeenCalled();
3359 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3360 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3361 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3362 *    }));
3363 *  });
3364 * </pre>
3365 */
3366
3367/**
3368 * @ngdoc method
3369 * @name AUTO.$provide#factory
3370 * @methodOf AUTO.$provide
3371 * @description
3372 *
3373 * Register a **service factory**, which will be called to return the service instance.
3374 * This is short for registering a service where its provider consists of only a `$get` property,
3375 * which is the given service factory function.
3376 * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to
3377 * configure your service in a provider.
3378 *
3379 * @param {string} name The name of the instance.
3380 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3381 *                            for `$provide.provider(name, {$get: $getFn})`.
3382 * @returns {Object} registered provider instance
3383 *
3384 * @example
3385 * Here is an example of registering a service
3386 * <pre>
3387 *   $provide.factory('ping', ['$http', function($http) {
3388 *     return function ping() {
3389 *       return $http.send('/ping');
3390 *     };
3391 *   }]);
3392 * </pre>
3393 * You would then inject and use this service like this:
3394 * <pre>
3395 *   someModule.controller('Ctrl', ['ping', function(ping) {
3396 *     ping();
3397 *   }]);
3398 * </pre>
3399 */
3400
3401
3402/**
3403 * @ngdoc method
3404 * @name AUTO.$provide#service
3405 * @methodOf AUTO.$provide
3406 * @description
3407 *
3408 * Register a **service constructor**, which will be invoked with `new` to create the service
3409 * instance.
3410 * This is short for registering a service where its provider's `$get` property is the service
3411 * constructor function that will be used to instantiate the service instance.
3412 *
3413 * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
3414 * as a type/class.
3415 *
3416 * @param {string} name The name of the instance.
3417 * @param {Function} constructor A class (constructor function) that will be instantiated.
3418 * @returns {Object} registered provider instance
3419 *
3420 * @example
3421 * Here is an example of registering a service using
3422 * {@link AUTO.$provide#methods_service $provide.service(class)}.
3423 * <pre>
3424 *   var Ping = function($http) {
3425 *     this.$http = $http;
3426 *   };
3427 * 
3428 *   Ping.$inject = ['$http'];
3429 *   
3430 *   Ping.prototype.send = function() {
3431 *     return this.$http.get('/ping');
3432 *   };
3433 *   $provide.service('ping', Ping);
3434 * </pre>
3435 * You would then inject and use this service like this:
3436 * <pre>
3437 *   someModule.controller('Ctrl', ['ping', function(ping) {
3438 *     ping.send();
3439 *   }]);
3440 * </pre>
3441 */
3442
3443
3444/**
3445 * @ngdoc method
3446 * @name AUTO.$provide#value
3447 * @methodOf AUTO.$provide
3448 * @description
3449 *
3450 * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a
3451 * number, an array, an object or a function.  This is short for registering a service where its
3452 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3453 * service**.
3454 *
3455 * Value services are similar to constant services, except that they cannot be injected into a
3456 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3457 * an Angular
3458 * {@link AUTO.$provide#decorator decorator}.
3459 *
3460 * @param {string} name The name of the instance.
3461 * @param {*} value The value.
3462 * @returns {Object} registered provider instance
3463 *
3464 * @example
3465 * Here are some examples of creating value services.
3466 * <pre>
3467 *   $provide.value('ADMIN_USER', 'admin');
3468 *
3469 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3470 *
3471 *   $provide.value('halfOf', function(value) {
3472 *     return value / 2;
3473 *   });
3474 * </pre>
3475 */
3476
3477
3478/**
3479 * @ngdoc method
3480 * @name AUTO.$provide#constant
3481 * @methodOf AUTO.$provide
3482 * @description
3483 *
3484 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3485 * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be
3486 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3487 * be overridden by an Angular {@link AUTO.$provide#decorator decorator}.
3488 *
3489 * @param {string} name The name of the constant.
3490 * @param {*} value The constant value.
3491 * @returns {Object} registered instance
3492 *
3493 * @example
3494 * Here a some examples of creating constants:
3495 * <pre>
3496 *   $provide.constant('SHARD_HEIGHT', 306);
3497 *
3498 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3499 *
3500 *   $provide.constant('double', function(value) {
3501 *     return value * 2;
3502 *   });
3503 * </pre>
3504 */
3505
3506
3507/**
3508 * @ngdoc method
3509 * @name AUTO.$provide#decorator
3510 * @methodOf AUTO.$provide
3511 * @description
3512 *
3513 * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator
3514 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3515 * service. The object returned by the decorator may be the original service, or a new service
3516 * object which replaces or wraps and delegates to the original service.
3517 *
3518 * @param {string} name The name of the service to decorate.
3519 * @param {function()} decorator This function will be invoked when the service needs to be
3520 *    instantiated and should return the decorated service instance. The function is called using
3521 *    the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
3522 *    Local injection arguments:
3523 *
3524 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3525 *      decorated or delegated to.
3526 *
3527 * @example
3528 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3529 * calls to {@link ng.$log#error $log.warn()}.
3530 * <pre>
3531 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3532 *     $delegate.warn = $delegate.error;
3533 *     return $delegate;
3534 *   }]);
3535 * </pre>
3536 */
3537
3538
3539function createInjector(modulesToLoad) {
3540  var INSTANTIATING = {},
3541      providerSuffix = 'Provider',
3542      path = [],
3543      loadedModules = new HashMap(),
3544      providerCache = {
3545        $provide: {
3546            provider: supportObject(provider),
3547            factory: supportObject(factory),
3548            service: supportObject(service),
3549            value: supportObject(value),
3550            constant: supportObject(constant),
3551            decorator: decorator
3552          }
3553      },
3554      providerInjector = (providerCache.$injector =
3555          createInternalInjector(providerCache, function() {
3556            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3557          })),
3558      instanceCache = {},
3559      instanceInjector = (instanceCache.$injector =
3560          createInternalInjector(instanceCache, function(servicename) {
3561            var provider = providerInjector.get(servicename + providerSuffix);
3562            return instanceInjector.invoke(provider.$get, provider);
3563          }));
3564
3565
3566  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3567
3568  return instanceInjector;
3569
3570  ////////////////////////////////////
3571  // $provider
3572  ////////////////////////////////////
3573
3574  function supportObject(delegate) {
3575    return function(key, value) {
3576      if (isObject(key)) {
3577        forEach(key, reverseParams(delegate));
3578      } else {
3579        return delegate(key, value);
3580      }
3581    };
3582  }
3583
3584  function provider(name, provider_) {
3585    assertNotHasOwnProperty(name, 'service');
3586    if (isFunction(provider_) || isArray(provider_)) {
3587      provider_ = providerInjector.instantiate(provider_);
3588    }
3589    if (!provider_.$get) {
3590      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3591    }
3592    return providerCache[name + providerSuffix] = provider_;
3593  }
3594
3595  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3596
3597  function service(name, constructor) {
3598    return factory(name, ['$injector', function($injector) {
3599      return $injector.instantiate(constructor);
3600    }]);
3601  }
3602
3603  function value(name, val) { return factory(name, valueFn(val)); }
3604
3605  function constant(name, value) {
3606    assertNotHasOwnProperty(name, 'constant');
3607    providerCache[name] = value;
3608    instanceCache[name] = value;
3609  }
3610
3611  function decorator(serviceName, decorFn) {
3612    var origProvider = providerInjector.get(serviceName + providerSuffix),
3613        orig$get = origProvider.$get;
3614
3615    origProvider.$get = function() {
3616      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3617      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3618    };
3619  }
3620
3621  ////////////////////////////////////
3622  // Module Loading
3623  ////////////////////////////////////
3624  function loadModules(modulesToLoad){
3625    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3626    forEach(modulesToLoad, function(module) {
3627      if (loadedModules.get(module)) return;
3628      loadedModules.put(module, true);
3629
3630      try {
3631        if (isString(module)) {
3632          moduleFn = angularModule(module);
3633          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3634
3635          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3636            var invokeArgs = invokeQueue[i],
3637                provider = providerInjector.get(invokeArgs[0]);
3638
3639            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3640          }
3641        } else if (isFunction(module)) {
3642            runBlocks.push(providerInjector.invoke(module));
3643        } else if (isArray(module)) {
3644            runBlocks.push(providerInjector.invoke(module));
3645        } else {
3646          assertArgFn(module, 'module');
3647        }
3648      } catch (e) {
3649        if (isArray(module)) {
3650          module = module[module.length - 1];
3651        }
3652        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3653          // Safari & FF's stack traces don't contain error.message content
3654          // unlike those of Chrome and IE
3655          // So if stack doesn't contain message, we create a new string that contains both.
3656          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3657          /* jshint -W022 */
3658          e = e.message + '\n' + e.stack;
3659        }
3660        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3661                  module, e.stack || e.message || e);
3662      }
3663    });
3664    return runBlocks;
3665  }
3666
3667  ////////////////////////////////////
3668  // internal Injector
3669  ////////////////////////////////////
3670
3671  function createInternalInjector(cache, factory) {
3672
3673    function getService(serviceName) {
3674      if (cache.hasOwnProperty(serviceName)) {
3675        if (cache[serviceName] === INSTANTIATING) {
3676          throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
3677        }
3678        return cache[serviceName];
3679      } else {
3680        try {
3681          path.unshift(serviceName);
3682          cache[serviceName] = INSTANTIATING;
3683          return cache[serviceName] = factory(serviceName);
3684        } catch (err) {
3685          if (cache[serviceName] === INSTANTIATING) {
3686            delete cache[serviceName];
3687          }
3688          throw err;
3689        } finally {
3690          path.shift();
3691        }
3692      }
3693    }
3694
3695    function invoke(fn, self, locals){
3696      var args = [],
3697          $inject = annotate(fn),
3698          length, i,
3699          key;
3700
3701      for(i = 0, length = $inject.length; i < length; i++) {
3702        key = $inject[i];
3703        if (typeof key !== 'string') {
3704          throw $injectorMinErr('itkn',
3705                  'Incorrect injection token! Expected service name as string, got {0}', key);
3706        }
3707        args.push(
3708          locals && locals.hasOwnProperty(key)
3709          ? locals[key]
3710          : getService(key)
3711        );
3712      }
3713      if (!fn.$inject) {
3714        // this means that we must be an array.
3715        fn = fn[length];
3716      }
3717
3718      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3719      // #5388
3720      return fn.apply(self, args);
3721    }
3722
3723    function instantiate(Type, locals) {
3724      var Constructor = function() {},
3725          instance, returnedValue;
3726
3727      // Check if Type is annotated and use just the given function at n-1 as parameter
3728      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3729      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3730      instance = new Constructor();
3731      returnedValue = invoke(Type, instance, locals);
3732
3733      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3734    }
3735
3736    return {
3737      invoke: invoke,
3738      instantiate: instantiate,
3739      get: getService,
3740      annotate: annotate,
3741      has: function(name) {
3742        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3743      }
3744    };
3745  }
3746}
3747
3748/**
3749 * @ngdoc function
3750 * @name ng.$anchorScroll
3751 * @requires $window
3752 * @requires $location
3753 * @requires $rootScope
3754 *
3755 * @description
3756 * When called, it checks current value of `$location.hash()` and scroll to related element,
3757 * according to rules specified in
3758 * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
3759 *
3760 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3761 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3762 * 
3763 * @example
3764   <example>
3765     <file name="index.html">
3766       <div id="scrollArea" ng-controller="ScrollCtrl">
3767         <a ng-click="gotoBottom()">Go to bottom</a>
3768         <a id="bottom"></a> You're at the bottom!
3769       </div>
3770     </file>
3771     <file name="script.js">
3772       function ScrollCtrl($scope, $location, $anchorScroll) {
3773         $scope.gotoBottom = function (){
3774           // set the location.hash to the id of
3775           // the element you wish to scroll to.
3776           $location.hash('bottom');
3777           
3778           // call $anchorScroll()
3779           $anchorScroll();
3780         }
3781       }
3782     </file>
3783     <file name="style.css">
3784       #scrollArea {
3785         height: 350px;
3786         overflow: auto;
3787       }
3788
3789       #bottom {
3790         display: block;
3791         margin-top: 2000px;
3792       }
3793     </file>
3794   </example>
3795 */
3796function $AnchorScrollProvider() {
3797
3798  var autoScrollingEnabled = true;
3799
3800  this.disableAutoScrolling = function() {
3801    autoScrollingEnabled = false;
3802  };
3803
3804  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
3805    var document = $window.document;
3806
3807    // helper function to get first anchor from a NodeList
3808    // can't use filter.filter, as it accepts only instances of Array
3809    // and IE can't convert NodeList to an array using [].slice
3810    // TODO(vojta): use filter if we change it to accept lists as well
3811    function getFirstAnchor(list) {
3812      var result = null;
3813      forEach(list, function(element) {
3814        if (!result && lowercase(element.nodeName) === 'a') result = element;
3815      });
3816      return result;
3817    }
3818
3819    function scroll() {
3820      var hash = $location.hash(), elm;
3821
3822      // empty hash, scroll to the top of the page
3823      if (!hash) $window.scrollTo(0, 0);
3824
3825      // element with given id
3826      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
3827
3828      // first anchor with given name :-D
3829      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
3830
3831      // no element and hash == 'top', scroll to the top of the page
3832      else if (hash === 'top') $window.scrollTo(0, 0);
3833    }
3834
3835    // does not scroll when user clicks on anchor link that is currently on
3836    // (no url change, no $location.hash() change), browser native does scroll
3837    if (autoScrollingEnabled) {
3838      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
3839        function autoScrollWatchAction() {
3840          $rootScope.$evalAsync(scroll);
3841        });
3842    }
3843
3844    return scroll;
3845  }];
3846}
3847
3848var $animateMinErr = minErr('$animate');
3849
3850/**
3851 * @ngdoc object
3852 * @name ng.$animateProvider
3853 *
3854 * @description
3855 * Default implementation of $animate that doesn't perform any animations, instead just
3856 * synchronously performs DOM
3857 * updates and calls done() callbacks.
3858 *
3859 * In order to enable animations the ngAnimate module has to be loaded.
3860 *
3861 * To see the functional implementation check out src/ngAnimate/animate.js
3862 */
3863var $AnimateProvider = ['$provide', function($provide) {
3864
3865  
3866  this.$$selectors = {};
3867
3868
3869  /**
3870   * @ngdoc function
3871   * @name ng.$animateProvider#register
3872   * @methodOf ng.$animateProvider
3873   *
3874   * @description
3875   * Registers a new injectable animation factory function. The factory function produces the
3876   * animation object which contains callback functions for each event that is expected to be
3877   * animated.
3878   *
3879   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
3880   *   must be called once the element animation is complete. If a function is returned then the
3881   *   animation service will use this function to cancel the animation whenever a cancel event is
3882   *   triggered.
3883   *
3884   *
3885   *<pre>
3886   *   return {
3887     *     eventFn : function(element, done) {
3888     *       //code to run the animation
3889     *       //once complete, then run done()
3890     *       return function cancellationFunction() {
3891     *         //code to cancel the animation
3892     *       }
3893     *     }
3894     *   }
3895   *</pre>
3896   *
3897   * @param {string} name The name of the animation.
3898   * @param {function} factory The factory function that will be executed to return the animation
3899   *                           object.
3900   */
3901  this.register = function(name, factory) {
3902    var key = name + '-animation';
3903    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
3904        "Expecting class selector starting with '.' got '{0}'.", name);
3905    this.$$selectors[name.substr(1)] = key;
3906    $provide.factory(key, factory);
3907  };
3908
3909  /**
3910   * @ngdoc function
3911   * @name ng.$animateProvider#classNameFilter
3912   * @methodOf ng.$animateProvider
3913   *
3914   * @description
3915   * Sets and/or returns the CSS class regular expression that is checked when performing
3916   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
3917   * therefore enable $animate to attempt to perform an animation on any element.
3918   * When setting the classNameFilter value, animations will only be performed on elements
3919   * that successfully match the filter expression. This in turn can boost performance
3920   * for low-powered devices as well as applications containing a lot of structural operations.
3921   * @param {RegExp=} expression The className expression which will be checked against all animations
3922   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
3923   */
3924  this.classNameFilter = function(expression) {
3925    if(arguments.length === 1) {
3926      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
3927    }
3928    return this.$$classNameFilter;
3929  };
3930
3931  this.$get = ['$timeout', function($timeout) {
3932
3933    /**
3934     *
3935     * @ngdoc object
3936     * @name ng.$animate
3937     * @description The $animate service provides rudimentary DOM manipulation functions to
3938     * insert, remove and move elements within the DOM, as well as adding and removing classes.
3939     * This service is the core service used by the ngAnimate $animator service which provides
3940     * high-level animation hooks for CSS and JavaScript.
3941     *
3942     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
3943     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
3944     * manipulation operations.
3945     *
3946     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
3947     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
3948     * page}.
3949     */
3950    return {
3951
3952      /**
3953       *
3954       * @ngdoc function
3955       * @name ng.$animate#enter
3956       * @methodOf ng.$animate
3957       * @function
3958       * @description Inserts the element into the DOM either after the `after` element or within
3959       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
3960       * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
3961       * @param {jQuery/jqLite element} parent the parent element which will append the element as
3962       *   a child (if the after element is not present)
3963       * @param {jQuery/jqLite element} after the sibling element which will append the element
3964       *   after itself
3965       * @param {function=} done callback function that will be called after the element has been
3966       *   inserted into the DOM
3967       */
3968      enter : function(element, parent, after, done) {
3969        if (after) {
3970          after.after(element);
3971        } else {
3972          if (!parent || !parent[0]) {
3973            parent = after.parent();
3974          }
3975          parent.append(element);
3976        }
3977        done && $timeout(done, 0, false);
3978      },
3979
3980      /**
3981       *
3982       * @ngdoc function
3983       * @name ng.$animate#leave
3984       * @methodOf ng.$animate
3985       * @function
3986       * @description Removes the element from the DOM. Once complete, the done() callback will be
3987       *   fired (if provided).
3988       * @param {jQuery/jqLite element} element the element which will be removed from the DOM
3989       * @param {function=} done callback function that will be called after the element has been
3990       *   removed from the DOM
3991       */
3992      leave : function(element, done) {
3993        element.remove();
3994        done && $timeout(done, 0, false);
3995      },
3996
3997      /**
3998       *
3999       * @ngdoc function
4000       * @name ng.$animate#move
4001       * @methodOf ng.$animate
4002       * @function
4003       * @description Moves the position of the provided element within the DOM to be placed
4004       * either after the `after` element or inside of the `parent` element. Once complete, the
4005       * done() callback will be fired (if provided).
4006       * 
4007       * @param {jQuery/jqLite element} element the element which will be moved around within the
4008       *   DOM
4009       * @param {jQuery/jqLite element} parent the parent element where the element will be
4010       *   inserted into (if the after element is not present)
4011       * @param {jQuery/jqLite element} after the sibling element where the element will be
4012       *   positioned next to
4013       * @param {function=} done the callback function (if provided) that will be fired after the
4014       *   element has been moved to its new position
4015       */
4016      move : function(element, parent, after, done) {
4017        // Do not remove element before insert. Removing will cause data associated with the
4018        // element to be dropped. Insert will implicitly do the remove.
4019        this.enter(element, parent, after, done);
4020      },
4021
4022      /**
4023       *
4024       * @ngdoc function
4025       * @name ng.$animate#addClass
4026       * @methodOf ng.$animate
4027       * @function
4028       * @description Adds the provided className CSS class value to the provided element. Once
4029       * complete, the done() callback will be fired (if provided).
4030       * @param {jQuery/jqLite element} element the element which will have the className value
4031       *   added to it
4032       * @param {string} className the CSS class which will be added to the element
4033       * @param {function=} done the callback function (if provided) that will be fired after the
4034       *   className value has been added to the element
4035       */
4036      addClass : function(element, className, done) {
4037        className = isString(className) ?
4038                      className :
4039                      isArray(className) ? className.join(' ') : '';
4040        forEach(element, function (element) {
4041          jqLiteAddClass(element, className);
4042        });
4043        done && $timeout(done, 0, false);
4044      },
4045
4046      /**
4047       *
4048       * @ngdoc function
4049       * @name ng.$animate#removeClass
4050       * @methodOf ng.$animate
4051       * @function
4052       * @description Removes the provided className CSS class value from the provided element.
4053       * Once complete, the done() callback will be fired (if provided).
4054       * @param {jQuery/jqLite element} element the element which will have the className value
4055       *   removed from it
4056       * @param {string} className the CSS class which will be removed from the element
4057       * @param {function=} done the callback function (if provided) that will be fired after the
4058       *   className value has been removed from the element
4059       */
4060      removeClass : function(element, className, done) {
4061        className = isString(className) ?
4062                      className :
4063                      isArray(className) ? className.join(' ') : '';
4064        forEach(element, function (element) {
4065          jqLiteRemoveClass(element, className);
4066        });
4067        done && $timeout(done, 0, false);
4068      },
4069
4070      /**
4071       *
4072       * @ngdoc function
4073       * @name ng.$animate#setClass
4074       * @methodOf ng.$animate
4075       * @function
4076       * @description Adds and/or removes the given CSS classes to and from the element.
4077       * Once complete, the done() callback will be fired (if provided).
4078       * @param {jQuery/jqLite element} element the element which will it's CSS classes changed
4079       *   removed from it
4080       * @param {string} add the CSS classes which will be added to the element
4081       * @param {string} remove the CSS class which will be removed from the element
4082       * @param {function=} done the callback function (if provided) that will be fired after the
4083       *   CSS classes have been set on the element
4084       */
4085      setClass : function(element, add, remove, done) {
4086        forEach(element, function (element) {
4087          jqLiteAddClass(element, add);
4088          jqLiteRemoveClass(element, remove);
4089        });
4090        done && $timeout(done, 0, false);
4091      },
4092
4093      enabled : noop
4094    };
4095  }];
4096}];
4097
4098/**
4099 * ! This is a private undocumented service !
4100 *
4101 * @name ng.$browser
4102 * @requires $log
4103 * @description
4104 * This object has two goals:
4105 *
4106 * - hide all the global state in the browser caused by the window object
4107 * - abstract away all the browser specific features and inconsistencies
4108 *
4109 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4110 * service, which can be used for convenient testing of the application without the interaction with
4111 * the real browser apis.
4112 */
4113/**
4114 * @param {object} window The global window object.
4115 * @param {object} document jQuery wrapped document.
4116 * @param {function()} XHR XMLHttpRequest constructor.
4117 * @param {object} $log console.log or an object with the same interface.
4118 * @param {object} $sniffer $sniffer service
4119 */
4120function Browser(window, document, $log, $sniffer) {
4121  var self = this,
4122      rawDocument = document[0],
4123      location = window.location,
4124      history = window.history,
4125      setTimeout = window.setTimeout,
4126      clearTimeout = window.clearTimeout,
4127      pendingDeferIds = {};
4128
4129  self.isMock = false;
4130
4131  var outstandingRequestCount = 0;
4132  var outstandingRequestCallbacks = [];
4133
4134  // TODO(vojta): remove this temporary api
4135  self.$$completeOutstandingRequest = completeOutstandingRequest;
4136  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4137
4138  /**
4139   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4140   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4141   */
4142  function completeOutstandingRequest(fn) {
4143    try {
4144      fn.apply(null, sliceArgs(arguments, 1));
4145    } finally {
4146      outstandingRequestCount--;
4147      if (outstandingRequestCount === 0) {
4148        while(outstandingRequestCallbacks.length) {
4149          try {
4150            outstandingRequestCallbacks.pop()();
4151          } catch (e) {
4152            $log.error(e);
4153          }
4154        }
4155      }
4156    }
4157  }
4158
4159  /**
4160   * @private
4161   * Note: this method is used only by scenario runner
4162   * TODO(vojta): prefix this method with $$ ?
4163   * @param {function()} callback Function that will be called when no outstanding request
4164   */
4165  self.notifyWhenNoOutstandingRequests = function(callback) {
4166    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4167    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4168    // regular poller would result in flaky tests.
4169    forEach(pollFns, function(pollFn){ pollFn(); });
4170
4171    if (outstandingRequestCount === 0) {
4172      callback();
4173    } else {
4174      outstandingRequestCallbacks.push(callback);
4175    }
4176  };
4177
4178  //////////////////////////////////////////////////////////////
4179  // Poll Watcher API
4180  //////////////////////////////////////////////////////////////
4181  var pollFns = [],
4182      pollTimeout;
4183
4184  /**
4185   * @name ng.$browser#addPollFn
4186   * @methodOf ng.$browser
4187   *
4188   * @param {function()} fn Poll function to add
4189   *
4190   * @description
4191   * Adds a function to the list of functions that poller periodically executes,
4192   * and starts polling if not started yet.
4193   *
4194   * @returns {function()} the added function
4195   */
4196  self.addPollFn = function(fn) {
4197    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4198    pollFns.push(fn);
4199    return fn;
4200  };
4201
4202  /**
4203   * @param {number} interval How often should browser call poll functions (ms)
4204   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4205   *
4206   * @description
4207   * Configures the poller to run in the specified intervals, using the specified
4208   * setTimeout fn and kicks it off.
4209   */
4210  function startPoller(interval, setTimeout) {
4211    (function check() {
4212      forEach(pollFns, function(pollFn){ pollFn(); });
4213      pollTimeout = setTimeout(check, interval);
4214    })();
4215  }
4216
4217  //////////////////////////////////////////////////////////////
4218  // URL API
4219  //////////////////////////////////////////////////////////////
4220
4221  var lastBrowserUrl = location.href,
4222      baseElement = document.find('base'),
4223      newLocation = null;
4224
4225  /**
4226   * @name ng.$browser#url
4227   * @methodOf ng.$browser
4228   *
4229   * @description
4230   * GETTER:
4231   * Without any argument, this method just returns current value of location.href.
4232   *
4233   * SETTER:
4234   * With at least one argument, this method sets url to new value.
4235   * If html5 history api supported, pushState/replaceState is used, otherwise
4236   * location.href/location.replace is used.
4237   * Returns its own instance to allow chaining
4238   *
4239   * NOTE: this api is intended for use only by the $location service. Please use the
4240   * {@link ng.$location $location service} to change url.
4241   *
4242   * @param {string} url New url (when used as setter)
4243   * @param {boolean=} replace Should new url replace current history record ?
4244   */
4245  self.url = function(url, replace) {
4246    // Android Browser BFCache causes location, history reference to become stale.
4247    if (location !== window.location) location = window.location;
4248    if (history !== window.history) history = window.history;
4249
4250    // setter
4251    if (url) {
4252      if (lastBrowserUrl == url) return;
4253      lastBrowserUrl = url;
4254      if ($sniffer.history) {
4255        if (replace) history.replaceState(null, '', url);
4256        else {
4257          history.pushState(null, '', url);
4258          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4259          baseElement.attr('href', baseElement.attr('href'));
4260        }
4261      } else {
4262        newLocation = url;
4263        if (replace) {
4264          location.replace(url);
4265        } else {
4266          location.href = url;
4267        }
4268      }
4269      return self;
4270    // getter
4271    } else {
4272      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4273      //   methods not updating location.href synchronously.
4274      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4275      return newLocation || location.href.replace(/%27/g,"'");
4276    }
4277  };
4278
4279  var urlChangeListeners = [],
4280      urlChangeInit = false;
4281
4282  function fireUrlChange() {
4283    newLocation = null;
4284    if (lastBrowserUrl == self.url()) return;
4285
4286    lastBrowserUrl = self.url();
4287    forEach(urlChangeListeners, function(listener) {
4288      listener(self.url());
4289    });
4290  }
4291
4292  /**
4293   * @name ng.$browser#onUrlChange
4294   * @methodOf ng.$browser
4295   * @TODO(vojta): refactor to use node's syntax for events
4296   *
4297   * @description
4298   * Register callback function that will be called, when url changes.
4299   *
4300   * It's only called when the url is changed from outside of angular:
4301   * - user types different url into address bar
4302   * - user clicks on history (forward/back) button
4303   * - user clicks on a link
4304   *
4305   * It's not called when url is changed by $browser.url() method
4306   *
4307   * The listener gets called with new url as parameter.
4308   *
4309   * NOTE: this api is intended for use only by the $location service. Please use the
4310   * {@link ng.$location $location service} to monitor url changes in angular apps.
4311   *
4312   * @param {function(string)} listener Listener function to be called when url changes.
4313   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4314   */
4315  self.onUrlChange = function(callback) {
4316    if (!urlChangeInit) {
4317      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4318      // don't fire popstate when user change the address bar and don't fire hashchange when url
4319      // changed by push/replaceState
4320
4321      // html5 history api - popstate event
4322      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4323      // hashchange event
4324      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4325      // polling
4326      else self.addPollFn(fireUrlChange);
4327
4328      urlChangeInit = true;
4329    }
4330
4331    urlChangeListeners.push(callback);
4332    return callback;
4333  };
4334
4335  //////////////////////////////////////////////////////////////
4336  // Misc API
4337  //////////////////////////////////////////////////////////////
4338
4339  /**
4340   * @name ng.$browser#baseHref
4341   * @methodOf ng.$browser
4342   *
4343   * @description
4344   * Returns current <base href>
4345   * (always relative - without domain)
4346   *
4347   * @returns {string=} current <base href>
4348   */
4349  self.baseHref = function() {
4350    var href = baseElement.attr('href');
4351    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4352  };
4353
4354  //////////////////////////////////////////////////////////////
4355  // Cookies API
4356  //////////////////////////////////////////////////////////////
4357  var lastCookies = {};
4358  var lastCookieString = '';
4359  var cookiePath = self.baseHref();
4360
4361  /**
4362   * @name ng.$browser#cookies
4363   * @methodOf ng.$browser
4364   *
4365   * @param {string=} name Cookie name
4366   * @param {string=} value Cookie value
4367   *
4368   * @description
4369   * The cookies method provides a 'private' low level access to browser cookies.
4370   * It is not meant to be used directly, use the $cookie service instead.
4371   *
4372   * The return values vary depending on the arguments that the method was called with as follows:
4373   *
4374   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4375   *   it
4376   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4377   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4378   *   way)
4379   *
4380   * @returns {Object} Hash of all cookies (if called without any parameter)
4381   */
4382  self.cookies = function(name, value) {
4383    /* global escape: false, unescape: false */
4384    var cookieLength, cookieArray, cookie, i, index;
4385
4386    if (name) {
4387      if (value === undefined) {
4388        rawDocument.cookie = escape(name) + "=;
4388path=" + cookiePath +
4389                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4390      } else {
4391        if (isString(value)) {
4392          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4393                                ';path=' + cookiePath).length + 1;
4394
4395          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4396          // - 300 cookies
4397          // - 20 cookies per unique domain
4398          // - 4096 bytes per cookie
4399          if (cookieLength > 4096) {
4400            $log.warn("Cookie '"+ name +
4401              "' possibly not set or overflowed because it was too large ("+
4402              cookieLength + " > 4096 bytes)!");
4403          }
4404        }
4405      }
4406    } else {
4407      if (rawDocument.cookie !== lastCookieString) {
4408        lastCookieString = rawDocument.cookie;
4409        cookieArray = lastCookieString.split("; ");
4410        lastCookies = {};
4411
4412        for (i = 0; i < cookieArray.length; i++) {
4413          cookie = cookieArray[i];
4414          index = cookie.indexOf('=');
4415          if (index > 0) { //ignore nameless cookies
4416            name = unescape(cookie.substring(0, index));
4417            // the first value that is seen for a cookie is the most
4418            // specific one.  values for the same cookie name that
4419            // follow are for less specific paths.
4420            if (lastCookies[name] === undefined) {
4421              lastCookies[name] = unescape(cookie.substring(index + 1));
4422            }
4423          }
4424        }
4425      }
4426      return lastCookies;
4427    }
4428  };
4429
4430
4431  /**
4432   * @name ng.$browser#defer
4433   * @methodOf ng.$browser
4434   * @param {function()} fn A function, who's execution should be deferred.
4435   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4436   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4437   *
4438   * @description
4439   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4440   *
4441   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4442   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4443   * via `$browser.defer.flush()`.
4444   *
4445   */
4446  self.defer = function(fn, delay) {
4447    var timeoutId;
4448    outstandingRequestCount++;
4449    timeoutId = setTimeout(function() {
4450      delete pendingDeferIds[timeoutId];
4451      completeOutstandingRequest(fn);
4452    }, delay || 0);
4453    pendingDeferIds[timeoutId] = true;
4454    return timeoutId;
4455  };
4456
4457
4458  /**
4459   * @name ng.$browser#defer.cancel
4460   * @methodOf ng.$browser.defer
4461   *
4462   * @description
4463   * Cancels a deferred task identified with `deferId`.
4464   *
4465   * @param {*} deferId Token returned by the `$browser.defer` function.
4466   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4467   *                    canceled.
4468   */
4469  self.defer.cancel = function(deferId) {
4470    if (pendingDeferIds[deferId]) {
4471      delete pendingDeferIds[deferId];
4472      clearTimeout(deferId);
4473      completeOutstandingRequest(noop);
4474      return true;
4475    }
4476    return false;
4477  };
4478
4479}
4480
4481function $BrowserProvider(){
4482  this.$get = ['$window', '$log', '$sniffer', '$document',
4483      function( $window,   $log,   $sniffer,   $document){
4484        return new Browser($window, $document, $log, $sniffer);
4485      }];
4486}
4487
4488/**
4489 * @ngdoc object
4490 * @name ng.$cacheFactory
4491 *
4492 * @description
4493 * Factory that constructs cache objects and gives access to them.
4494 * 
4495 * <pre>
4496 * 
4497 *  var cache = $cacheFactory('cacheId');
4498 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4499 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4500 *
4501 *  cache.put("key", "value");
4502 *  cache.put("another key", "another value");
4503 *
4504 *  // We've specified no options on creation
4505 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2}); 
4506 * 
4507 * </pre>
4508 *
4509 *
4510 * @param {string} cacheId Name or id of the newly created cache.
4511 * @param {object=} options Options object that specifies the cache behavior. Properties:
4512 *
4513 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4514 *
4515 * @returns {object} Newly created cache object with the following set of methods:
4516 *
4517 * - `{object}` `info()` — Returns id, size, and options of cache.
4518 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4519 *   it.
4520 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4521 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4522 * - `{void}` `removeAll()` — Removes all cached values.
4523 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4524 *
4525 */
4526function $CacheFactoryProvider() {
4527
4528  this.$get = function() {
4529    var caches = {};
4530
4531    function cacheFactory(cacheId, options) {
4532      if (cacheId in caches) {
4533        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4534      }
4535
4536      var size = 0,
4537          stats = extend({}, options, {id: cacheId}),
4538          data = {},
4539          capacity = (options && options.capacity) || Number.MAX_VALUE,
4540          lruHash = {},
4541          freshEnd = null,
4542          staleEnd = null;
4543
4544      return caches[cacheId] = {
4545
4546        put: function(key, value) {
4547          var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4548
4549          refresh(lruEntry);
4550
4551          if (isUndefined(value)) return;
4552          if (!(key in data)) size++;
4553          data[key] = value;
4554
4555          if (size > capacity) {
4556            this.remove(staleEnd.key);
4557          }
4558
4559          return value;
4560        },
4561
4562
4563        get: function(key) {
4564          var lruEntry = lruHash[key];
4565
4566          if (!lruEntry) return;
4567
4568          refresh(lruEntry);
4569
4570          return data[key];
4571        },
4572
4573
4574        remove: function(key) {
4575          var lruEntry = lruHash[key];
4576
4577          if (!lruEntry) return;
4578
4579          if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4580          if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4581          link(lruEntry.n,lruEntry.p);
4582
4583          delete lruHash[key];
4584          delete data[key];
4585          size--;
4586        },
4587
4588
4589        removeAll: function() {
4590          data = {};
4591          size = 0;
4592          lruHash = {};
4593          freshEnd = staleEnd = null;
4594        },
4595
4596
4597        destroy: function() {
4598          data = null;
4599          stats = null;
4600          lruHash = null;
4601          delete caches[cacheId];
4602        },
4603
4604
4605        info: function() {
4606          return extend({}, stats, {size: size});
4607        }
4608      };
4609
4610
4611      /**
4612       * makes the `entry` the freshEnd of the LRU linked list
4613       */
4614      function refresh(entry) {
4615        if (entry != freshEnd) {
4616          if (!staleEnd) {
4617            staleEnd = entry;
4618          } else if (staleEnd == entry) {
4619            staleEnd = entry.n;
vendor: 5,054 bytes, lines 4620-4789
4620          }
4621
4622          link(entry.n, entry.p);
4623          link(entry, freshEnd);
4624          freshEnd = entry;
4625          freshEnd.n = null;
4626        }
4627      }
4628
4629
4630      /**
4631       * bidirectionally links two entries of the LRU linked list
4632       */
4633      function link(nextEntry, prevEntry) {
4634        if (nextEntry != prevEntry) {
4635          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
4636          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
4637        }
4638      }
4639    }
4640
4641
4642  /**
4643   * @ngdoc method
4644   * @name ng.$cacheFactory#info
4645   * @methodOf ng.$cacheFactory
4646   *
4647   * @description
4648   * Get information about all the of the caches that have been created
4649   *
4650   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
4651   */
4652    cacheFactory.info = function() {
4653      var info = {};
4654      forEach(caches, function(cache, cacheId) {
4655        info[cacheId] = cache.info();
4656      });
4657      return info;
4658    };
4659
4660
4661  /**
4662   * @ngdoc method
4663   * @name ng.$cacheFactory#get
4664   * @methodOf ng.$cacheFactory
4665   *
4666   * @description
4667   * Get access to a cache object by the `cacheId` used when it was created.
4668   *
4669   * @param {string} cacheId Name or id of a cache to access.
4670   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
4671   */
4672    cacheFactory.get = function(cacheId) {
4673      return caches[cacheId];
4674    };
4675
4676
4677    return cacheFactory;
4678  };
4679}
4680
4681/**
4682 * @ngdoc object
4683 * @name ng.$templateCache
4684 *
4685 * @description
4686 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
4687 * can load templates directly into the cache in a `script` tag, or by consuming the
4688 * `$templateCache` service directly.
4689 * 
4690 * Adding via the `script` tag:
4691 * <pre>
4692 * <html ng-app>
4693 * <head>
4694 * <script type="text/ng-template" id="templateId.html">
4695 *   This is the content of the template
4696 * </script>
4697 * </head>
4698 *   ...
4699 * </html>
4700 * </pre>
4701 * 
4702 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
4703 * the document, but it must be below the `ng-app` definition.
4704 * 
4705 * Adding via the $templateCache service:
4706 * 
4707 * <pre>
4708 * var myApp = angular.module('myApp', []);
4709 * myApp.run(function($templateCache) {
4710 *   $templateCache.put('templateId.html', 'This is the content of the template');
4711 * });
4712 * </pre>
4713 * 
4714 * To retrieve the template later, simply use it in your HTML:
4715 * <pre>
4716 * <div ng-include=" 'templateId.html' "></div>
4717 * </pre>
4718 * 
4719 * or get it via Javascript:
4720 * <pre>
4721 * $templateCache.get('templateId.html')
4722 * </pre>
4723 * 
4724 * See {@link ng.$cacheFactory $cacheFactory}.
4725 *
4726 */
4727function $TemplateCacheProvider() {
4728  this.$get = ['$cacheFactory', function($cacheFactory) {
4729    return $cacheFactory('templates');
4730  }];
4731}
4732
4733/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
4734 *
4735 * DOM-related variables:
4736 *
4737 * - "node" - DOM Node
4738 * - "element" - DOM Element or Node
4739 * - "$node" or "$element" - jqLite-wrapped node or element
4740 *
4741 *
4742 * Compiler related stuff:
4743 *
4744 * - "linkFn" - linking fn of a single directive
4745 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
4746 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
4747 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
4748 */
4749
4750
4751/**
4752 * @ngdoc function
4753 * @name ng.$compile
4754 * @function
4755 *
4756 * @description
4757 * Compiles an HTML string or DOM into a template and produces a template function, which
4758 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
4759 *
4760 * The compilation is a process of walking the DOM tree and matching DOM elements to
4761 * {@link ng.$compileProvider#methods_directive directives}.
4762 *
4763 * <div class="alert alert-warning">
4764 * **Note:** This document is an in-depth reference of all directive options.
4765 * For a gentle introduction to directives with examples of common use cases,
4766 * see the {@link guide/directive directive guide}.
4767 * </div>
4768 *
4769 * ## Comprehensive Directive API
4770 *
4771 * There are many different options for a directive.
4772 *
4773 * The difference resides in the return value of the factory function.
4774 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
4775 * or just the `postLink` function (all other properties will have the default values).
4776 *
4777 * <div class="alert alert-success">
4778 * **Best Practice:** It's recommended to use the "directive definition object" form.
4779 * </div>
4780 *
4781 * Here's an example directive declared with a Directive Definition Object:
4782 *
4783 * <pre>
4784 *   var myModule = angular.module(...);
4785 *
4786 *   myModule.directive('directiveName', function factory(injectables) {
4787 *     var directiveDefinitionObject = {
4788 *       priority: 0,
4789 *       template: '<div></div>
4789', // or // function(tElement, tAttrs) { ... },
4790 *       // or
4791 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
4792 *       replace: false,
4793 *       transclude: false,
4794 *       restrict: 'A',
4795 *       scope: false,
4796 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
4797 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
4798 *       compile: function compile(tElement, tAttrs, transclude) {
4799 *         return {
4800 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
4801 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
4802 *         }
4803 *         // or
4804 *         // return function postLink( ... ) { ... }
4805 *       },
4806 *       // or
4807 *       // link: {
4808 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
4809 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
4810 *       // }
4811 *       // or
4812 *       // link: function postLink( ... ) { ... }
4813 *     };
4814 *     return directiveDefinitionObject;
4815 *   });
4816 * </pre>
4817 *
4818 * <div class="alert alert-warning">
4819 * **Note:** Any unspecified options will use the default value. You can see the default values below.
4820 * </div>
4821 *
4822 * Therefore the above can be simplified as:
4823 *
4824 * <pre>
4825 *   var myModule = angular.module(...);
4826 *
4827 *   myModule.directive('directiveName', function factory(injectables) {
4828 *     var directiveDefinitionObject = {
4829 *       link: function postLink(scope, iElement, iAttrs) { ... }
4830 *     };
4831 *     return directiveDefinitionObject;
4832 *     // or
4833 *     // return function postLink(scope, iElement, iAttrs) { ... }
4834 *   });
4835 * </pre>
4836 *
4837 *
4838 *
4839 * ### Directive Definition Object
4840 *
4841 * The directive definition object provides instructions to the {@link api/ng.$compile
4842 * compiler}. The attributes are:
4843 *
4844 * #### `priority`
4845 * When there are multiple directives defined on a single DOM element, sometimes it
4846 * is necessary to specify the order in which the directives are applied. The `priority` is used
4847 * to sort the directives before their `compile` functions get called. Priority is defined as a
4848 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
4849 * are also run in priority order, but post-link functions are run in reverse order. The order
4850 * of directives with the same priority is undefined. The default priority is `0`.
4851 *
4852 * #### `terminal`
4853 * If set to true then the current `priority` will be the last set of directives
4854 * which will execute (any directives at the current priority will still execute
4855 * as the order of execution on same `priority` is undefined).
4856 *
4857 * #### `scope`
4858 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
4859 * same element request a new scope, only one new scope is created. The new scope rule does not
4860 * apply for the root of the template since the root of the template always gets a new scope.
4861 *
4862 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
4863 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
4864 * when creating reusable components, which should not accidentally read or modify data in the
4865 * parent scope.
4866 *
4867 * The 'isolate' scope takes an object hash which defines a set of local scope properties
4868 * derived from the parent scope. These local properties are useful for aliasing values for
4869 * templates. Locals definition is a hash of local scope property to its source:
4870 *
4871 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
4872 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
4873 *   attribute name is assumed to be the same as the local name.
4874 *   Given `<widget my-attr="hello {{name}}">` and widget definition
4875 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
4876 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
4877 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
4878 *   component scope).
4879 *
4880 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
4881 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
4882 *   name is specified then the attribute name is assumed to be the same as the local name.
4883 *   Given `<widget my-attr="parentModel">` and widget definition of
4884 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
4885 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
4886 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
4887 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
4888 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
4889 *
4890 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
4891 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
4892 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
4893 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
4894 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
4895 *   pass data from the isolated scope via an expression and to the parent scope, this can be
4896 *   done by passing a map of local variable names and values into the expression wrapper fn.
4897 *   For example, if the expression is `increment(amount)` then we can specify the amount value
4898 *   by calling the `localFn` as `localFn({amount: 22})`.
4899 *
4900 *
4901 *
4902 * #### `controller`
4903 * Controller constructor function. The controller is instantiated before the
4904 * pre-linking phase and it is shared with other directives (see
4905 * `require` attribute). This allows the directives to communicate with each other and augment
4906 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
4907 *
4908 * * `$scope` - Current scope associated with the element
4909 * * `$element` - Current element
4910 * * `$attrs` - Current attributes object for the element
4911 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
4912 *    The scope can be overridden by an optional first argument.
4913 *   `function([scope], cloneLinkingFn)`.
4914 *
4915 *
4916 * #### `require`
4917 * Require another directive and inject its controller as the fourth argument to the linking function. The
4918 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
4919 * injected argument will be an array in corresponding order. If no such directive can be
4920 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
4921 *
4922 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
4923 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
4924 * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
4925 * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
4926 *   `link` fn if not found.
4927 *
4928 *
4929 * #### `controllerAs`
4930 * Controller alias at the directive scope. An alias for the controller so it
4931 * can be referenced at the directive template. The directive needs to define a scope for this
4932 * configuration to be used. Useful in the case when directive is used as component.
4933 *
4934 *
4935 * #### `restrict`
4936 * String of subset of `EACM` which restricts the directive to a specific directive
4937 * declaration style. If omitted, the default (attributes only) is used.
4938 *
4939 * * `E` - Element name: `<my-directive></my-directive>`
4940 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
4941 * * `C` - Class: `<div class="my-directive: exp;"></div>`
4942 * * `M` - Comment: `<!-- directive: my-directive exp -->`
4943 *
4944 *
4945 * #### `template`
4946 * replace the current element with the contents of the HTML. The replacement process
4947 * migrates all of the attributes / classes from the old element to the new one. See the
4948 * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
4949 * Directives Guide} for an example.
4950 *
4951 * You can specify `template` as a string representing the template or as a function which takes
4952 * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
4953 * returns a string value representing the template.
4954 *
4955 *
4956 * #### `templateUrl`
4957 * Same as `template` but the template is loaded from the specified URL. Because
4958 * the template loading is asynchronous the compilation/linking is suspended until the template
4959 * is loaded.
4960 *
4961 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
4962 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
4963 * a string value representing the url.  In either case, the template URL is passed through {@link
4964 * api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}.
4965 *
4966 *
4967 * #### `replace`
4968 * specify where the template should be inserted. Defaults to `false`.
4969 *
4970 * * `true` - the template will replace the current element.
4971 * * `false` - the template will replace the contents of the current element.
4972 *
4973 *
4974 * #### `transclude`
4975 * compile the content of the element and make it available to the directive.
4976 * Typically used with {@link api/ng.directive:ngTransclude
4977 * ngTransclude}. The advantage of transclusion is that the linking function receives a
4978 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
4979 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
4980 * scope. This makes it possible for the widget to have private state, and the transclusion to
4981 * be bound to the parent (pre-`isolate`) scope.
4982 *
4983 * * `true` - transclude the content of the directive.
4984 * * `'element'` - transclude the whole element including any directives defined at lower priority.
4985 *
4986 *
4987 * #### `compile`
4988 *
4989 * <pre>
4990 *   function compile(tElement, tAttrs, transclude) { ... }
4991 * </pre>
4992 *
4993 * The compile function deals with transforming the template DOM. Since most directives do not do
4994 * template transformation, it is not used often. Examples that require compile functions are
4995 * directives that transform template DOM, such as {@link
4996 * api/ng.directive:ngRepeat ngRepeat}, or load the contents
4997 * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The
4998 * compile function takes the following arguments.
4999 *
5000 *   * `tElement` - template element - The element where the directive has been declared. It is
5001 *     safe to do template transformation on the element and child elements only.
5002 *
5003 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5004 *     between all directive compile functions.
5005 *
5006 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5007 *
5008 * <div class="alert alert-warning">
5009 * **Note:** The template instance and the link instance may be different objects if the template has
5010 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5011 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5012 * should be done in a linking function rather than in a compile function.
5013 * </div>
5014 *
5015 * <div class="alert alert-error">
5016 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5017 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5018 *   to the link function instead.
5019 * </div>
5020
5021 * A compile function can have a return value which can be either a function or an object.
5022 *
5023 * * returning a (post-link) function - is equivalent to registering the linking function via the
5024 *   `link` property of the config object when the compile function is empty.
5025 *
5026 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5027 *   control when a linking function should be called during the linking phase. See info about
5028 *   pre-linking and post-linking functions below.
5029 *
5030 *
5031 * #### `link`
5032 * This property is used only if the `compile` property is not defined.
5033 *
5034 * <pre>
5035 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5036 * </pre>
5037 *
5038 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5039 * executed after the template has been cloned. This is where most of the directive logic will be
5040 * put.
5041 *
5042 *   * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
5043 *     directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}.
5044 *
5045 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5046 *     manipulate the children of the element only in `postLink` function since the children have
5047 *     already been linked.
5048 *
5049 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5050 *     between all directive linking functions.
5051 *
5052 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5053 *     element defines a controller. The controller is shared among all the directives, which allows
5054 *     the directives to use the controllers as a communication channel.
5055 *
5056 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5057 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5058 *     parameter of directive controllers.
5059 *     `function([scope], cloneLinkingFn)`.
5060 *
5061 *
5062 * #### Pre-linking function
5063 *
5064 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5065 * compiler linking function will fail to locate the correct elements for linking.
5066 *
5067 * #### Post-linking function
5068 *
5069 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5070 *
5071 * <a name="Attributes"></a>
5072 * ### Attributes
5073 *
5074 * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5075 * `link()` or `compile()` functions. It has a variety of uses.
5076 *
5077 * accessing *Normalized attribute names:*
5078 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5079 * the attributes object allows for normalized access to
5080 *   the attributes.
5081 *
5082 * * *Directive inter-communication:* All directives share the same instance of the attributes
5083 *   object which allows the directives to use the attributes object as inter directive
5084 *   communication.
5085 *
5086 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5087 *   allowing other directives to read the interpolated value.
5088 *
5089 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5090 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
5091 *   the only way to easily get the actual value because during the linking phase the interpolation
5092 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5093 *
5094 * <pre>
5095 * function linkingFn(scope, elm, attrs, ctrl) {
5096 *   // get the attribute value
5097 *   console.log(attrs.ngModel);
5098 *
5099 *   // change the attribute
5100 *   attrs.$set('ngModel', 'new value');
5101 *
5102 *   // observe changes to interpolated attribute
5103 *   attrs.$observe('ngModel', function(value) {
5104 *     console.log('ngModel has changed value to ' + value);
5105 *   });
5106 * }
5107 * </pre>
5108 *
5109 * Below is an example using `$compileProvider`.
5110 *
5111 * <div class="alert alert-warning">
5112 * **Note**: Typically directives are registered with `module.directive`. The example below is
5113 * to illustrate how `$compile` works.
5114 * </div>
5115 *
5116 <doc:example module="compile">
5117   <doc:source>
5118    <script>
5119      angular.module('compile', [], function($compileProvider) {
5120        // configure new 'compile' directive by passing a directive
5121        // factory function. The factory function injects the '$compile'
5122        $compileProvider.directive('compile', function($compile) {
5123          // directive factory creates a link function
5124          return function(scope, element, attrs) {
5125            scope.$watch(
5126              function(scope) {
5127                 // watch the 'compile' expression for changes
5128                return scope.$eval(attrs.compile);
5129              },
5130              function(value) {
5131                // when the 'compile' expression changes
5132                // assign it into the current DOM
5133                element.html(value);
5134
5135                // compile the new DOM and link it to the current
5136                // scope.
5137                // NOTE: we only compile .childNodes so that
5138                // we don't get into infinite loop compiling ourselves
5139                $compile(element.contents())(scope);
5140              }
5141            );
5142          };
5143        })
5144      });
5145
5146      function Ctrl($scope) {
5147        $scope.name = 'Angular';
5148        $scope.html = 'Hello {{name}}';
5149      }
5150    </script>
5151    <div ng-controller="Ctrl">
5152      <input ng-model="name"> <br>
5153      <textarea ng-model="html"></textarea> <br>
5154      <div compile="html"></div>
5155    </div>
5156   </doc:source>
5157   <doc:protractor>
5158     it('should auto compile', function() {
5159       var textarea = $('textarea');
5160       var output = $('div[compile]');
5161       // The initial state reads 'Hello Angular'.
5162       expect(output.getText()).toBe('Hello Angular');
5163       textarea.clear();
5164       textarea.sendKeys('{{name}}!');
5165       expect(output.getText()).toBe('Angular!');
5166     });
5167   </doc:protractor>
5168 </doc:example>
5169
5170 *
5171 *
5172 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5173 * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
5174 * @param {number} maxPriority only apply directives lower then given priority (Only effects the
5175 *                 root element(s), not their children)
5176 * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
5177 * (a DOM element/tree) to a scope. Where:
5178 *
5179 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5180 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5181 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5182 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5183 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5184 *
5185 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5186 *      * `scope` - is the current scope with which the linking function is working with.
5187 *
5188 * Calling the linking function returns the element of the template. It is either the original
5189 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5190 *
5191 * After linking the view is not updated until after a call to $digest which typically is done by
5192 * Angular automatically.
5193 *
5194 * If you need access to the bound view, there are two ways to do it:
5195 *
5196 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5197 *   before you send them to the compiler and keep this reference around.
5198 *   <pre>
5199 *     var element = $compile('<p>{{total}}</p>')(scope);
5200 *   </pre>
5201 *
5202 * - if on the other hand, you need the element to be cloned, the view reference from the original
5203 *   example would not point to the clone, but rather to the original template that was cloned. In
5204 *   this case, you can access the clone via the cloneAttachFn:
5205 *   <pre>
5206 *     var templateElement = angular.element('<p>{{total}}</p>'),
5207 *         scope = ....;
5208 *
5209 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5210 *       //attach the clone to DOM document at the right place
5211 *     });
5212 *
5213 *     //now we have reference to the cloned DOM via `clonedElement`
5214 *   </pre>
5215 *
5216 *
5217 * For information on how the compiler works, see the
5218 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5219 */
5220
5221var $compileMinErr = minErr('$compile');
5222
5223/**
5224 * @ngdoc service
5225 * @name ng.$compileProvider
5226 * @function
5227 *
5228 * @description
5229 */
vendor: 4,092 bytes, lines 5230-5322
5230$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5231function $CompileProvider($provide, $$sanitizeUriProvider) {
5232  var hasDirectives = {},
5233      Suffix = 'Directive',
5234      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5235      CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
5236      TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|tbody)(\s+[^>]*)?>/i;
5237
5238  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5239  // The assumption is that future DOM event attribute names will begin with
5240  // 'on' and be composed of only English letters.
5241  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5242
5243  /**
5244   * @ngdoc function
5245   * @name ng.$compileProvider#directive
5246   * @methodOf ng.$compileProvider
5247   * @function
5248   *
5249   * @description
5250   * Register a new directive with the compiler.
5251   *
5252   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5253   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5254   *    names and the values are the factories.
5255   * @param {function|Array} directiveFactory An injectable directive factory function. See
5256   *    {@link guide/directive} for more info.
5257   * @returns {ng.$compileProvider} Self for chaining.
5258   */
5259   this.directive = function registerDirective(name, directiveFactory) {
5260    assertNotHasOwnProperty(name, 'directive');
5261    if (isString(name)) {
5262      assertArg(directiveFactory, 'directiveFactory');
5263      if (!hasDirectives.hasOwnProperty(name)) {
5264        hasDirectives[name] = [];
5265        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5266          function($injector, $exceptionHandler) {
5267            var directives = [];
5268            forEach(hasDirectives[name], function(directiveFactory, index) {
5269              try {
5270                var directive = $injector.invoke(directiveFactory);
5271                if (isFunction(directive)) {
5272                  directive = { compile: valueFn(directive) };
5273                } else if (!directive.compile && directive.link) {
5274                  directive.compile = valueFn(directive.link);
5275                }
5276                directive.priority = directive.priority || 0;
5277                directive.index = index;
5278                directive.name = directive.name || name;
5279                directive.require = directive.require || (directive.controller && directive.name);
5280                directive.restrict = directive.restrict || 'A';
5281                directives.push(directive);
5282              } catch (e) {
5283                $exceptionHandler(e);
5284              }
5285            });
5286            return directives;
5287          }]);
5288      }
5289      hasDirectives[name].push(directiveFactory);
5290    } else {
5291      forEach(name, reverseParams(registerDirective));
5292    }
5293    return this;
5294  };
5295
5296
5297  /**
5298   * @ngdoc function
5299   * @name ng.$compileProvider#aHrefSanitizationWhitelist
5300   * @methodOf ng.$compileProvider
5301   * @function
5302   *
5303   * @description
5304   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5305   * urls during a[href] sanitization.
5306   *
5307   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5308   *
5309   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5310   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5311   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5312   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5313   *
5314   * @param {RegExp=} regexp New regexp to whitelist urls with.
5315   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5316   *    chaining otherwise.
5317   */
5318  this.aHrefSanitizationWhitelist = function(regexp) {
5319    if (isDefined(regexp)) {
5320      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5321      return this;
5322    } else {
5323      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5324    }
5325  };
5326
5327
5328  /**
5329   * @ngdoc function
5330   * @name ng.$compileProvider#imgSrcSanitizationWhitelist
5331   * @methodOf ng.$compileProvider
5332   * @function
5333   *
5334   * @description
5335   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5336   * urls during img[src] sanitization.
5337   *
5338   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5339   *
5340   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5341   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5342   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5343   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5344   *
5345   * @param {RegExp=} regexp New regexp to whitelist urls with.
5346   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5347   *    chaining otherwise.
5348   */
5349  this.imgSrcSanitizationWhitelist = function(regexp) {
5350    if (isDefined(regexp)) {
5351      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5352      return this;
5353    } else {
5354      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5355    }
5356  };
5357
5358  this.$get = [
5359            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5360            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5361    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5362             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5363
5364    var Attributes = function(element, attr) {
5365      this.$$element = element;
5366      this.$attr = attr || {};
5367    };
5368
5369    Attributes.prototype = {
5370      $normalize: directiveNormalize,
5371
5372
5373      /**
5374       * @ngdoc function
5375       * @name ng.$compile.directive.Attributes#$addClass
5376       * @methodOf ng.$compile.directive.Attributes
5377       * @function
5378       *
5379       * @description
5380       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5381       * are enabled then an animation will be triggered for the class addition.
5382       *
5383       * @param {string} classVal The className value that will be added to the element
5384       */
5385      $addClass : function(classVal) {
5386        if(classVal && classVal.length > 0) {
5387          $animate.addClass(this.$$element, classVal);
5388        }
5389      },
5390
5391      /**
5392       * @ngdoc function
5393       * @name ng.$compile.directive.Attributes#$removeClass
5394       * @methodOf ng.$compile.directive.Attributes
5395       * @function
5396       *
5397       * @description
5398       * Removes the CSS class value specified by the classVal parameter from the element. If
5399       * animations are enabled then an animation will be triggered for the class removal.
5400       *
5401       * @param {string} classVal The className value that will be removed from the element
5402       */
5403      $removeClass : function(classVal) {
5404        if(classVal && classVal.length > 0) {
5405          $animate.removeClass(this.$$element, classVal);
5406        }
5407      },
5408
5409      /**
5410       * @ngdoc function
5411       * @name ng.$compile.directive.Attributes#$updateClass
5412       * @methodOf ng.$compile.directive.Attributes
5413       * @function
5414       *
5415       * @description
5416       * Adds and removes the appropriate CSS class values to the element based on the difference
5417       * between the new and old CSS class values (specified as newClasses and oldClasses).
5418       *
5419       * @param {string} newClasses The current CSS className value
5420       * @param {string} oldClasses The former CSS className value
5421       */
5422      $updateClass : function(newClasses, oldClasses) {
5423        var toAdd = tokenDifference(newClasses, oldClasses);
5424        var toRemove = tokenDifference(oldClasses, newClasses);
5425
5426        if(toAdd.length === 0) {
5427          $animate.removeClass(this.$$element, toRemove);
5428        } else if(toRemove.length === 0) {
5429          $animate.addClass(this.$$element, toAdd);
5430        } else {
5431          $animate.setClass(this.$$element, toAdd, toRemove);
5432        }
5433      },
5434
5435      /**
5436       * Set a normalized attribute on the element in a way such that all directives
5437       * can share the attribute. This function properly handles boolean attributes.
5438       * @param {string} key Normalized key. (ie ngAttribute)
5439       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5440       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5441       *     Defaults to true.
5442       * @param {string=} attrName Optional none normalized name. Defaults to key.
5443       */
5444      $set: function(key, value, writeAttr, attrName) {
5445        // TODO: decide whether or not to throw an error if "class"
5446        //is set through this function since it may cause $updateClass to
5447        //become unstable.
5448
5449        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5450            normalizedVal,
5451            nodeName;
5452
5453        if (booleanKey) {
5454          this.$$element.prop(key, value);
5455          attrName = booleanKey;
5456        }
5457
5458        this[key] = value;
5459
5460        // translate normalized key to actual key
5461        if (attrName) {
5462          this.$attr[key] = attrName;
5463        } else {
5464          attrName = this.$attr[key];
5465          if (!attrName) {
5466            this.$attr[key] = attrName = snake_case(key, '-');
5467          }
5468        }
5469
5470        nodeName = nodeName_(this.$$element);
5471
5472        // sanitize a[href] and img[src] values
5473        if ((nodeName === 'A' && key === 'href') ||
5474            (nodeName === 'IMG' && key === 'src')) {
5475          this[key] = value = $$sanitizeUri(value, key === 'src');
5476        }
5477
5478        if (writeAttr !== false) {
5479          if (value === null || value === undefined) {
5480            this.$$element.removeAttr(attrName);
5481          } else {
5482            this.$$element.attr(attrName, value);
5483          }
5484        }
5485
5486        // fire observers
5487        var $$observers = this.$$observers;
5488        $$observers && forEach($$observers[key], function(fn) {
5489          try {
5490            fn(value);
5491          } catch (e) {
5492            $exceptionHandler(e);
5493          }
5494        });
5495      },
5496
5497
5498      /**
5499       * @ngdoc function
5500       * @name ng.$compile.directive.Attributes#$observe
5501       * @methodOf ng.$compile.directive.Attributes
5502       * @function
5503       *
5504       * @description
5505       * Observes an interpolated attribute.
5506       *
5507       * The observer function will be invoked once during the next `$digest` following
5508       * compilation. The observer is then invoked whenever the interpolated value
5509       * changes.
5510       *
5511       * @param {string} key Normalized key. (ie ngAttribute) .
5512       * @param {function(interpolatedValue)} fn Function that will be called whenever
5513                the interpolated value of the attribute changes.
5514       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5515       * @returns {function()} the `fn` parameter.
5516       */
5517      $observe: function(key, fn) {
5518        var attrs = this,
5519            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5520            listeners = ($$observers[key] || ($$observers[key] = []));
5521
5522        listeners.push(fn);
5523        $rootScope.$evalAsync(function() {
5524          if (!listeners.$$inter) {
5525            // no one registered attribute interpolation function, so lets call it manually
5526            fn(attrs[key]);
5527          }
5528        });
5529        return fn;
5530      }
5531    };
5532
5533    var startSymbol = $interpolate.startSymbol(),
5534        endSymbol = $interpolate.endSymbol(),
5535        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5536            ? identity
5537            : function denormalizeTemplate(template) {
5538              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5539        },
5540        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5541
5542
5543    return compile;
5544
5545    //================================
5546
5547    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5548                        previousCompileContext) {
5549      if (!($compileNodes instanceof jqLite)) {
5550        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5551        // modify it.
5552        $compileNodes = jqLite($compileNodes);
5553      }
5554      // We can not compile top level text elements since text nodes can be merged and we will
5555      // not be able to attach scope data to them, so we will wrap them in <span>
5556      forEach($compileNodes, function(node, index){
5557        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5558          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5559        }
5560      });
5561      var compositeLinkFn =
5562              compileNodes($compileNodes, transcludeFn, $compileNodes,
5563                           maxPriority, ignoreDirective, previousCompileContext);
5564      safeAddClass($compileNodes, 'ng-scope');
5565      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
5566        assertArg(scope, 'scope');
5567        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5568        // and sometimes changes the structure of the DOM.
5569        var $linkNode = cloneConnectFn
5570          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5571          : $compileNodes;
5572
5573        forEach(transcludeControllers, function(instance, name) {
5574          $linkNode.data('$' + name + 'Controller', instance);
5575        });
5576
5577        // Attach scope only to non-text nodes.
5578        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5579          var node = $linkNode[i],
5580              nodeType = node.nodeType;
5581          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5582            $linkNode.eq(i).data('$scope', scope);
5583          }
5584        }
5585
5586        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5587        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
5588        return $linkNode;
5589      };
5590    }
5591
5592    function safeAddClass($element, className) {
5593      try {
5594        $element.addClass(className);
5595      } catch(e) {
5596        // ignore, since it means that we are trying to set class on
5597        // SVG element, where class name is read-only.
5598      }
5599    }
5600
5601    /**
5602     * Compile function matches each node in nodeList against the directives. Once all directives
5603     * for a particular node are collected their compile functions are executed. The compile
5604     * functions return values - the linking functions - are combined into a composite linking
5605     * function, which is the a linking function for the node.
5606     *
5607     * @param {NodeList} nodeList an array of nodes or NodeList to compile
5608     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
5609     *        scope argument is auto-generated to the new child of the transcluded parent scope.
5610     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
5611     *        the rootElement must be set the jqLite collection of the compile root. This is
5612     *        needed so that the jqLite collection items can be replaced with widgets.
5613     * @param {number=} maxPriority Max directive priority.
5614     * @returns {?function} A composite linking function of all of the matched directives or null.
5615     */
5616    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
5617                            previousCompileContext) {
5618      var linkFns = [],
5619          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
5620
5621      for (var i = 0; i < nodeList.length; i++) {
5622        attrs = new Attributes();
5623
5624        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
5625        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
5626                                        ignoreDirective);
5627
5628        nodeLinkFn = (directives.length)
5629            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
5630                                      null, [], [], previousCompileContext)
5631            : null;
5632
5633        if (nodeLinkFn && nodeLinkFn.scope) {
5634          safeAddClass(jqLite(nodeList[i]), 'ng-scope');
5635        }
5636
5637        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
5638                      !(childNodes = nodeList[i].childNodes) ||
5639                      !childNodes.length)
5640            ? null
5641            : compileNodes(childNodes,
5642                 nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
5643
5644        linkFns.push(nodeLinkFn, childLinkFn);
5645        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
5646        //use the previous context only for the first element in the virtual group
5647        previousCompileContext = null;
5648      }
5649
5650      // return a linking function if we have found anything, null otherwise
5651      return linkFnFound ? compositeLinkFn : null;
5652
5653      function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
5654        var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
5655
5656        // copy nodeList so that linking doesn't break due to live list updates.
5657        var nodeListLength = nodeList.length,
5658            stableNodeList = new Array(nodeListLength);
5659        for (i = 0; i < nodeListLength; i++) {
5660          stableNodeList[i] = nodeList[i];
5661        }
5662
5663        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
5664          node = stableNodeList[n];
5665          nodeLinkFn = linkFns[i++];
5666          childLinkFn = linkFns[i++];
5667          $node = jqLite(node);
5668
5669          if (nodeLinkFn) {
5670            if (nodeLinkFn.scope) {
5671              childScope = scope.$new();
5672              $node.data('$scope', childScope);
5673            } else {
5674              childScope = scope;
5675            }
5676            childTranscludeFn = nodeLinkFn.transclude;
5677            if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
5678              nodeLinkFn(childLinkFn, childScope, node, $rootElement,
5679                createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5680              );
5681            } else {
5682              nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
5683            }
5684          } else if (childLinkFn) {
5685            childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
5686          }
5687        }
5688      }
5689    }
5690
5691    function createBoundTranscludeFn(scope, transcludeFn) {
5692      return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
5693        var scopeCreated = false;
5694
5695        if (!transcludedScope) {
5696          transcludedScope = scope.$new();
5697          transcludedScope.$$transcluded = true;
5698          scopeCreated = true;
5699        }
5700
5701        var clone = transcludeFn(transcludedScope, cloneFn, controllers);
5702        if (scopeCreated) {
5703          clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
5704        }
5705        return clone;
5706      };
5707    }
5708
5709    /**
5710     * Looks for directives on the given node and adds them to the directive collection which is
5711     * sorted.
5712     *
5713     * @param node Node to search.
5714     * @param directives An array to which the directives are added to. This array is sorted before
5715     *        the function returns.
5716     * @param attrs The shared attrs object which is used to populate the normalized attributes.
5717     * @param {number=} maxPriority Max directive priority.
5718     */
5719    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
5720      var nodeType = node.nodeType,
5721          attrsMap = attrs.$attr,
5722          match,
5723          className;
5724
5725      switch(nodeType) {
5726        case 1: /* Element */
5727          // use the node name: <directive>
5728          addDirective(directives,
5729              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
5730
5731          // iterate over the attributes
5732          for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
5733                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
5734            var attrStartName = false;
5735            var attrEndName = false;
5736
5737            attr = nAttrs[j];
5738            if (!msie || msie >= 8 || attr.specified) {
5739              name = attr.name;
5740              // support ngAttr attribute binding
5741              ngAttrName = directiveNormalize(name);
5742              if (NG_ATTR_BINDING.test(ngAttrName)) {
5743                name = snake_case(ngAttrName.substr(6), '-');
5744              }
5745
5746              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
5747              if (ngAttrName === directiveNName + 'Start') {
5748                attrStartName = name;
5749                attrEndName = name.substr(0, name.length - 5) + 'end';
5750                name = name.substr(0, name.length - 6);
5751              }
5752
5753              nName = directiveNormalize(name.toLowerCase());
5754              attrsMap[nName] = name;
5755              attrs[nName] = value = trim(attr.value);
5756              if (getBooleanAttrName(node, nName)) {
5757                attrs[nName] = true; // presence means true
5758              }
5759              addAttrInterpolateDirective(node, directives, value, nName);
5760              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
5761                            attrEndName);
5762            }
5763          }
5764
5765          // use class as directive
5766          className = node.className;
5767          if (isString(className) && className !== '') {
5768            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
5769              nName = directiveNormalize(match[2]);
5770              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
5771                attrs[nName] = trim(match[3]);
5772              }
5773              className = className.substr(match.index + match[0].length);
5774            }
5775          }
5776          break;
5777        case 3: /* Text Node */
5778          addTextInterpolateDirective(directives, node.nodeValue);
5779          break;
5780        case 8: /* Comment */
5781          try {
5782            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
5783            if (match) {
5784              nName = directiveNormalize(match[1]);
5785              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
5786                attrs[nName] = trim(match[2]);
5787              }
5788            }
5789          } catch (e) {
5790            // turns out that under some circumstances IE9 throws errors when one attempts to read
5791            // comment's node value.
5792            // Just ignore it and continue. (Can't seem to reproduce in test case.)
5793          }
5794          break;
5795      }
5796
5797      directives.sort(byPriority);
5798      return directives;
5799    }
5800
5801    /**
5802     * Given a node with an directive-start it collects all of the siblings until it finds
5803     * directive-end.
5804     * @param node
5805     * @param attrStart
5806     * @param attrEnd
5807     * @returns {*}
5808     */
5809    function groupScan(node, attrStart, attrEnd) {
5810      var nodes = [];
5811      var depth = 0;
5812      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
5813        var startNode = node;
5814        do {
5815          if (!node) {
5816            throw $compileMinErr('uterdir',
5817                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
5818                      attrStart, attrEnd);
5819          }
5820          if (node.nodeType == 1 /** Element **/) {
5821            if (node.hasAttribute(attrStart)) depth++;
5822            if (node.hasAttribute(attrEnd)) depth--;
5823          }
5824          nodes.push(node);
5825          node = node.nextSibling;
5826        } while (depth > 0);
5827      } else {
5828        nodes.push(node);
5829      }
5830
5831      return jqLite(nodes);
5832    }
5833
5834    /**
5835     * Wrapper for linking function which converts normal linking function into a grouped
5836     * linking function.
5837     * @param linkFn
5838     * @param attrStart
5839     * @param attrEnd
5840     * @returns {Function}
5841     */
5842    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
5843      return function(scope, element, attrs, controllers, transcludeFn) {
5844        element = groupScan(element[0], attrStart, attrEnd);
5845        return linkFn(scope, element, attrs, controllers, transcludeFn);
5846      };
5847    }
5848
5849    /**
5850     * Once the directives have been collected, their compile functions are executed. This method
5851     * is responsible for inlining directive templates as well as terminating the application
5852     * of the directives if the terminal directive has been reached.
5853     *
5854     * @param {Array} directives Array of collected directives to execute their compile function.
5855     *        this needs to be pre-sorted by priority order.
5856     * @param {Node} compileNode The raw DOM node to apply the compile functions to
5857     * @param {Object} templateAttrs The shared attribute function
5858     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
5859     *                                                  scope argument is auto-generated to the new
5860     *                                                  child of the transcluded parent scope.
5861     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
5862     *                              argument has the root jqLite array so that we can replace nodes
5863     *                              on it.
5864     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
5865     *                                           compiling the transclusion.
5866     * @param {Array.<Function>} preLinkFns
5867     * @param {Array.<Function>} postLinkFns
5868     * @param {Object} previousCompileContext Context used for previous compilation of the current
5869     *                                        node
5870     * @returns linkFn
5871     */
5872    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
5873                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
5874                                   previousCompileContext) {
5875      previousCompileContext = previousCompileContext || {};
5876
5877      var terminalPriority = -Number.MAX_VALUE,
5878          newScopeDirective,
5879          controllerDirectives = previousCompileContext.controllerDirectives,
5880          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
5881          templateDirective = previousCompileContext.templateDirective,
5882          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
5883          hasTranscludeDirective = false,
5884          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
5885          $compileNode = templateAttrs.$$element = jqLite(compileNode),
5886          directive,
5887          directiveName,
5888          $template,
5889          replaceDirective = originalReplaceDirective,
5890          childTranscludeFn = transcludeFn,
5891          linkFn,
5892          directiveValue;
5893
5894      // executes all directives on the current element
5895      for(var i = 0, ii = directives.length; i < ii; i++) {
5896        directive = directives[i];
5897        var attrStart = directive.$$start;
5898        var attrEnd = directive.$$end;
5899
5900        // collect multiblock sections
5901        if (attrStart) {
5902          $compileNode = groupScan(compileNode, attrStart, attrEnd);
5903        }
5904        $template = undefined;
5905
5906        if (terminalPriority > directive.priority) {
5907          break; // prevent further processing of directives
5908        }
5909
5910        if (directiveValue = directive.scope) {
5911          newScopeDirective = newScopeDirective || directive;
5912
5913          // skip the check for directives with async templates, we'll check the derived sync
5914          // directive when the template arrives
5915          if (!directive.templateUrl) {
5916            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
5917                              $compileNode);
5918            if (isObject(directiveValue)) {
5919              newIsolateScopeDirective = directive;
5920            }
5921          }
5922        }
5923
5924        directiveName = directive.name;
5925
5926        if (!directive.templateUrl && directive.controller) {
5927          directiveValue = directive.controller;
5928          controllerDirectives = controllerDirectives || {};
5929          assertNoDuplicate("'" + directiveName + "' controller",
5930              controllerDirectives[directiveName], directive, $compileNode);
5931          controllerDirectives[directiveName] = directive;
5932        }
5933
5934        if (directiveValue = directive.transclude) {
5935          hasTranscludeDirective = true;
5936
5937          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
5938          // This option should only be used by directives that know how to safely handle element transclusion,
5939          // where the transcluded nodes are added or replaced after linking.
5940          if (!directive.$$tlb) {
5941            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
5942            nonTlbTranscludeDirective = directive;
5943          }
5944
5945          if (directiveValue == 'element') {
5946            hasElementTranscludeDirective = true;
5947            terminalPriority = directive.priority;
5948            $template = groupScan(compileNode, attrStart, attrEnd);
5949            $compileNode = templateAttrs.$$element =
5950                jqLite(document.createComment(' ' + directiveName + ': ' +
5951                                              templateAttrs[directiveName] + ' '));
5952            compileNode = $compileNode[0];
5953            replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
5954
5955            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
5956                                        replaceDirective && replaceDirective.name, {
5957                                          // Don't pass in:
5958                                          // - controllerDirectives - otherwise we'll create duplicates controllers
5959                                          // - newIsolateScopeDirective or templateDirective - comb
5959ining templates with
5960                                          //   element transclusion doesn't make sense.
5961                                          //
5962                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
5963                                          // on the same element more than once.
5964                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
5965                                        });
5966          } else {
5967            $template = jqLite(jqLiteClone(compileNode)).contents();
5968            $compileNode.empty(); // clear contents
5969            childTranscludeFn = compile($template, transcludeFn);
5970          }
5971        }
5972
5973        if (directive.template) {
5974          assertNoDuplicate('template', templateDirective, directive, $compileNode);
5975          templateDirective = directive;
5976
5977          directiveValue = (isFunction(directive.template))
5978              ? directive.template($compileNode, templateAttrs)
5979              : directive.template;
5980
5981          directiveValue = denormalizeTemplate(directiveValue);
5982
5983          if (directive.replace) {
5984            replaceDirective = directive;
5985            $template = directiveTemplateContents(directiveValue);
5986            compileNode = $template[0];
5987
5988            if ($template.length != 1 || compileNode.nodeType !== 1) {
5989              throw $compileMinErr('tplrt',
5990                  "Template for directive '{0}' must have exactly one root element. {1}",
5991                  directiveName, '');
5992            }
5993
5994            replaceWith(jqCollection, $compileNode, compileNode);
5995
5996            var newTemplateAttrs = {$attr: {}};
5997
5998            // combine directives from the original node and from the template:
5999            // - take the array of directives for this element
6000            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6001            // - collect directives from the template and sort them by priority
6002            // - combine directives as: processed + template + unprocessed
6003            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6004            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6005
6006            if (newIsolateScopeDirective) {
6007              markDirectivesAsIsolate(templateDirectives);
6008            }
6009            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6010            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6011
6012            ii = directives.length;
6013          } else {
6014            $compileNode.html(directiveValue);
6015          }
6016        }
6017
6018        if (directive.templateUrl) {
6019          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6020          templateDirective = directive;
6021
6022          if (directive.replace) {
6023            replaceDirective = directive;
6024          }
6025
6026          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6027              templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
6028                controllerDirectives: controllerDirectives,
6029                newIsolateScopeDirective: newIsolateScopeDirective,
6030                templateDirective: templateDirective,
6031                nonTlbTranscludeDirective: nonTlbTranscludeDirective
6032              });
6033          ii = directives.length;
6034        } else if (directive.compile) {
6035          try {
6036            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6037            if (isFunction(linkFn)) {
6038              addLinkFns(null, linkFn, attrStart, attrEnd);
6039            } else if (linkFn) {
6040              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6041            }
6042          } catch (e) {
6043            $exceptionHandler(e, startingTag($compileNode));
6044          }
6045        }
6046
6047        if (directive.terminal) {
6048          nodeLinkFn.terminal = true;
6049          terminalPriority = Math.max(terminalPriority, directive.priority);
6050        }
6051
6052      }
6053
6054      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6055      nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6056      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6057
6058      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6059      return nodeLinkFn;
6060
6061      ////////////////////
6062
6063      function addLinkFns(pre, post, attrStart, attrEnd) {
6064        if (pre) {
6065          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6066          pre.require = directive.require;
6067          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6068            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6069          }
6070          preLinkFns.push(pre);
6071        }
6072        if (post) {
6073          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6074          post.require = directive.require;
6075          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6076            post = cloneAndAnnotateFn(post, {isolateScope: true});
6077          }
6078          postLinkFns.push(post);
6079        }
6080      }
6081
6082
6083      function getControllers(require, $element, elementControllers) {
6084        var value, retrievalMethod = 'data', optional = false;
6085        if (isString(require)) {
6086          while((value = require.charAt(0)) == '^' || value == '?') {
6087            require = require.substr(1);
6088            if (value == '^') {
6089              retrievalMethod = 'inheritedData';
6090            }
6091            optional = optional || value == '?';
6092          }
6093          value = null;
6094
6095          if (elementControllers && retrievalMethod === 'data') {
6096            value = elementControllers[require];
6097          }
6098          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6099
6100          if (!value && !optional) {
6101            throw $compileMinErr('ctreq',
6102                "Controller '{0}', required by directive '{1}', can't be found!",
6103                require, directiveName);
6104          }
6105          return value;
6106        } else if (isArray(require)) {
6107          value = [];
6108          forEach(require, function(require) {
6109            value.push(getControllers(require, $element, elementControllers));
6110          });
6111        }
6112        return value;
6113      }
6114
6115
6116      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6117        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6118
6119        if (compileNode === linkNode) {
6120          attrs = templateAttrs;
6121        } else {
6122          attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6123        }
6124        $element = attrs.$$element;
6125
6126        if (newIsolateScopeDirective) {
6127          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6128          var $linkNode = jqLite(linkNode);
6129
6130          isolateScope = scope.$new(true);
6131
6132          if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6133            $linkNode.data('$isolateScope', isolateScope) ;
6134          } else {
6135            $linkNode.data('$isolateScopeNoTemplate', isolateScope);
6136          }
6137
6138
6139
6140          safeAddClass($linkNode, 'ng-isolate-scope');
6141
6142          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6143            var match = definition.match(LOCAL_REGEXP) || [],
6144                attrName = match[3] || scopeName,
6145                optional = (match[2] == '?'),
6146                mode = match[1], // @, =, or &
6147                lastValue,
6148                parentGet, parentSet, compare;
6149
6150            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6151
6152            switch (mode) {
6153
6154              case '@':
6155                attrs.$observe(attrName, function(value) {
6156                  isolateScope[scopeName] = value;
6157                });
6158                attrs.$$observers[attrName].$$scope = scope;
6159                if( attrs[attrName] ) {
6160                  // If the attribute has been provided then we trigger an interpolation to ensure
6161                  // the value is there for use in the link fn
6162                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6163                }
6164                break;
6165
6166              case '=':
6167                if (optional && !attrs[attrName]) {
6168                  return;
6169                }
6170                parentGet = $parse(attrs[attrName]);
6171                if (parentGet.literal) {
6172                  compare = equals;
6173                } else {
6174                  compare = function(a,b) { return a === b; };
6175                }
6176                parentSet = parentGet.assign || function() {
6177                  // reset the change, or we will throw this exception on every $digest
6178                  lastValue = isolateScope[scopeName] = parentGet(scope);
6179                  throw $compileMinErr('nonassign',
6180                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6181                      attrs[attrName], newIsolateScopeDirective.name);
6182                };
6183                lastValue = isolateScope[scopeName] = parentGet(scope);
6184                isolateScope.$watch(function parentValueWatch() {
6185                  var parentValue = parentGet(scope);
6186                  if (!compare(parentValue, isolateScope[scopeName])) {
6187                    // we are out of sync and need to copy
6188                    if (!compare(parentValue, lastValue)) {
6189                      // parent changed and it has precedence
6190                      isolateScope[scopeName] = parentValue;
6191                    } else {
6192                      // if the parent can be assigned then do so
6193                      parentSet(scope, parentValue = isolateScope[scopeName]);
6194                    }
6195                  }
6196                  return lastValue = parentValue;
6197                }, null, parentGet.literal);
6198                break;
6199
6200              case '&':
6201                parentGet = $parse(attrs[attrName]);
6202                isolateScope[scopeName] = function(locals) {
6203                  return parentGet(scope, locals);
6204                };
6205                break;
6206
6207              default:
6208                throw $compileMinErr('iscp',
6209                    "Invalid isolate scope definition for directive '{0}'." +
6210                    " Definition: {... {1}: '{2}' ...}",
6211                    newIsolateScopeDirective.name, scopeName, definition);
6212            }
6213          });
6214        }
6215        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6216        if (controllerDirectives) {
6217          forEach(controllerDirectives, function(directive) {
6218            var locals = {
6219              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6220              $element: $element,
6221              $attrs: attrs,
6222              $transclude: transcludeFn
6223            }, controllerInstance;
6224
6225            controller = directive.controller;
6226            if (controller == '@') {
6227              controller = attrs[directive.name];
6228            }
6229
6230            controllerInstance = $controller(controller, locals);
6231            // For directives with element transclusion the element is a comment,
6232            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6233            // clean up (http://bugs.jquery.com/ticket/8335).
6234            // Instead, we save the controllers for the element in a local hash and attach to .data
6235            // later, once we have the actual element.
6236            elementControllers[directive.name] = controllerInstance;
6237            if (!hasElementTranscludeDirective) {
6238              $element.data('$' + directive.name + 'Controller', controllerInstance);
6239            }
6240
6241            if (directive.controllerAs) {
6242              locals.$scope[directive.controllerAs] = controllerInstance;
6243            }
6244          });
6245        }
6246
6247        // PRELINKING
6248        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6249          try {
6250            linkFn = preLinkFns[i];
6251            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6252                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6253          } catch (e) {
6254            $exceptionHandler(e, startingTag($element));
6255          }
6256        }
6257
6258        // RECURSION
6259        // We only pass the isolate scope, if the isolate directive has a template,
6260        // otherwise the child elements do not belong to the isolate directive.
6261        var scopeToChild = scope;
6262        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6263          scopeToChild = isolateScope;
6264        }
6265        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6266
6267        // POSTLINKING
6268        for(i = postLinkFns.length - 1; i >= 0; i--) {
6269          try {
6270            linkFn = postLinkFns[i];
6271            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6272                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6273          } catch (e) {
6274            $exceptionHandler(e, startingTag($element));
6275          }
6276        }
6277
6278        // This is the function that is injected as `$transclude`.
6279        function controllersBoundTransclude(scope, cloneAttachFn) {
6280          var transcludeControllers;
6281
6282          // no scope passed
6283          if (arguments.length < 2) {
6284            cloneAttachFn = scope;
6285            scope = undefined;
6286          }
6287
6288          if (hasElementTranscludeDirective) {
6289            transcludeControllers = elementControllers;
6290          }
6291
6292          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6293        }
6294      }
6295    }
6296
6297    function markDirectivesAsIsolate(directives) {
6298      // mark all directives as needing isolate scope.
6299      for (var j = 0, jj = directives.length; j < jj; j++) {
6300        directives[j] = inherit(directives[j], {$$isolateScope: true});
6301      }
6302    }
6303
6304    /**
6305     * looks up the directive and decorates it with exception handling and proper parameters. We
6306     * call this the boundDirective.
6307     *
6308     * @param {string} name name of the directive to look up.
6309     * @param {string} location The directive must be found in specific format.
6310     *   String containing any of theses characters:
6311     *
6312     *   * `E`: element name
6313     *   * `A': attribute
6314     *   * `C`: class
6315     *   * `M`: comment
6316     * @returns true if directive was added.
6317     */
6318    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6319                          endAttrName) {
6320      if (name === ignoreDirective) return null;
6321      var match = null;
6322      if (hasDirectives.hasOwnProperty(name)) {
6323        for(var directive, directives = $injector.get(name + Suffix),
6324            i = 0, ii = directives.length; i<ii; i++) {
6325          try {
6326            directive = directives[i];
6327            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6328                 directive.restrict.indexOf(location) != -1) {
6329              if (startAttrName) {
6330                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6331              }
6332              tDirectives.push(directive);
6333              match = directive;
6334            }
6335          } catch(e) { $exceptionHandler(e); }
6336        }
6337      }
6338      return match;
6339    }
6340
6341
6342    /**
6343     * When the element is replaced with HTML template then the new attributes
6344     * on the template need to be merged with the existing attributes in the DOM.
6345     * The desired effect is to have both of the attributes present.
6346     *
6347     * @param {object} dst destination attributes (original DOM)
6348     * @param {object} src source attributes (from the directive template)
6349     */
6350    function mergeTemplateAttributes(dst, src) {
6351      var srcAttr = src.$attr,
6352          dstAttr = dst.$attr,
6353          $element = dst.$$element;
6354
6355      // reapply the old attributes to the new element
6356      forEach(dst, function(value, key) {
6357        if (key.charAt(0) != '$') {
6358          if (src[key]) {
6359            value += (key === 'style' ? ';' : ' ') + src[key];
6360          }
6361          dst.$set(key, value, true, srcAttr[key]);
6362        }
6363      });
6364
6365      // copy the new attributes on the old attrs object
6366      forEach(src, function(value, key) {
6367        if (key == 'class') {
6368          safeAddClass($element, value);
6369          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6370        } else if (key == 'style') {
6371          $element.attr('style', $element.attr('style') + ';' + value);
6372          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6373          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6374          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6375          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6376        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6377          dst[key] = value;
6378          dstAttr[key] = srcAttr[key];
6379        }
6380      });
6381    }
6382
6383
6384    function directiveTemplateContents(template) {
6385      var type;
6386      template = trim(template);
6387      if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
6388        type = type[1].toLowerCase();
6389        var table = jqLite('<table>' + template + '</table>'),
6390            tbody = table.children('tbody'),
6391            leaf = /(td|th)/.test(type) && table.find('tr');
6392        if (tbody.length && type !== 'tbody') {
6393          table = tbody;
6394        }
6395        if (leaf && leaf.length) {
6396          table = leaf;
6397        }
6398        return table.contents();
6399      }
6400      return jqLite('<div>' +
6401                      template +
6402                    '</div>').contents();
6403    }
6404
6405
6406    function compileTemplateUrl(directives, $compileNode, tAttrs,
6407        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6408      var linkQueue = [],
6409          afterTemplateNodeLinkFn,
6410          afterTemplateChildLinkFn,
6411          beforeTemplateCompileNode = $compileNode[0],
6412          origAsyncDirective = directives.shift(),
6413          // The fact that we have to copy and patch the directive seems wrong!
6414          derivedSyncDirective = extend({}, origAsyncDirective, {
6415            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6416          }),
6417          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6418              ? origAsyncDirective.templateUrl($compileNode, tAttrs
6418)
6419              : origAsyncDirective.templateUrl;
6420
6421      $compileNode.empty();
6422
6423      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6424        success(function(content) {
6425          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6426
6427          content = denormalizeTemplate(content);
6428
6429          if (origAsyncDirective.replace) {
6430            $template = directiveTemplateContents(content);
6431            compileNode = $template[0];
6432
6433            if ($template.length != 1 || compileNode.nodeType !== 1) {
6434              throw $compileMinErr('tplrt',
6435                  "Template for directive '{0}' must have exactly one root element. {1}",
6436                  origAsyncDirective.name, templateUrl);
6437            }
6438
6439            tempTemplateAttrs = {$attr: {}};
6440            replaceWith($rootElement, $compileNode, compileNode);
6441            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6442
6443            if (isObject(origAsyncDirective.scope)) {
6444              markDirectivesAsIsolate(templateDirectives);
6445            }
6446            directives = templateDirectives.concat(directives);
6447            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6448          } else {
6449            compileNode = beforeTemplateCompileNode;
6450            $compileNode.html(content);
6451          }
6452
6453          directives.unshift(derivedSyncDirective);
6454
6455          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6456              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6457              previousCompileContext);
6458          forEach($rootElement, function(node, i) {
6459            if (node == compileNode) {
6460              $rootElement[i] = $compileNode[0];
6461            }
6462          });
6463          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6464
6465
6466          while(linkQueue.length) {
6467            var scope = linkQueue.shift(),
6468                beforeTemplateLinkNode = linkQueue.shift(),
6469                linkRootElement = linkQueue.shift(),
6470                boundTranscludeFn = linkQueue.shift(),
6471                linkNode = $compileNode[0];
6472
6473            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6474              var oldClasses = beforeTemplateLinkNode.className;
6475
6476              if (!(previousCompileContext.hasElementTranscludeDirective &&
6477                  origAsyncDirective.replace)) {
6478                // it was cloned therefore we have to clone as well.
6479                linkNode = jqLiteClone(compileNode);
6480              }
6481
6482              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6483
6484              // Copy in CSS classes from original node
6485              safeAddClass(jqLite(linkNode), oldClasses);
6486            }
6487            if (afterTemplateNodeLinkFn.transclude) {
6488              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6489            } else {
6490              childBoundTranscludeFn = boundTranscludeFn;
6491            }
6492            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6493              childBoundTranscludeFn);
6494          }
6495          linkQueue = null;
6496        }).
6497        error(function(response, code, headers, config) {
6498          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6499        });
6500
6501      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6502        if (linkQueue) {
6503          linkQueue.push(scope);
6504          linkQueue.push(node);
6505          linkQueue.push(rootElement);
6506          linkQueue.push(boundTranscludeFn);
6507        } else {
6508          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6509        }
6510      };
6511    }
6512
6513
6514    /**
6515     * Sorting function for bound directives.
6516     */
6517    function byPriority(a, b) {
6518      var diff = b.priority - a.priority;
6519      if (diff !== 0) return diff;
6520      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6521      return a.index - b.index;
6522    }
6523
6524
6525    function assertNoDuplicate(what, previousDirective, directive, element) {
6526      if (previousDirective) {
6527        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6528            previousDirective.name, directive.name, what, startingTag(element));
6529      }
6530    }
6531
6532
6533    function addTextInterpolateDirective(directives, text) {
6534      var interpolateFn = $interpolate(text, true);
6535      if (interpolateFn) {
6536        directives.push({
6537          priority: 0,
6538          compile: valueFn(function textInterpolateLinkFn(scope, node) {
6539            var parent = node.parent(),
6540                bindings = parent.data('$binding') || [];
6541            bindings.push(interpolateFn);
6542            safeAddClass(parent.data('$binding', bindings), 'ng-binding');
6543            scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6544              node[0].nodeValue = value;
6545            });
6546          })
6547        });
6548      }
6549    }
6550
6551
6552    function getTrustedContext(node, attrNormalizedName) {
6553      if (attrNormalizedName == "srcdoc") {
6554        return $sce.HTML;
6555      }
6556      var tag = nodeName_(node);
6557      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6558      if (attrNormalizedName == "xlinkHref" ||
6559          (tag == "FORM" && attrNormalizedName == "action") ||
6560          (tag != "IMG" && (attrNormalizedName == "src" ||
6561                            attrNormalizedName == "ngSrc"))) {
6562        return $sce.RESOURCE_URL;
6563      }
6564    }
6565
6566
6567    function addAttrInterpolateDirective(node, directives, value, name) {
6568      var interpolateFn = $interpolate(value, true);
6569
6570      // no interpolation found -> ignore
6571      if (!interpolateFn) return;
6572
6573
6574      if (name === "multiple" && nodeName_(node) === "SELECT") {
6575        throw $compileMinErr("selmulti",
6576            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6577            startingTag(node));
6578      }
6579
6580      directives.push({
6581        priority: 100,
6582        compile: function() {
6583            return {
6584              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6585                var $$observers = (attr.$$observers || (attr.$$observers = {}));
6586
6587                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
6588                  throw $compileMinErr('nodomevents',
6589                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
6590                          "ng- versions (such as ng-click instead of onclick) instead.");
6591                }
6592
6593                // we need to interpolate again, in case the attribute value has been updated
6594                // (e.g. by another directive's compile function)
6595                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
6596
6597                // if attribute was updated so that there is no interpolation going on we don't want to
6598                // register any observers
6599                if (!interpolateFn) return;
6600
6601                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
6602                // actual attr value
6603                attr[name] = interpolateFn(scope);
6604                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6605                (attr.$$observers && attr.$$observers[name].$$scope || scope).
6606                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6607                    //special case for class attribute addition + removal
6608                    //so that class changes can tap into the animation
6609                    //hooks provided by the $animate service. Be sure to
6610                    //skip animations when the first digest occurs (when
6611                    //both the new and the old values are the same) since
6612                    //the CSS classes are the non-interpolated values
6613                    if(name === 'class' && newValue != oldValue) {
6614                      attr.$updateClass(newValue, oldValue);
6615                    } else {
6616                      attr.$set(name, newValue);
6617                    }
6618                  });
6619              }
6620            };
6621          }
6622      });
6623    }
6624
6625
6626    /**
6627     * This is a special jqLite.replaceWith, which can replace items which
6628     * have no parents, provided that the containing jqLite collection is provided.
6629     *
6630     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
6631     *                               in the root of the tree.
6632     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
6633     *                                  the shell, but replace its DOM node reference.
6634     * @param {Node} newNode The new DOM node.
6635     */
6636    function replaceWith($rootElement, elementsToRemove, newNode) {
6637      var firstElementToRemove = elementsToRemove[0],
6638          removeCount = elementsToRemove.length,
6639          parent = firstElementToRemove.parentNode,
6640          i, ii;
6641
6642      if ($rootElement) {
6643        for(i = 0, ii = $rootElement.length; i < ii; i++) {
6644          if ($rootElement[i] == firstElementToRemove) {
6645            $rootElement[i++] = newNode;
6646            for (var j = i, j2 = j + removeCount - 1,
6647                     jj = $rootElement.length;
6648                 j < jj; j++, j2++) {
6649              if (j2 < jj) {
6650                $rootElement[j] = $rootElement[j2];
6651              } else {
6652                delete $rootElement[j];
6653              }
6654            }
6655            $rootElement.length -= removeCount - 1;
6656            break;
6657          }
6658        }
6659      }
6660
6661      if (parent) {
6662        parent.replaceChild(newNode, firstElementToRemove);
6663      }
6664      var fragment = document.createDocumentFragment();
6665      fragment.appendChild(firstElementToRemove);
6666      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
6667      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
6668        var element = elementsToRemove[k];
6669        jqLite(element).remove(); // must do this way to clean up expando
6670        fragment.appendChild(element);
6671        delete elementsToRemove[k];
6672      }
6673
6674      elementsToRemove[0] = newNode;
6675      elementsToRemove.length = 1;
6676    }
6677
6678
6679    function cloneAndAnnotateFn(fn, annotation) {
6680      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
6681    }
6682  }];
6683}
6684
6685var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
6686/**
6687 * Converts all accepted directives format into proper directive name.
6688 * All of these will become 'myDirective':
6689 *   my:Directive
6690 *   my-directive
6691 *   x-my-directive
6692 *   data-my:directive
6693 *
6694 * Also there is special case for Moz prefix starting with upper case letter.
6695 * @param name Name to normalize
6696 */
6697function directiveNormalize(name) {
6698  return camelCase(name.replace(PREFIX_REGEXP, ''));
6699}
6700
6701/**
6702 * @ngdoc object
6703 * @name ng.$compile.directive.Attributes
6704 *
6705 * @description
6706 * A shared object between directive compile / linking functions which contains 
6706normalized DOM
6707 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
6708 * needed since all of these are treated as equivalent in Angular:
6709 *
6710 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
6711 */
6712
6713/**
6714 * @ngdoc property
6715 * @name ng.$compile.directive.Attributes#$attr
6716 * @propertyOf ng.$compile.directive.Attributes
6717 * @returns {object} A map of DOM element attribute names to the normalized name. This is
6718 *                   needed to do reverse lookup from normalized name back to actual name.
6719 */
6720
6721
6722/**
6723 * @ngdoc function
6724 * @name ng.$compile.directive.Attributes#$set
6725 * @methodOf ng.$compile.directive.Attributes
6726 * @function
6727 *
6728 * @description
6729 * Set DOM element attribute value.
6730 *
6731 *
6732 * @param {string} name Normalized element attribute name of the property to modify. The name is
6733 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
6734 *          property to the original name.
6735 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
6736 */
6737
6738
6739
6740/**
6741 * Closure compiler type information
6742 */
6743
6744function nodesetLinkingFn(
6745  /* angular.Scope */ scope,
6746  /* NodeList */ nodeList,
6747  /* Element */ rootElement,
6748  /* function(Function) */ boundTranscludeFn
6749){}
6750
6751function directiveLinkingFn(
6752  /* nodesetLinkingFn */ nodesetLinkingFn,
6753  /* angular.Scope */ scope,
6754  /* Node */ node,
6755  /* Element */ rootElement,
6756  /* function(Function) */ boundTranscludeFn
6757){}
6758
6759function tokenDifference(str1, str2) {
6760  var values = '',
6761      tokens1 = str1.split(/\s+/),
6762      tokens2 = str2.split(/\s+/);
6763
6764  outer:
6765  for(var i = 0; i < tokens1.length; i++) {
6766    var token = tokens1[i];
6767    for(var j = 0; j < tokens2.length; j++) {
6768      if(token == tokens2[j]) continue outer;
6769    }
6770    values += (values.length > 0 ? ' ' : '') + token;
6771  }
6772  return values;
6773}
6774
6775/**
6776 * @ngdoc object
6777 * @name ng.$controllerProvider
6778 * @description
6779 * The {@link ng.$controller $controller service} is used by Angular to create new
6780 * controllers.
6781 *
6782 * This provider allows controller registration via the
6783 * {@link ng.$controllerProvider#methods_register register} method.
6784 */
6785function $ControllerProvider() {
6786  var controllers = {},
6787      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
6788
6789
6790  /**
6791   * @ngdoc function
6792   * @name ng.$controllerProvider#register
6793   * @methodOf ng.$controllerProvider
6794   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
6795   *    the names and the values are the constructors.
6796   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
6797   *    annotations in the array notation).
6798   */
6799  this.register = function(name, constructor) {
6800    assertNotHasOwnProperty(name, 'controller');
6801    if (isObject(name)) {
6802      extend(controllers, name);
6803    } else {
6804      controllers[name] = constructor;
6805    }
6806  };
6807
6808
6809  this.$get = ['$injector', '$window', function($injector, $window) {
6810
6811    /**
6812     * @ngdoc function
6813     * @name ng.$controller
6814     * @requires $injector
6815     *
6816     * @param {Function|string} constructor If called with a function then it's considered to be the
6817     *    controller constructor function. Otherwise it's considered to be a string which is used
6818     *    to retrieve the controller constructor using the following steps:
6819     *
6820     *    * check if a controller with given name is registered via `$controllerProvider`
6821     *    * check if evaluating the string on the current scope returns a constructor
6822     *    * check `window[constructor]` on the global `window` object
6823     *
6824     * @param {Object} locals Injection locals for Controller.
6825     * @return {Object} Instance of given controller.
6826     *
6827     * @description
6828     * `$controller` service is responsible for instantiating controllers.
6829     *
6830     * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
6831     * a service, so that one can override this service with {@link https://gist.github.com/1649788
6832     * BC version}.
6833     */
6834    return function(expression, locals) {
6835      var instance, match, constructor, identifier;
6836
6837      if(isString(expression)) {
6838        match = expression.match(CNTRL_REG),
6839        constructor = match[1],
6840        identifier = match[3];
6841        expression = controllers.hasOwnProperty(constructor)
6842            ? controllers[constructor]
6843            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
6844
6845        assertArgFn(expression, constructor, true);
6846      }
6847
6848      instance = $injector.instantiate(expression, locals);
6849
6850      if (identifier) {
6851        if (!(locals && typeof locals.$scope == 'object')) {
6852          throw minErr('$controller')('noscp',
6853              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
6854              constructor || expression.name, identifier);
6855        }
6856
6857        locals.$scope[identifier] = instance;
6858      }
6859
6860      return instance;
6861    };
6862  }];
6863}
6864
6865/**
6866 * @ngdoc object
6867 * @name ng.$document
6868 * @requires $window
6869 *
6870 * @description
6871 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
6872 */
6873function $DocumentProvider(){
6874  this.$get = ['$window', function(window){
6875    return jqLite(window.document);
6876  }];
6877}
6878
6879/**
6880 * @ngdoc function
6881 * @name ng.$exceptionHandler
6882 * @requires $log
6883 *
6884 * @description
6885 * Any uncaught exception in angular expressions is delegated to this service.
6886 * The default implementation simply delegates to `$log.error` which logs it into
6887 * the browser console.
6888 * 
6889 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
6890 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
6891 *
6892 * ## Example:
6893 * 
6894 * <pre>
6895 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
6896 *     return function (exception, cause) {
6897 *       exception.message += ' (caused by "' + cause + '")';
6898 *       throw exception;
6899 *     };
6900 *   });
6901 * </pre>
6902 * 
6903 * This example will override the normal action of `$exceptionHandler`, to make angular
6904 * exceptions fail hard when they happen, instead of just logging to the console.
6905 *
6906 * @param {Error} exception Exception associated with the error.
6907 * @param {string=} cause optional information about the context in which
6908 *       the error was thrown.
6909 *
6910 */
6911function $ExceptionHandlerProvider() {
6912  this.$get = ['$log', function($log) {
6913    return function(exception, cause) {
6914      $log.error.apply($log, arguments);
6915    };
6916  }];
6917}
6918
6919/**
6920 * Parse headers into key value object
6921 *
6922 * @param {string} headers Raw headers as a string
6923 * @returns {Object} Parsed headers as key value object
6924 */
6925function parseHeaders(headers) {
6926  var parsed = {}, key, val, i;
6927
6928  if (!headers) return parsed;
6929
6930  forEach(headers.split('\n'), function(line) {
6931    i = line.indexOf(':');
6932    key = lowercase(trim(line.substr(0, i)));
6933    val = trim(line.substr(i + 1));
6934
6935    if (key) {
6936      if (parsed[key]) {
6937        parsed[key] += ', ' + val;
6938      } else {
6939        parsed[key] = val;
6940      }
6941    }
6942  });
6943
6944  return parsed;
6945}
6946
6947
6948/**
6949 * Returns a function that provides access to parsed headers.
6950 *
6951 * Headers are lazy parsed when first requested.
6952 * @see parseHeaders
6953 *
6954 * @param {(string|Object)} headers Headers to provide access to.
6955 * @returns {function(string=)} Returns a getter function which if called with:
6956 *
6957 *   - if called with single an argument returns a single header value or null
6958 *   - if called with no arguments returns an object containing all headers.
6959 */
6960function headersGetter(headers) {
6961  var headersObj = isObject(headers) ? headers : undefined;
6962
6963  return function(name) {
6964    if (!headersObj) headersObj =  parseHeaders(headers);
6965
6966    if (name) {
6967      return headersObj[lowercase(name)] || null;
6968    }
6969
6970    return headersObj;
6971  };
6972}
6973
6974
6975/**
6976 * Chain all given functions
6977 *
6978 * This function is used for both request and response transforming
6979 *
6980 * @param {*} data Data to transform.
6981 * @param {function(string=)} headers Http headers getter fn.
6982 * @param {(function|Array.<function>)} fns Function or an array of functions.
6983 * @returns {*} Transformed data.
6984 */
6985function transformData(data, headers, fns) {
6986  if (isFunction(fns))
6987    return fns(data, headers);
6988
6989  forEach(fns, function(fn) {
6990    data = fn(data, headers);
6991  });
6992
6993  return data;
6994}
6995
6996
6997function isSuccess(status) {
6998  return 200 <= status && status < 300;
6999}
7000
7001
7002function $HttpProvider() {
7003  var JSON_START = /^\s*(\[|\{[^\{])/,
7004      JSON_END = /[\}\]]\s*$/,
7005      PROTECTION_PREFIX = /^\)\]\}',?\n/,
7006      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7007
7008  var defaults = this.defaults = {
7009    // transform incoming response data
7010    transformResponse: [function(data) {
7011      if (isString(data)) {
7012        // strip json vulnerability protection prefix
7013        data = data.replace(PROTECTION_PREFIX, '');
7014        if (JSON_START.test(data) && JSON_END.test(data))
7015          data = fromJson(data);
7016      }
7017      return data;
7018    }],
7019
7020    // transform outgoing request data
7021    transformRequest: [function(d) {
7022      return isObject(d) && !isFile(d) ? toJson(d) : d;
7023    }],
7024
7025    // default headers
7026    headers: {
7027      common: {
7028        'Accept': 'application/json, text/plain, */*'
7029      },
7030      post:   copy(CONTENT_TYPE_APPLICATION_JSON),
7031      put:    copy(CONTENT_TYPE_APPLICATION_JSON),
7032      patch:  copy(CONTENT_TYPE_APPLICATION_JSON)
7033    },
7034
7035    xsrfCookieName: 'XSRF-TOKEN',
7036    xsrfHeaderName: 'X-XSRF-TOKEN'
7037  };
7038
7039  /**
7040   * Are ordered by request, i.e. they are applied in the same order as the
7041   * array, on request, but reverse order, on response.
7042   */
7043  var interceptorFactories = this.interceptors = [];
7044
7045  /**
7046   * For historical reasons, response interceptors are ordered by the order in which
7047   * they are applied to the response. (This is the opposite of interceptorFactories)
7048   */
7049  var responseInterceptorFactories = this.responseInterceptors = [];
7050
7051  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7052      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7053
7054    var defaultCache = $cacheFactory('$http');
7055
7056    /**
7057     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7058     * The reversal is needed so that we can build up the interception chain around the
7059     * server request.
7060     */
7061    var reversedInterceptors = [];
7062
7063    forEach(interceptorFactories, function(interceptorFactory) {
7064      reversedInterceptors.unshift(isString(interceptorFactory)
7065          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7066    });
7067
7068    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7069      var responseFn = isString(interceptorFactory)
7070          ? $injector.get(interceptorFactory)
7071          : $injector.invoke(interceptorFactory);
7072
7073      /**
7074       * Response interceptors go before "around" interceptors (no real reason, just
7075       * had to pick one.) But they are already reversed, so we can't use unshift, hence
7076       * the splice.
7077       */
7078      reversedInterceptors.splice(index, 0, {
7079        response: function(response) {
7080          return responseFn($q.when(response));
7081        },
7082        responseError: function(response) {
7083          return responseFn($q.reject(response));
7084        }
7085      });
7086    });
7087
7088
7089    /**
7090     * @ngdoc function
7091     * @name ng.$http
7092     * @requires $httpBackend
7093     * @requires $browser
7094     * @requires $cacheFactory
7095     * @requires $rootScope
7096     * @requires $q
7097     * @requires $injector
7098     *
7099     * @description
7100     * The `$http` service is a core Angular service that facilitates communication with the remote
7101     * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
7102     * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
7103     *
7104     * For unit testing applications that use `$http` service, see
7105     * {@link ngMock.$httpBackend $httpBackend mock}.
7106     *
7107     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7108     * $resource} service.
7109     *
7110     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7111     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7112     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7113     *
7114     *
7115     * # General usage
7116     * The `$http` service is a function which takes a single argument — a configuration object —
7117     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7118     * with two $http specific methods: `success` and `error`.
7119     *
7120     * <pre>
7121     *   $http({method: 'GET', url: '/someUrl'}).
7122     *     success(function(data, status, headers, config) {
7123     *       // this callback will be called asynchronously
7124     *       // when the response is available
7125     *     }).
7126     *     error(function(data, status, headers, config) {
7127     *       // called asynchronously if an error occurs
7128     *       // or server returns response with an error status.
7129     *     });
7130     * </pre>
7131     *
7132     * Since the returned value of calling the $http function is a `promise`, you can also use
7133     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7134     * an object representing the response. See the API signature and type info below for more
7135     * details.
7136     *
7137     * A response status code between 200 and 299 is considered a success status and
7138     * will result in the success callback being called. Note that if the response is a redirect,
7139     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7140     * called for such responses.
7141     *
7142     * # Writing Unit Tests that use $http
7143     * When unit testing (using {@link api/ngMock ngMock}), it is necessary to call
7144     * {@link api/ngMock.$httpBackend#methods_flush $httpBackend.flush()} to flush each pending
7145     * request using trained responses.
7146     *
7147     * ```
7148     * $httpBackend.expectGET(...);
7149     * $http.get(...);
7150     * $httpBackend.flush();
7151     * ```
7152     *
7153     * # Shortcut methods
7154     *
7155     * Since all invocations of the $http service require passing in an HTTP method and URL, and
7156     * POST/PUT requests require request data to be provided as well, shortcut methods
7157     * were created:
7158     *
7159     * <pre>
7160     *   $http.get('/someUrl').success(successCallback);
7161     *   $http.post('/someUrl', data).success(successCallback);
7162     * </pre>
7163     *
7164     * Complete list of shortcut methods:
7165     *
7166     * - {@link ng.$http#methods_get $http.get}
7167     * - {@link ng.$http#methods_head $http.head}
7168     * - {@link ng.$http#methods_post $http.post}
7169     * - {@link ng.$http#methods_put $http.put}
7170     * - {@link ng.$http#methods_delete $http.delete}
7171     * - {@link ng.$http#methods_jsonp $http.jsonp}
7172     *
7173     *
7174     * # Setting HTTP Headers
7175     *
7176     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7177     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7178     * object, which currently contains this default configuration:
7179     *
7180     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7181     *   - `Accept: application/json, text/plain, * / *`
7182     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7183     *   - `Content-Type: application/json`
7184     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7185     *   - `Content-Type: application/json`
7186     *
7187     * To add or overwrite these defaults, simply add or remove a property from these configuration
7188     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7189     * with the lowercased HTTP method name as the key, e.g.
7190     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7191     *
7192     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7193     * fashion. For example:
7194     *
7195     * ```
7196     * module.run(function($http) {
7197     *   $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
7198     * });
7199     * ```
7200     *
7201     * In addition, you can supply a `headers` property in the config object passed when
7202     * calling `$http(config)`, which overrides the defaults without changing them globally.
7203     *
7204     *
7205     * # Transforming Requests and Responses
7206     *
7207     * Both requests and responses can be transformed using transform functions. By default, Angular
7208     * applies these transformations:
7209     *
7210     * Request transformations:
7211     *
7212     * - If the `data` property of the request configuration object contains an object, serialize it
7213     *   into JSON format.
7214     *
7215     * Response transformations:
7216     *
7217     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7218     *  - If JSON response is detected, deserialize it using a JSON parser.
7219     *
7220     * To globally augment or override the default transforms, modify the
7221     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7222     * properties. These properties are by default an array of transform functions, which allows you
7223     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7224     * also decide to completely override any default transformations by assigning your
7225     * transformation functions to these properties directly without the array wrapper.  These defaults
7226     * are again available on the $http factory at run-time, which may be useful if you have run-time
7227     * services you wish to be involved in your transformations.
7228     *
7229     * Similarly, to locally override the request/response transforms, augment the
7230     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7231     * into `$http`.
7232     *
7233     *
7234     * # Caching
7235     *
7236     * To enable caching, set the request configuration `cache` property to `true` (to use default
7237     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7238     * When the cache is enabled, `$http` stores the response from the server in the specified
7239     * cache. The next time the same request is made, the response is served from the cache without
7240     * sending a request to the server.
7241     *
7242     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7243     * the same way that real requests are.
7244     *
7245     * If there are multiple GET requests for the same URL that should be cached using the same
7246     * cache, but the cache is not populated yet, only one request to the server will be made and
7247     * the remaining requests will be fulfilled using the response from the first request.
7248     *
7249     * You can change the default cache to a new object (built with
7250     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7251     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7252     * their `cache` property to `true` will now use this cache object.
7253     *
7254     * If you set the default cache to `false` then only requests that specify their own custom
7255     * cache object will be cached.
7256     *
7257     * # Interceptors
7258     *
7259     * Before you start creating interceptors, be sure to understand the
7260     * {@link ng.$q $q and deferred/promise APIs}.
7261     *
7262     * For purposes of global error handling, authentication, or any kind of synchronous or
7263     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7264     * able to intercept requests before they are handed to the server and
7265     * responses before they are handed over to the application code that
7266     * initiated these requests. The interceptors leverage the {@link ng.$q
7267     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7268     *
7269     * The interceptors are service factories that are registered with the `$httpProvider` by
7270     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7271     * injected with dependencies (if specified) and returns the interceptor.
7272     *
7273     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7274     *
7275     *   * `request`: interceptors get called with http `config` object. The function is free to
7276     *     modify the `config` or create a new one. The function needs to return the `config`
7277     *     directly or as a promise.
7278     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7279     *     resolved with a rejection.
7280     *   * `response`: interceptors get called with http `response` object. The function is free to
7281     *     modify the `response` or create a new one. The function needs to return the `response`
7282     *     directly or as a promise.
7283     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7284     *     resolved with a rejection.
7285     *
7286     *
7287     * <pre>
7288     *   // register the interceptor as a service
7289     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7290     *     return {
7291     *       // optional method
7292     *       'request': function(config) {
7293     *         // do something on success
7294     *         return config || $q.when(config);
7295     *       },
7296     *
7297     *       // optional method
7298     *      'requestError': function(rejection) {
7299     *         // do something on error
7300     *         if (canRecover(rejection)) {
7301     *           return responseOrNewPromise
7302     *         }
7303     *         return $q.reject(rejection);
7304     *       },
7305     *
7306     *
7307     *
7308     *       // optional method
7309     *       'response': function(response) {
7310     *         // do something on success
7311     *         return response || $q.when(response);
7312     *       },
7313     *
7314     *       // optional method
7315     *      'responseError': function(rejection) {
7316     *         // do something on error
7317     *         if (canRecover(rejection)) {
7318     *           return responseOrNewPromise
7319     *         }
7320     *         return $q.reject(rejection);
7321     *       }
7322     *     };
7323     *   });
7324     *
7325     *   $httpProvider.interceptors.push('myHttpInterceptor');
7326     *
7327     *
7328     *   // alternatively, register the interceptor via an anonymous factory
7329     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7330     *     return {
7331     *      'request': function(config) {
7332     *          // same as above
7333     *       },
7334     *
7335     *       'response': function(response) {
7336     *          // same as above
7337     *       }
7338     *     };
7339     *   });
7340     * </pre>
7341     *
7342     * # Response interceptors (DEPRECATED)
7343     *
7344     * Before you start creating interceptors, be sure to understand the
7345     * {@link ng.$q $q and deferred/promise APIs}.
7346     *
7347     * For purposes of global error handling, authentication or any kind of synchronous or
7348     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7349     * responses for http requests before they are handed over to the application code that
7350     * initiated these requests. The response interceptors leverage the {@link ng.$q
7351     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7352     *
7353     * The interceptors are service factories that are registered with the $httpProvider by
7354     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7355     * injected with dependencies (if specified) and returns the interceptor  — a function that
7356     * takes a {@link ng.$q promise} and returns the original or a new promise.
7357     *
7358     * <pre>
7359     *   // register the interceptor as a service
7360     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7361     *     return function(promise) {
7362     *       return promise.then(function(response) {
7363     *         // do something on success
7364     *         return response;
7365     *       }, function(response) {
7366     *         // do something on error
7367     *         if (canRecover(response)) {
7368     *           return responseOrNewPromise
7369     *         }
7370     *         return $q.reject(response);
7371     *       });
7372     *     }
7373     *   });
7374     *
7375     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7376     *
7377     *
7378     *   // register the interceptor via an anonymous factory
7379     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7380     *     return function(promise) {
7381     *       // same as above
7382     *     }
7383     *   });
7384     * </pre>
7385     *
7386     *
7387     * # Security Considerations
7388     *
7389     * When designing web applications, consider security threats from:
7390     *
7391     * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
7392     *   JSON vulnerability}
7393     * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
7394     *
7395     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7396     * pre-configured with strategies that address these issues, but for this to work backend server
7397     * cooperation is required.
7398     *
7399     * ## JSON Vulnerability Protection
7400     *
7401     * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
7402     * JSON vulnerability} allows third party website to turn your JSON resource URL into
7403     * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
7404     * counter this your server can prefix all JSON requests with following str
7404ing `")]}',\n"`.
7405     * Angular will automatically strip the prefix before processing it as JSON.
7406     *
7407     * For example if your server needs to return:
7408     * <pre>
7409     * ['one','two']
7410     * </pre>
7411     *
7412     * which is vulnerable to attack, your server can return:
7413     * <pre>
7414     * )]}',
7415     * ['one','two']
7416     * </pre>
7417     *
7418     * Angular will strip the prefix, before processing the JSON.
7419     *
7420     *
7421     * ## Cross Site Request Forgery (XSRF) Protection
7422     *
7423     * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
7424     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7425     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7426     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7427     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7428     * the XHR came from JavaScript running on your domain. The header will not be set for
7429     * cross-domain requests.
7430     *
7431     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7432     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7433     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7434     * that only JavaScript running on your domain could have sent the request. The token must be
7435     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7436     * making up its own tokens). We recommend that the token is a digest of your site's
7437     * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt}
7438     * for added security.
7439     *
7440     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7441     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7442     * or the per-request config object.
7443     *
7444     *
7445     * @param {object} config Object describing the request to be made and how it should be
7446     *    processed. The object has following properties:
7447     *
7448     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7449     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7450     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7451     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7452     *      JSONified.
7453     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7454     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7455     *      HTTP headers to send to the server. If the return value of a function is null, the
7456     *      header will not be sent.
7457     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7458     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7459     *    - **transformRequest** –
7460     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7461     *      transform function or an array of such functions. The transform function takes the http
7462     *      request body and headers and returns its transformed (typically serialized) version.
7463     *    - **transformResponse** –
7464     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7465     *      transform function or an array of such functions. The transform function takes the http
7466     *      response body and headers and returns its transformed (typically deserialized) version.
7467     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7468     *      GET request, otherwise if a cache instance built with
7469     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7470     *      caching.
7471     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7472     *      that should abort the request when resolved.
7473     *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
7474     *      XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
7475     *      requests with credentials} for more information.
7476     *    - **responseType** - `{string}` - see {@link
7477     *      https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
7478     *
7479     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7480     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7481     *   method takes two arguments a success and an error callback which will be called with a
7482     *   response object. The `success` and `error` methods take a single argument - a function that
7483     *   will be called when the request succeeds or fails respectively. The arguments passed into
7484     *   these functions are destructured representation of the response object passed into the
7485     *   `then` method. The response object has these properties:
7486     *
7487     *   - **data** – `{string|Object}` – The response body transformed with the transform
7488     *     functions.
7489     *   - **status** – `{number}` – HTTP status code of the response.
7490     *   - **headers** – `{function([headerName])}` – Header getter function.
7491     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7492     *
7493     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7494     *   requests. This is primarily meant to be used for debugging purposes.
7495     *
7496     *
7497     * @example
7498<example>
7499<file name="index.html">
7500  <div ng-controller="FetchCtrl">
7501    <select ng-model="method">
7502      <option>GET</option>
7503      <option>JSONP</option>
7504    </select>
7505    <input type="text" ng-model="url" size="80"/>
7506    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7507    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7508    <button id="samplejsonpbtn"
7509      ng-click="updateModel('JSONP',
7510                    'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7511      Sample JSONP
7512    </button>
7513    <button id="invalidjsonpbtn"
7514      ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7515        Invalid JSONP
7516      </button>
7517    <pre>http status code: {{status}}</pre>
7518    <pre>http response data: {{data}}</pre>
7519  </div>
7520</file>
7521<file name="script.js">
7522  function FetchCtrl($scope, $http, $templateCache) {
7523    $scope.method = 'GET';
7524    $scope.url = 'http-hello.html';
7525
7526    $scope.fetch = function() {
7527      $scope.code = null;
7528      $scope.response = null;
7529
7530      $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7531        success(function(data, status) {
7532          $scope.status = status;
7533          $scope.data = data;
7534        }).
7535        error(function(data, status) {
7536          $scope.data = data || "Request failed";
7537          $scope.status = status;
7538      });
7539    };
7540
7541    $scope.updateModel = function(method, url) {
7542      $scope.method = method;
7543      $scope.url = url;
7544    };
7545  }
7546</file>
7547<file name="http-hello.html">
7548  Hello, $http!
7549</file>
7550<file name="protractorTest.js">
7551  var status = element(by.binding('status'));
7552  var data = element(by.binding('data'));
7553  var fetchBtn = element(by.id('fetchbtn'));
7554  var sampleGetBtn = element(by.id('samplegetbtn'));
7555  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
7556  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
7557
7558  it('should make an xhr GET request', function() {
7559    sampleGetBtn.click();
7560    fetchBtn.click();
7561    expect(status.getText()).toMatch('200');
7562    expect(data.getText()).toMatch(/Hello, \$http!/)
7563  });
7564
7565  it('should make a JSONP request to angularjs.org', function() {
7566    sampleJsonpBtn.click();
7567    fetchBtn.click();
7568    expect(status.getText()).toMatch('200');
7569    expect(data.getText()).toMatch(/Super Hero!/);
7570  });
7571
7572  it('should make JSONP request to invalid URL and invoke the error handler',
7573      function() {
7574    invalidJsonpBtn.click();
7575    fetchBtn.click();
7576    expect(status.getText()).toMatch('0');
7577    expect(data.getText()).toMatch('Request failed');
7578  });
7579</file>
7580</example>
7581     */
7582    function $http(requestConfig) {
7583      var config = {
7584        transformRequest: defaults.transformRequest,
7585        transformResponse: defaults.transformResponse
7586      };
7587      var headers = mergeHeaders(requestConfig);
7588
7589      extend(config, requestConfig);
7590      config.headers = headers;
7591      config.method = uppercase(config.method);
7592
7593      var xsrfValue = urlIsSameOrigin(config.url)
7594          ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
7595          : undefined;
7596      if (xsrfValue) {
7597        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
7598      }
7599
7600
7601      var serverRequest = function(config) {
7602        headers = config.headers;
7603        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
7604
7605        // strip content-type if data is undefined
7606        if (isUndefined(config.data)) {
7607          forEach(headers, function(value, header) {
7608            if (lowercase(header) === 'content-type') {
7609                delete headers[header];
7610            }
7611          });
7612        }
7613
7614        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
7615          config.withCredentials = defaults.withCredentials;
7616        }
7617
7618        // send request
7619        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
7620      };
7621
7622      var chain = [serverRequest, undefined];
7623      var promise = $q.when(config);
7624
7625      // apply interceptors
7626      forEach(reversedInterceptors, function(interceptor) {
7627        if (interceptor.request || interceptor.requestError) {
7628          chain.unshift(interceptor.request, interceptor.requestError);
7629        }
7630        if (interceptor.response || interceptor.responseError) {
7631          chain.push(interceptor.response, interceptor.responseError);
7632        }
7633      });
7634
7635      while(chain.length) {
7636        var thenFn = chain.shift();
7637        var rejectFn = chain.shift();
7638
7639        promise = promise.then(thenFn, rejectFn);
7640      }
7641
7642      promise.success = function(fn) {
7643        promise.then(function(response) {
7644          fn(response.data, response.status, response.headers, config);
7645        });
7646        return promise;
7647      };
7648
7649      promise.error = function(fn) {
7650        promise.then(null, function(response) {
7651          fn(response.data, response.status, response.headers, config);
7652        });
7653        return promise;
7654      };
7655
7656      return promise;
7657
7658      function transformResponse(response) {
7659        // make a copy since the response must be cacheable
7660        var resp = extend({}, response, {
7661          data: transformData(response.data, response.headers, config.transformResponse)
7662        });
7663        return (isSuccess(response.status))
7664          ? resp
7665          : $q.reject(resp);
7666      }
7667
7668      function mergeHeaders(config) {
7669        var defHeaders = defaults.headers,
7670            reqHeaders = extend({}, config.headers),
7671            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
7672
7673        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
7674
7675        // execute if header value is function
7676        execHeaders(defHeaders);
7677        execHeaders(reqHeaders);
7678
7679        // using for-in instead of forEach to avoid unecessary iteration after header has been found
7680        defaultHeadersIteration:
7681        for (defHeaderName in defHeaders) {
7682          lowercaseDefHeaderName = lowercase(defHeaderName);
7683
7684          for (reqHeaderName in reqHeaders) {
7685            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
7686              continue defaultHeadersIteration;
7687            }
7688          }
7689
7690          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
7691        }
7692
7693        return reqHeaders;
7694
7695        function execHeaders(headers) {
7696          var headerContent;
7697
7698          forEach(headers, function(headerFn, header) {
7699            if (isFunction(headerFn)) {
7700              headerContent = headerFn();
7701              if (headerContent != null) {
7702                headers[header] = headerContent;
7703              } else {
7704                delete headers[header];
7705              }
7706            }
7707          });
7708        }
7709      }
7710    }
7711
7712    $http.pendingRequests = [];
7713
7714    /**
7715     * @ngdoc method
7716     * @name ng.$http#get
7717     * @methodOf ng.$http
7718     *
7719     * @description
7720     * Shortcut method to perform `GET` request.
7721     *
7722     * @param {string} url Relative or absolute URL specifying the destination of the request
7723     * @param {Object=} config Optional configuration object
7724     * @returns {HttpPromise} Future object
7725     */
7726
7727    /**
7728     * @ngdoc method
7729     * @name ng.$http#delete
7730     * @methodOf ng.$http
7731     *
7732     * @description
7733     * Shortcut method to perform `DELETE` request.
7734     *
7735     * @param {string} url Relative or absolute URL specifying the destination of the request
7736     * @param {Object=} config Optional configuration object
7737     * @returns {HttpPromise} Future object
7738     */
7739
7740    /**
7741     * @ngdoc method
7742     * @name ng.$http#head
7743     * @methodOf ng.$http
7744     *
7745     * @description
7746     * Shortcut method to perform `HEAD` request.
7747     *
7748     * @param {string} url Relative or absolute URL specifying the destination of the request
7749     * @param {Object=} config Optional configuration object
7750     * @returns {HttpPromise} Future object
7751     */
7752
7753    /**
7754     * @ngdoc method
7755     * @name ng.$http#jsonp
7756     * @methodOf ng.$http
7757     *
7758     * @description
7759     * Shortcut method to perform `JSONP` request.
7760     *
7761     * @param {string} url Relative or absolute URL specifying the destination of the request.
7762     *                     Should contain `JSON_CALLBACK` string.
7763     * @param {Object=} config Optional configuration object
7764     * @returns {HttpPromise} Future object
7765     */
7766    createShortMethods('get', 'delete', 'head', 'jsonp');
7767
7768    /**
7769     * @ngdoc method
7770     * @name ng.$http#post
7771     * @methodOf ng.$http
7772     *
7773     * @description
7774     * Shortcut method to perform `POST` request.
7775     *
7776     * @param {string} url Relative or absolute URL specifying the destination of the request
7777     * @param {*} data Request content
7778     * @param {Object=} config Optional configuration object
7779     * @returns {HttpPromise} Future object
7780     */
7781
7782    /**
7783     * @ngdoc method
7784     * @name ng.$http#put
7785     * @methodOf ng.$http
7786     *
7787     * @description
7788     * Shortcut method to perform `PUT` request.
7789     *
7790     * @param {string} url Relative or absolute URL specifying the destination of the request
7791     * @param {*} data Request content
7792     * @param {Object=} config Optional configuration object
7793     * @returns {HttpPromise} Future object
7794     */
7795    createShortMethodsWithData('post', 'put');
7796
7797        /**
7798         * @ngdoc property
7799         * @name ng.$http#defaults
7800         * @propertyOf ng.$http
7801         *
7802         * @description
7803         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
7804         * default headers, withCredentials as well as request and response transformations.
7805         *
7806         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
7807         */
7808    $http.defaults = defaults;
7809
7810
7811    return $http;
7812
7813
7814    function createShortMethods(names) {
7815      forEach(arguments, function(name) {
7816        $http[name] = function(url, config) {
7817          return $http(extend(config || {}, {
7818            method: name,
7819            url: url
7820          }));
7821        };
7822      });
7823    }
7824
7825
7826    function createShortMethodsWithData(name) {
7827      forEach(arguments, function(name) {
7828        $http[name] = function(url, data, config) {
7829          return $http(extend(config || {}, {
7830            method: name,
7831            url: url,
7832            data: data
7833          }));
7834        };
7835      });
7836    }
7837
7838
7839    /**
7840     * Makes the request.
7841     *
7842     * !!! ACCESSES CLOSURE VARS:
7843     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
7844     */
7845    function sendReq(config, reqData, reqHeaders) {
7846      var deferred = $q.defer(),
7847          promise = deferred.promise,
7848          cache,
7849          cachedResp,
7850          url = buildUrl(config.url, config.params);
7851
7852      $http.pendingRequests.push(config);
7853      promise.then(removePendingReq, removePendingReq);
7854
7855
7856      if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
7857        cache = isObject(config.cache) ? config.cache
7858              : isObject(defaults.cache) ? defaults.cache
7859              : defaultCache;
7860      }
7861
7862      if (cache) {
7863        cachedResp = cache.get(url);
7864        if (isDefined(cachedResp)) {
7865          if (cachedResp.then) {
7866            // cached request has already been sent, but there is no response yet
7867            cachedResp.then(removePendingReq, removePendingReq);
7868            return cachedResp;
7869          } else {
7870            // serving from cache
7871            if (isArray(cachedResp)) {
7872              resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
7873            } else {
7874              resolvePromise(cachedResp, 200, {});
7875            }
7876          }
7877        } else {
7878          // put the promise for the non-transformed response into cache as a placeholder
7879          cache.put(url, promise);
7880        }
7881      }
7882
7883      // if we won't have the response in cache, send the request to the backend
7884      if (isUndefined(cachedResp)) {
7885        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
7886            config.withCredentials, config.responseType);
7887      }
7888
7889      return promise;
7890
7891
7892      /**
7893       * Callback registered to $httpBackend():
7894       *  - caches the response if desired
7895       *  - resolves the raw $http promise
7896       *  - calls $apply
7897       */
7898      function done(status, response, headersString) {
7899        if (cache) {
7900          if (isSuccess(status)) {
7901            cache.put(url, [status, response, parseHeaders(headersString)]);
7902          } else {
7903            // remove promise from the cache
7904            cache.remove(url);
7905          }
7906        }
7907
7908        resolvePromise(response, status, headersString);
7909        if (!$rootScope.$$phase) $rootScope.$apply();
7910      }
7911
7912
7913      /**
7914       * Resolves the raw $http promise.
7915       */
7916      function resolvePromise(response, status, headers) {
7917        // normalize internal statuses to 0
7918        status = Math.max(status, 0);
7919
7920        (isSuccess(status) ? deferred.resolve : deferred.reject)({
7921          data: response,
7922          status: status,
7923          headers: headersGetter(headers),
7924          config: config
7925        });
7926      }
7927
7928
7929      function removePendingReq() {
7930        var idx = indexOf($http.pendingRequests, config);
7931        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
7932      }
7933    }
7934
7935
7936    function buildUrl(url, params) {
7937          if (!params) return url;
7938          var parts = [];
7939          forEachSorted(params, function(value, key) {
7940            if (value === null || isUndefined(value)) return;
7941            if (!isArray(value)) value = [value];
7942
7943            forEach(value, function(v) {
7944              if (isObject(v)) {
7945                v = toJson(v);
7946              }
7947              parts.push(encodeUriQuery(key) + '=' +
7948                         encodeUriQuery(v));
7949            });
7950          });
7951          return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
7952        }
7953
7954
7955  }];
7956}
7957
7958function createXhr(method) {
7959    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
7960    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
7961    //if it is available
7962    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
7963      !window.XMLHttpRequest)) {
7964      return new window.ActiveXObject("Microsoft.XMLHTTP");
7965    } else if (window.XMLHttpRequest) {
7966      return new window.XMLHttpRequest();
7967    }
7968
7969    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
7970}
7971
7972/**
7973 * @ngdoc object
7974 * @name ng.$httpBackend
7975 * @requires $browser
7976 * @requires $window
7977 * @requires $document
7978 *
7979 * @description
7980 * HTTP backend used by the {@link ng.$http service} that delegates to
7981 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
7982 *
7983 * You should never need to use this service directly, instead use the higher-level abstractions:
7984 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
7985 *
7986 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
7987 * $httpBackend} which can be trained with responses.
7988 */
7989function $HttpBackendProvider() {
7990  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
7991    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
7992  }];
7993}
7994
7995function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
7996  var ABORTED = -1;
7997
7998  // TODO(vojta): fix the signature
7999  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8000    var status;
8001    $browser.$$incOutstandingRequestCount();
8002    url = url || $browser.url();
8003
8004    if (lowercase(method) == 'jsonp') {
8005      var callbackId = '_' + (callbacks.counter++).toString(36);
8006      callbacks[callbackId] = function(data) {
8007        callbacks[callbackId].data = data;
8008      };
8009
8010      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8011          function() {
8012        if (callbacks[callbackId].data) {
8013          completeRequest(callback, 200, callbacks[callbackId].data);
8014        } else {
8015          completeRequest(callback, status || -2);
8016        }
8017        callbacks[callbackId] = angular.noop;
8018      });
8019    } else {
8020
8021      var xhr = createXhr(method);
8022
8023      xhr.open(method, url, true);
8024      forEach(headers, function(value, key) {
8025        if (isDefined(value)) {
8026            xhr.setRequestHeader(key, value);
8027        }
8028      });
8029
8030      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8031      // response is in the cache. the promise api will ensure that to the app code the api is
8032      // always async
8033      xhr.onreadystatechange = function() {
8034        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8035        // xhrs that are resolved while the app is in the background (see #5426).
8036        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8037        // continuing
8038        //
8039        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8040        // Safari respectively.
8041        if (xhr && xhr.readyState == 4) {
8042          var responseHeaders = null,
8043              response = null;
8044
8045          if(status !== ABORTED) {
8046            responseHeaders = xhr.getAllResponseHeaders();
8047
8048            // responseText is the old-school way of retrieving response 
8048(supported by IE8 & 9)
8049            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8050            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8051          }
8052
8053          completeRequest(callback,
8054              status || xhr.status,
8055              response,
8056              responseHeaders);
8057        }
8058      };
8059
8060      if (withCredentials) {
8061        xhr.withCredentials = true;
8062      }
8063
8064      if (responseType) {
8065        try {
8066          xhr.responseType = responseType;
8067        } catch (e) {
8068          // WebKit added support for the json responseType value on 09/03/2013
8069          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8070          // known to throw when setting the value "json" as the response type. Other older
8071          // browsers implementing the responseType 
8072          //
8073          // The json response type can be ignored if not supported, because JSON payloads are
8074          // parsed on the client-side regardless.
8075          if (responseType !== 'json') {
8076            throw e;
8077          }
8078        }
8079      }
8080
8081      xhr.send(post || null);
8082    }
8083
8084    if (timeout > 0) {
8085      var timeoutId = $browserDefer(timeoutRequest, timeout);
8086    } else if (timeout && timeout.then) {
8087      timeout.then(timeoutRequest);
8088    }
8089
8090
8091    function timeoutRequest() {
8092      status = ABORTED;
8093      jsonpDone && jsonpDone();
8094      xhr && xhr.abort();
8095    }
8096
8097    function completeRequest(callback, status, response, headersString) {
8098      // cancel timeout and subsequent timeout promise resolution
8099      timeoutId && $browserDefer.cancel(timeoutId);
8100      jsonpDone = xhr = null;
8101
8102      // fix status code when it is 0 (0 status is undocumented).
8103      // Occurs when accessing file resources.
8104      // On Android 4.1 stock browser it occurs while retrieving files from application cache.
8105      status = (status === 0) ? (response ? 200 : 404) : status;
8106
8107      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8108      status = status == 1223 ? 204 : status;
8109
8110      callback(status, response, headersString);
8111      $browser.$$completeOutstandingRequest(noop);
8112    }
8113  };
8114
8115  function jsonpReq(url, done) {
8116    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8117    // - fetches local scripts via XHR and evals them
8118    // - adds and immediately removes script elements from the document
8119    var script = rawDocument.createElement('script'),
8120        doneWrapper = function() {
8121          script.onreadystatechange = script.onload = script.onerror = null;
8122          rawDocument.body.removeChild(script);
8123          if (done) done();
8124        };
8125
8126    script.type = 'text/javascript';
8127    script.src = url;
8128
8129    if (msie && msie <= 8) {
8130      script.onreadystatechange = function() {
8131        if (/loaded|complete/.test(script.readyState)) {
8132          doneWrapper();
8133        }
8134      };
8135    } else {
8136      script.onload = script.onerror = function() {
8137        doneWrapper();
8138      };
8139    }
8140
8141    rawDocument.body.appendChild(script);
8142    return doneWrapper;
8143  }
8144}
8145
8146var $interpolateMinErr = minErr('$interpolate');
8147
8148/**
8149 * @ngdoc object
8150 * @name ng.$interpolateProvider
8151 * @function
8152 *
8153 * @description
8154 *
8155 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8156 *
8157 * @example
8158<doc:example module="customInterpolationApp">
8159<doc:source>
8160<script>
8161  var customInterpolationApp = angular.module('customInterpolationApp', []);
8162
8163  customInterpolationApp.config(function($interpolateProvider) {
8164    $interpolateProvider.startSymbol('//');
8165    $interpolateProvider.endSymbol('//');
8166  });
8167
8168
8169  customInterpolationApp.controller('DemoController', function DemoController() {
8170      this.label = "This binding is brought you by // interpolation symbols.";
8171  });
8172</script>
8173<div ng-app="App" ng-controller="DemoController as demo">
8174    //demo.label//
8175</div>
8176</doc:source>
8177<doc:protractor>
8178  it('should interpolate binding with custom symbols', function() {
8179    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8180  });
8181</doc:protractor>
8182</doc:example>
8183 */
8184function $InterpolateProvider() {
8185  var startSymbol = '{{';
8186  var endSymbol = '}}';
8187
8188  /**
8189   * @ngdoc method
8190   * @name ng.$interpolateProvider#startSymbol
8191   * @methodOf ng.$interpolateProvider
8192   * @description
8193   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8194   *
8195   * @param {string=} value new value to set the starting symbol to.
8196   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8197   */
8198  this.startSymbol = function(value){
8199    if (value) {
8200      startSymbol = value;
8201      return this;
8202    } else {
8203      return startSymbol;
8204    }
8205  };
8206
8207  /**
8208   * @ngdoc method
8209   * @name ng.$interpolateProvider#endSymbol
8210   * @methodOf ng.$interpolateProvider
8211   * @description
8212   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8213   *
8214   * @param {string=} value new value to set the ending symbol to.
8215   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8216   */
8217  this.endSymbol = function(value){
8218    if (value) {
8219      endSymbol = value;
8220      return this;
8221    } else {
8222      return endSymbol;
8223    }
8224  };
8225
8226
8227  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8228    var startSymbolLength = startSymbol.length,
8229        endSymbolLength = endSymbol.length;
8230
8231    /**
8232     * @ngdoc function
8233     * @name ng.$interpolate
8234     * @function
8235     *
8236     * @requires $parse
8237     * @requires $sce
8238     *
8239     * @description
8240     *
8241     * Compiles a string with markup into an interpolation function. This service is used by the
8242     * HTML {@link ng.$compile $compile} service for data binding. See
8243     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8244     * interpolation markup.
8245     *
8246     *
8247       <pre>
8248         var $interpolate = ...; // injected
8249         var exp = $interpolate('Hello {{name | uppercase}}!');
8250         expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8251       </pre>
8252     *
8253     *
8254     * @param {string} text The text with markup to interpolate.
8255     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8256     *    embedded expression in order to return an interpolation function. Strings with no
8257     *    embedded expression will return null for the interpolation function.
8258     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8259     *    result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
8260     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8261     *    provides Strict Contextual Escaping for details.
8262     * @returns {function(context)} an interpolation function which is used to compute the
8263     *    interpolated string. The function has these parameters:
8264     *
8265     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8266     *      against.
8267     *
8268     */
8269    function $interpolate(text, mustHaveExpression, trustedContext) {
8270      var startIndex,
8271          endIndex,
8272          index = 0,
8273          parts = [],
8274          length = text.length,
8275          hasInterpolation = false,
8276          fn,
8277          exp,
8278          concat = [];
8279
8280      while(index < length) {
8281        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8282             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8283          (index != startIndex) && parts.push(text.substring(index, startIndex));
8284          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8285          fn.exp = exp;
8286          index = endIndex + endSymbolLength;
8287          hasInterpolation = true;
8288        } else {
8289          // we did not find anything, so we have to add the remainder to the parts array
8290          (index != length) && parts.push(text.substring(index));
8291          index = length;
8292        }
8293      }
8294
8295      if (!(length = parts.length)) {
8296        // we added, nothing, must have been an empty string.
8297        parts.push('');
8298        length = 1;
8299      }
8300
8301      // Concatenating expressions makes it hard to reason about whether some combination of
8302      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8303      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8304      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8305      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8306      // the load when auditing for XSS issues.
8307      if (trustedContext && parts.length > 1) {
8308          throw $interpolateMinErr('noconcat',
8309              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8310              "interpolations that concatenate multiple expressions when a trusted value is " +
8311              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8312      }
8313
8314      if (!mustHaveExpression  || hasInterpolation) {
8315        concat.length = length;
8316        fn = function(context) {
8317          try {
8318            for(var i = 0, ii = length, part; i<ii; i++) {
8319              if (typeof (part = parts[i]) == 'function') {
8320                part = part(context);
8321                if (trustedContext) {
8322                  part = $sce.getTrusted(trustedContext, part);
8323                } else {
8324                  part = $sce.valueOf(part);
8325                }
8326                if (part === null || isUndefined(part)) {
8327                  part = '';
8328                } else if (typeof part != 'string') {
8329                  part = toJson(part);
8330                }
8331              }
8332              concat[i] = part;
8333            }
8334            return concat.join('');
8335          }
8336          catch(err) {
8337            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8338                err.toString());
8339            $exceptionHandler(newErr);
8340          }
8341        };
8342        fn.exp = text;
8343        fn.parts = parts;
8344        return fn;
8345      }
8346    }
8347
8348
8349    /**
8350     * @ngdoc method
8351     * @name ng.$interpolate#startSymbol
8352     * @methodOf ng.$interpolate
8353     * @description
8354     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8355     *
8356     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8357     * the symbol.
8358     *
8359     * @returns {string} start symbol.
8360     */
8361    $interpolate.startSymbol = function() {
8362      return startSymbol;
8363    };
8364
8365
8366    /**
8367     * @ngdoc method
8368     * @name ng.$interpolate#endSymbol
8369     * @methodOf ng.$interpolate
8370     * @description
8371     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8372     *
8373     * Use {@link ng.$interpolateProvider#methods_endSymbol $interpolateProvider#endSymbol} to change
8374     * the symbol.
8375     *
8376     * @returns {string} start symbol.
8377     */
8378    $interpolate.endSymbol = function() {
8379      return endSymbol;
8380    };
8381
8382    return $interpolate;
8383  }];
8384}
8385
8386function $IntervalProvider() {
8387  this.$get = ['$rootScope', '$window', '$q',
8388       function($rootScope,   $window,   $q) {
8389    var intervals = {};
8390
8391
8392     /**
8393      * @ngdoc function
8394      * @name ng.$interval
8395      *
8396      * @description
8397      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8398      * milliseconds.
8399      *
8400      * The return value of registering an interval function is a promise. This promise will be
8401      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8402      * run indefinitely if `count` is not defined. The value of the notification will be the
8403      * number of iterations that have run.
8404      * To cancel an interval, call `$interval.cancel(promise)`.
8405      *
8406      * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
8407      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8408      * time.
8409      *
8410      * <div class="alert alert-warning">
8411      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8412      * with them.  In particular they are not automatically destroyed when a controller's scope or a
8413      * directive's element are destroyed.
8414      * You should take this into consideration and make sure to always cancel the interval at the
8415      * appropriate moment.  See the example below for more details on how and when to do this.
8416      * </div>
8417      *
8418      * @param {function()} fn A function that should be called repeatedly.
8419      * @param {number} delay Number of milliseconds between each function call.
8420      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8421      *   indefinitely.
8422      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8423      *   will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
8424      * @returns {promise} A promise which will be notified on each iteration.
8425      *
8426      * @example
8427      <doc:example module="time">
8428        <doc:source>
8429          <script>
8430            function Ctrl2($scope,$interval) {
8431              $scope.format = 'M/d/yy h:mm:ss a';
8432              $scope.blood_1 = 100;
8433              $scope.blood_2 = 120;
8434
8435              var stop;
8436              $scope.fight = function() {
8437                // Don't start a new fight if we are already fighting
8438                if ( angular.isDefined(stop) ) return;
8439
8440                stop = $interval(function() {
8441                  if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8442                      $scope.blood_1 = $scope.blood_1 - 3;
8443                      $scope.blood_2 = $scope.blood_2 - 4;
8444                  } else {
8445                      $scope.stopFight();
8446                  }
8447                }, 100);
8448              };
8449
8450              $scope.stopFight = function() {
8451                if (angular.isDefined(stop)) {
8452                  $interval.cancel(stop);
8453                  stop = undefined;
8454                }
8455              };
8456
8457              $scope.resetFight = function() {
8458                $scope.blood_1 = 100;
8459                $scope.blood_2 = 120;
8460              }
8461
8462              $scope.$on('$destroy', function() {
8463                // Make sure that the interval is destroyed too
8464                $scope.stopFight();
8465              });
8466            }
8467
8468            angular.module('time', [])
8469              // Register the 'myCurrentTime' directive factory method.
8470              // We inject $interval and dateFilter service since the factory method is DI.
8471              .directive('myCurrentTime', function($interval, dateFilter) {
8472                // return the directive link function. (compile function not needed)
8473                return function(scope, element, attrs) {
8474                  var format,  // date format
8475                  stopTime; // so that we can cancel the time updates
8476
8477                  // used to update the UI
8478                  function updateTime() {
8479                    element.text(dateFilter(new Date(), format));
8480                  }
8481
8482                  // watch the expression, and update the UI on change.
8483                  scope.$watch(attrs.myCurrentTime, function(value) {
8484                    format = value;
8485                    updateTime();
8486                  });
8487
8488                  stopTime = $interval(updateTime, 1000);
8489
8490                  // listen on DOM destroy (removal) event, and cancel the next UI update
8491                  // to prevent updating time ofter the DOM element was removed.
8492                  element.bind('$destroy', function() {
8493                    $interval.cancel(stopTime);
8494                  });
8495                }
8496              });
8497          </script>
8498
8499          <div>
8500            <div ng-controller="Ctrl2">
8501              Date format: <input ng-model="format"> <hr/>
8502              Current time is: <span my-current-time="format"></span>
8503              <hr/>
8504              Blood 1 : <font color='red'>{{blood_1}}</font>
8505              Blood 2 : <font color='red'>{{blood_2}}</font>
8506              <button type="button" data-ng-click="fight()">Fight</button>
8507              <button type="button" data-ng-click="stopFight()">StopFight</button>
8508              <button type="button" data-ng-click="resetFight()">resetFight</button>
8509            </div>
8510          </div>
8511
8512        </doc:source>
8513      </doc:example>
8514      */
8515    function interval(fn, delay, count, invokeApply) {
8516      var setInterval = $window.setInterval,
8517          clearInterval = $window.clearInterval,
8518          deferred = $q.defer(),
8519          promise = deferred.promise,
8520          iteration = 0,
8521          skipApply = (isDefined(invokeApply) && !invokeApply);
8522
8523      count = isDefined(count) ? count : 0;
8524
8525      promise.then(null, null, fn);
8526
8527      promise.$$intervalId = setInterval(function tick() {
8528        deferred.notify(iteration++);
8529
8530        if (count > 0 && iteration >= count) {
8531          deferred.resolve(iteration);
8532          clearInterval(promise.$$intervalId);
8533          delete intervals[promise.$$intervalId];
8534        }
8535
8536        if (!skipApply) $rootScope.$apply();
8537
8538      }, delay);
8539
8540      intervals[promise.$$intervalId] = deferred;
8541
8542      return promise;
8543    }
8544
8545
8546     /**
8547      * @ngdoc function
8548      * @name ng.$interval#cancel
8549      * @methodOf ng.$interval
8550      *
8551      * @description
8552      * Cancels a task associated with the `promise`.
8553      *
8554      * @param {number} promise Promise returned by the `$interval` function.
8555      * @returns {boolean} Returns `true` if the task was successfully canceled.
8556      */
8557    interval.cancel = function(promise) {
8558      if (promise && promise.$$intervalId in intervals) {
8559        intervals[promise.$$intervalId].reject('canceled');
8560        clearInterval(promise.$$intervalId);
8561        delete intervals[promise.$$intervalId];
8562        return true;
8563      }
8564      return false;
8565    };
8566
8567    return interval;
8568  }];
8569}
8570
8571/**
8572 * @ngdoc object
8573 * @name ng.$locale
8574 *
8575 * @description
8576 * $locale service provides localization rules for various Angular components. As of right now the
8577 * only public api is:
8578 *
8579 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
8580 */
8581function $LocaleProvider(){
8582  this.$get = function() {
8583    return {
8584      id: 'en-us',
8585
8586      NUMBER_FORMATS: {
8587        DECIMAL_SEP: '.',
8588        GROUP_SEP: ',',
8589        PATTERNS: [
8590          { // Decimal Pattern
8591            minInt: 1,
8592            minFrac: 0,
8593            maxFrac: 3,
8594            posPre: '',
8595            posSuf: '',
8596            negPre: '-',
8597            negSuf: '',
8598            gSize: 3,
8599            lgSize: 3
8600          },{ //Currency Pattern
8601            minInt: 1,
8602            minFrac: 2,
8603            maxFrac: 2,
8604            posPre: '\u00A4',
8605            posSuf: '',
8606            negPre: '(\u00A4',
8607            negSuf: ')',
8608            gSize: 3,
8609            lgSize: 3
8610          }
8611        ],
8612        CURRENCY_SYM: '$'
8613      },
8614
8615      DATETIME_FORMATS: {
8616        MONTH:
8617            'January,February,March,April,May,June,July,August,September,October,November,December'
8618            .split(','),
8619        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
8620        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
8621        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
8622        AMPMS: ['AM','PM'],
8623        medium: 'MMM d, y h:mm:ss a',
8624        short: 'M/d/yy h:mm a',
8625        fullDate: 'EEEE, MMMM d, y',
8626        longDate: 'MMMM d, y',
8627        mediumDate: 'MMM d, y',
8628        shortDate: 'M/d/yy',
8629        mediumTime: 'h:mm:ss a',
8630        shortTime: 'h:mm a'
8631      },
8632
8633      pluralCat: function(num) {
8634        if (num === 1) {
8635          return 'one';
8636        }
8637        return 'other';
8638      }
8639    };
8640  };
8641}
8642
8643var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
8644    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
8645var $locationMinErr = minErr('$location');
8646
8647
8648/**
8649 * Encode path using encodeUriSegment, ignoring forward slashes
8650 *
8651 * @param {string} path Path to encode
8652 * @returns {string}
8653 */
8654function encodePath(path) {
8655  var segments = path.split('/'),
8656      i = segments.length;
8657
8658  while (i--) {
8659    segments[i] = encodeUriSegment(segments[i]);
8660  }
8661
8662  return segments.join('/');
8663}
8664
8665function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
8666  var parsedUrl = urlResolve(absoluteUrl, appBase);
8667
8668  locationObj.$$protocol = parsedUrl.protocol;
8669  locationObj.$$host = parsedUrl.hostname;
8670  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
8671}
8672
8673
8674function parseAppUrl(relativeUrl, locationObj, appBase) {
8675  var prefixed = (relativeUrl.charAt(0) !== '/');
8676  if (prefixed) {
8677    relativeUrl = '/' + relativeUrl;
8678  }
8679  var match = urlResolve(relativeUrl, appBase);
8680  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
8681      match.pathname.substring(1) : match.pathname);
8682  locationObj.$$search = parseKeyValue(match.search);
8683  locationObj.$$hash = decodeURIComponent(match.hash);
8684
8685  // make sure path starts with '/';
8686  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
8687    locationObj.$$path = '/' + locationObj.$$path;
8688  }
8689}
8690
8691
8692/**
8693 *
8694 * @param {string} begin
8695 * @param {string} whole
8696 * @returns {string} returns text from whole after begin or undefined if it does not begin with
8697 *                   expected string.
8698 */
8699function beginsWith(begin, whole) {
8700  if (whole.indexOf(begin) === 0) {
8701    return whole.substr(begin.length);
8702  }
8703}
8704
8705
8706function stripHash(url) {
8707  var index = url.indexOf('#');
8708  return index == -1 ? url : url.substr(0, index);
8709}
8710
8711
8712function stripFile(url) {
8713  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
8714}
8715
8716/* return the server only (scheme://host:port) */
8717function serverBase(url) {
8718  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
8719}
8720
8721
8722/**
8723 * LocationHtml5Url represents an url
8724 * This object is exposed as $location service when HTML5 mode is enabled and supported
8725 *
8726 * @constructor
8727 * @param {string} appBase application base URL
8728 * @param {string} basePrefix url path prefix
8729 */
8730function LocationHtml5Url(appBase, basePrefix) {
8731  this.$$html5 = true;
8732  basePrefix = basePrefix || '';
8733  var appBaseNoFile = stripFile(appBase);
8734  parseAbsoluteUrl(appBase, this, appBase);
8735
8736
8737  /**
8738   * Parse given html5 (regular) url string into properties
8739   * @param {string} newAbsoluteUrl HTML5 url
8740   * @private
8741   */
8742  this.$$parse = function(url) {
8743    var pathUrl = beginsWith(appBaseNoFile, url);
8744    if (!isString(pathUrl)) {
8745      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
8746          appBaseNoFile);
8747    }
8748
8749    parseAppUrl(pathUrl, this, appBase);
8750
8751    if (!this.$$path) {
8752      this.$$path = '/';
8753    }
8754
8755    this.$$compose();
8756  };
8757
8758  /**
8759   * Compose url and update `absUrl` property
8760   * @private
8761   */
8762  this.$$compose = function() {
8763    var search = toKeyValue(this.$$search),
8764        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
8765
8766    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
8767    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
8768  };
8769
8770  this.$$rewrite = function(url) {
8771    var appUrl, prevAppUrl;
8772
8773    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
8774      prevAppUrl = appUrl;
8775      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
8776        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
8777      } else {
8778        return appBase + prevAppUrl;
8779      }
8780    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
8781      return appBaseNoFile + appUrl;
8782    } else if (appBaseNoFile == url + '/') {
8783      return appBaseNoFile;
8784    }
8785  };
8786}
8787
8788
8789/**
8790 * LocationHashbangUrl represents url
8791 * This object is exposed as $location service when developer doesn't opt into html5 mode.
8792 * It also serves as the base class for html5 mode fallback on legacy browsers.
8793 *
8794 * @constructor
8795 * @param {string} appBase application base URL
8796 * @param {string} hashPrefix hashbang prefix
8797 */
8798function LocationHashbangUrl(appBase, hashPrefix) {
8799  var appBaseNoFile = stripFile(appBase);
8800
8801  parseAbsoluteUrl(appBase, this, appBase);
8802
8803
8804  /**
8805   * Parse given hashbang url into properties
8806   * @param {string} url Hashbang url
8807   * @private
8808   */
8809  this.$$parse = function(url) {
8810    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
8811    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
8812        ? beginsWith(hashPrefix, withoutBaseUrl)
8813        : (this.$$html5)
8814          ? withoutBaseUrl
8815          : '';
8816
8817    if (!isString(withoutHashUrl)) {
8818      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
8819          hashPrefix);
8820    }
8821    parseAppUrl(withoutHashUrl, this, appBase);
8822
8823    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
8824
8825    this.$$compose();
8826
8827    /*
8828     * In Windows, on an anchor node on documents loaded from
8829     * the filesystem, the browser will return a pathname
8830     * prefixed with the drive name ('/C:/path') when a
8831     * pathname without a drive is set:
8832     *  * a.setAttribute('href', '/foo')
8833     *   * a.pathname === '/C:/foo' //true
8834     *
8835     * Inside of Angular, we're always using pathnames that
8836     * do not include drive names for routing.
8837     */
8838    function removeWindowsDriveName (path, url, base) {
8839      /*
8840      Matches paths for file protocol on windows,
8841      such as /C:/foo/bar, and captures only /foo/bar.
8842      */
8843      var windowsFilePathExp = /^\/?.*?:(\/.*)/;
8844
8845      var firstPathSegmentMatch;
8846
8847      //Get the relative path from the input URL.
8848      if (url.indexOf(base) === 0) {
8849        url = url.replace(base, '');
8850      }
8851
8852      /*
8853       * The input URL intentionally contains a
8854       * first path segment that ends with a colon.
8855       */
8856      if (windowsFilePathExp.exec(url)) {
8857        return path;
8858      }
8859
8860      firstPathSegmentMatch = windowsFilePathExp.exec(path);
8861      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
8862    }
8863  };
8864
8865  /**
8866   * Compose hashbang url and update `absUrl` property
8867   * @private
8868   */
8869  this.$$compose = function() {
8870    var search = toKeyValue(this.$$search),
8871        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
8872
8873    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
8874    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
8875  };
8876
8877  this.$$rewrite = function(url) {
8878    if(stripHash(appBase) == stripHash(url)) {
8879      return url;
8880    }
8881  };
8882}
8883
8884
8885/**
8886 * LocationHashbangUrl represents url
8887 * This object is exposed as $location service when html5 history api is enabled but the browser
8888 * does not support it.
8889 *
8890 * @constructor
8891 * @param {string} appBase application base URL
8892 * @param {string} hashPrefix hashbang prefix
8893 */
8894function LocationHashbangInHtml5Url(appBase, hashPrefix) {
8895  this.$$html5 = true;
8896  LocationHashbangUrl.apply(this, arguments);
8897
8898  var appBaseNoFile = stripFile(appBase);
8899
8900  this.$$rewrite = function(url) {
8901    var appUrl;
8902
8903    if ( appBase == stripHash(url) ) {
8904      return url;
8905    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
8906      return appBase + hashPrefix + appUrl;
8907    } else if ( appBaseNoFile === url + '/') {
8908      return appBaseNoFile;
8909    }
8910  };
8911}
8912
8913
8914LocationHashbangInHtml5Url.prototype =
8915  LocationHashbangUrl.prototype =
8916  LocationHtml5Url.prototype = {
8917
8918  /**
8919   * Are we in html5 mode?
8920   * @private
8921   */
8922  $$html5: false,
8923
8924  /**
8925   * Has any change been replacing ?
8926   * @private
8927   */
8928  $$replace: false,
8929
8930  /**
8931   * @ngdoc method
8932   * @name ng.$location#absUrl
8933   * @methodOf ng.$location
8934   *
8935   * @description
8936   * This method is getter only.
8937   *
8938   * Return full url representation with all segments encoded according to rules specified in
8939   * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
8940   *
8941   * @return {string} full url
8942   */
8943  absUrl: locationGetter('$$absUrl'),
8944
8945  /**
8946   * @ngdoc method
8947   * @name ng.$location#url
8948   * @methodOf ng.$location
8949   *
8950   * @description
8951   * This method is getter / setter.
8952   *
8953   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
8954   *
8955   * Change path, search and hash, when called with parameter and return `$location`.
8956   *
8957   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
8958   * @param {string=} replace The path that will be changed
8959   * @return {string} url
8960   */
8961  url: function(url, replace) {
8962    if (isUndefined(url))
8963      return this.$$url;
8964
8965    var match = PATH_MATCH.exec(url);
8966    if (match[1]) this.path(decodeURIComponent(match[1]));
8967    if (match[2] || match[1]) this.search(match[3] || '');
8968    this.hash(match[5] || '', replace);
8969
8970    return this;
8971  },
8972
8973  /**
8974   * @ngdoc method
8975   * @name ng.$location#protocol
8976   * @methodOf ng.$location
8977   *
8978   * @description
8979   * This method is getter only.
8980   *
8981   * Return protocol of current url.
8982   *
8983   * @return {string} protocol of current url
8984   */
8985  protocol: locationGetter('$$protocol'),
8986
8987  /**
8988   * @ngdoc method
8989   * @name ng.$location#host
8990   * @methodOf ng.$location
8991   *
8992   * @description
8993   * This method is getter only.
8994   *
8995   * Return host of current url.
8996   *
8997   * @return {string} host of current url.
8998   */
8999  host: locationGetter('$$host'),
9000
9001  /**
9002   * @ngdoc method
9003   * @name ng.$location#port
9004   * @methodOf ng.$location
9005   *
9006   * @description
9007   * This method is getter only.
9008   *
9009   * Return port of current url.
9010   *
9011   * @return {Number} port
9012   */
9013  port: locationGetter('$$port'),
9014
9015  /**
9016   * @ngdoc method
9017   * @name ng.$location#path
9018   * @methodOf ng.$location
9019   *
9020   * @description
9021   * This method is getter / setter.
9022   *
9023   * Return path of current url when called without any parameter.
9024   *
9025   * Change path when called with parameter and return `$location`.
9026   *
9027   * Note: Path should always begin with forward slash (/), this method will add the forward slash
9028   * if it is missing.
9029   *
9030   * @param {string=} path New path
9031   * @return {string} path
9032   */
9033  path: locationGetterSetter('$$path', function(path) {
9034    return path.charAt(0) == '/' ? path : '/' + path;
9035  }),
9036
9037  /**
9038   * @ngdoc method
9039   * @name ng.$location#search
9040   * @methodOf ng.$location
9041   *
9042   * @description
9043   * This method is getter / setter.
9044   *
9045   * Return search part (as object) of current url when called without any parameter.
9046   *
9047   * Change search part when called with parameter and return `$location`.
9048   *
9049   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9050   * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
9051   * the url.
9052   *
9053   * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
9054   * single search parameter. If `paramValue` is an array, it will set the parameter as a
9055   * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
9056   *
9057   * @return {string} search
9058   */
9059  search: function(search, paramValue) {
9060    switch (arguments.length) {
9061      case 0:
9062        return this.$$search;
9063      case 1:
9064        if (isString(search)) {
9065          this.$$search = parseKeyValue(search);
9066        } else if (isObject(search)) {
9067          this.$$search = search;
9068        } else {
9069          throw $locationMinErr('isrcharg',
9070              'The first argument of the `$location#search()` call must be a string or an object.');
9071        }
9072        break;
9073      default:
9074        if (isUndefined(paramValue) || paramValue === null) {
9075          delete this.$$search[search];
vendor: 5,194 bytes, lines 9076-9253
9076        } else {
9077          this.$$search[search] = paramValue;
9078        }
9079    }
9080
9081    this.$$compose();
9082    return this;
9083  },
9084
9085  /**
9086   * @ngdoc method
9087   * @name ng.$location#hash
9088   * @methodOf ng.$location
9089   *
9090   * @description
9091   * This method is getter / setter.
9092   *
9093   * Return hash fragment when called without any parameter.
9094   *
9095   * Change hash fragment when called with parameter and return `$location`.
9096   *
9097   * @param {string=} hash New hash fragment
9098   * @return {string} hash
9099   */
9100  hash: locationGetterSetter('$$hash', identity),
9101
9102  /**
9103   * @ngdoc method
9104   * @name ng.$location#replace
9105   * @methodOf ng.$location
9106   *
9107   * @description
9108   * If called, all changes to $location during current `$digest` will be replacing current history
9109   * record, instead of adding new one.
9110   */
9111  replace: function() {
9112    this.$$replace = true;
9113    return this;
9114  }
9115};
9116
9117function locationGetter(property) {
9118  return function() {
9119    return this[property];
9120  };
9121}
9122
9123
9124function locationGetterSetter(property, preprocess) {
9125  return function(value) {
9126    if (isUndefined(value))
9127      return this[property];
9128
9129    this[property] = preprocess(value);
9130    this.$$compose();
9131
9132    return this;
9133  };
9134}
9135
9136
9137/**
9138 * @ngdoc object
9139 * @name ng.$location
9140 *
9141 * @requires $browser
9142 * @requires $sniffer
9143 * @requires $rootElement
9144 *
9145 * @description
9146 * The $location service parses the URL in the browser address bar (based on the
9147 * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
9148 * available to your application. Changes to the URL in the address bar are reflected into
9149 * $location service and changes to $location are reflected into the browser address bar.
9150 *
9151 * **The $location service:**
9152 *
9153 * - Exposes the current URL in the browser address bar, so you can
9154 *   - Watch and observe the URL.
9155 *   - Change the URL.
9156 * - Synchronizes the URL with the browser when the user
9157 *   - Changes the address bar.
9158 *   - Clicks the back or forward button (or clicks a History link).
9159 *   - Clicks on a link.
9160 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9161 *
9162 * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
9163 * Services: Using $location}
9164 */
9165
9166/**
9167 * @ngdoc object
9168 * @name ng.$locationProvider
9169 * @description
9170 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9171 */
9172function $LocationProvider(){
9173  var hashPrefix = '',
9174      html5Mode = false;
9175
9176  /**
9177   * @ngdoc property
9178   * @name ng.$locationProvider#hashPrefix
9179   * @methodOf ng.$locationProvider
9180   * @description
9181   * @param {string=} prefix Prefix for hash part (containing path and search)
9182   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9183   */
9184  this.hashPrefix = function(prefix) {
9185    if (isDefined(prefix)) {
9186      hashPrefix = prefix;
9187      return this;
9188    } else {
9189      return hashPrefix;
9190    }
9191  };
9192
9193  /**
9194   * @ngdoc property
9195   * @name ng.$locationProvider#html5Mode
9196   * @methodOf ng.$locationProvider
9197   * @description
9198   * @param {boolean=} mode Use HTML5 strategy if available.
9199   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9200   */
9201  this.html5Mode = function(mode) {
9202    if (isDefined(mode)) {
9203      html5Mode = mode;
9204      return this;
9205    } else {
9206      return html5Mode;
9207    }
9208  };
9209
9210  /**
9211   * @ngdoc event
9212   * @name ng.$location#$locationChangeStart
9213   * @eventOf ng.$location
9214   * @eventType broadcast on root scope
9215   * @description
9216   * Broadcasted before a URL will change. This change can be prevented by calling
9217   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#methods_$on} for more
9218   * details about event object. Upon successful change
9219   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9220   *
9221   * @param {Object} angularEvent Synthetic event object.
9222   * @param {string} newUrl New URL
9223   * @param {string=} oldUrl URL that was before it was changed.
9224   */
9225
9226  /**
9227   * @ngdoc event
9228   * @name ng.$location#$locationChangeSuccess
9229   * @eventOf ng.$location
9230   * @eventType broadcast on root scope
9231   * @description
9232   * Broadcasted after a URL was changed.
9233   *
9234   * @param {Object} angularEvent Synthetic event object.
9235   * @param {string} newUrl New URL
9236   * @param {string=} oldUrl URL that was before it was changed.
9237   */
9238
9239  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9240      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9241    var $location,
9242        LocationMode,
9243        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9244        initialUrl = $browser.url(),
9245        appBase;
9246
9247    if (html5Mode) {
9248      appBase = serverBase(initialUrl) + (baseHref || '/');
9249      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9250    } else {
9251      appBase = stripHash(initialUrl);
9252      LocationMode = LocationHashbangUrl;
9253    }
9254    $location = new LocationMode(appBase, '#' + hashPrefix);
9255    $location.$$parse($location.$$rewrite(initialUrl));
9256
9257    $rootElement.on('click', function(event) {
9258      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9259      // currently we open nice url link and redirect then
9260
9261      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9262
9263      var elm = jqLite(event.target);
9264
9265      // traverse the DOM up to find first A tag
9266      while (lowercase(elm[0].nodeName) !== 'a') {
9267        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9268        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9269      }
9270
9271      var absHref = elm.prop('href');
9272
9273      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9274        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9275        // an animation.
9276        absHref = urlResolve(absHref.animVal).href;
9277      }
9278
9279      var rewrittenUrl = $location.$$rewrite(absHref);
9280
9281      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9282        event.preventDefault();
9283        if (rewrittenUrl != $browser.url()) {
9284          // update location manually
9285          $location.$$parse(rewrittenUrl);
9286          $rootScope.$apply();
9287          // hack to work around FF6 bug 684208 when scenario runner clicks on links
9288          window.angular['ff-684208-preventDefault'] = true;
9289        }
9290      }
9291    });
9292
9293
9294    // rewrite hashbang url <> html5 url
9295    if ($location.absUrl() != initialUrl) {
9296      $browser.url($location.absUrl(), true);
9297    }
9298
9299    // update $location when $browser url changes
9300    $browser.onUrlChange(function(newUrl) {
9301      if ($location.absUrl() != newUrl) {
9302        $rootScope.$evalAsync(function() {
9303          var oldUrl = $location.absUrl();
9304
9305          $location.$$parse(newUrl);
9306          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9307                                    oldUrl).defaultPrevented) {
9308            $location.$$parse(oldUrl);
9309            $browser.url(oldUrl);
9310          } else {
9311            afterLocationChange(oldUrl);
9312          }
9313        });
9314        if (!$rootScope.$$phase) $rootScope.$digest();
9315      }
9316    });
9317
9318    // update browser
9319    var changeCounter = 0;
9320    $rootScope.$watch(function $locationWatch() {
9321      var oldUrl = $browser.url();
9322      var currentReplace = $location.$$replace;
9323
9324      if (!changeCounter || oldUrl != $location.absUrl()) {
9325        changeCounter++;
9326        $rootScope.$evalAsync(function() {
9327          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9328              defaultPrevented) {
9329            $location.$$parse(oldUrl);
9330          } else {
9331            $browser.url($location.absUrl(), currentReplace);
9332            afterLocationChange(oldUrl);
9333          }
9334        });
9335      }
9336      $location.$$replace = false;
9337
9338      return changeCounter;
9339    });
9340
9341    return $location;
9342
9343    function afterLocationChange(oldUrl) {
9344      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9345    }
9346}];
9347}
9348
9349/**
9350 * @ngdoc object
9351 * @name ng.$log
9352 * @requires $window
9353 *
9354 * @description
9355 * Simple service for logging. Default implementation safely writes the message
9356 * into the browser's console (if present).
9357 * 
9358 * The main purpose of this service is to simplify debugging and troubleshooting.
9359 *
9360 * The default is to log `debug` messages. You can use
9361 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9362 *
9363 * @example
9364   <example>
9365     <file name="script.js">
9366       function LogCtrl($scope, $log) {
9367         $scope.$log = $log;
9368         $scope.message = 'Hello World!';
9369       }
9370     </file>
9371     <file name="index.html">
9372       <div ng-controller="LogCtrl">
9373         <p>Reload this page with open console, enter text and hit the log button...</p>
9374         Message:
9375         <input type="text" ng-model="message"/>
9376         <button ng-click="$log.log(message)">log</button>
9377         <button ng-click="$log.warn(message)">warn</button>
9378         <button ng-click="$log.info(message)">info</button>
9379         <button ng-click="$log.error(message)">error</button>
9380       </div>
9381     </file>
9382   </example>
9383 */
9384
9385/**
9386 * @ngdoc object
9387 * @name ng.$logProvider
9388 * @description
9389 * Use the `$logProvider` to configure how the application logs messages
9390 */
9391function $LogProvider(){
9392  var debug = true,
9393      self = this;
9394  
9395  /**
9396   * @ngdoc property
9397   * @name ng.$logProvider#debugEnabled
9398   * @methodOf ng.$logProvider
9399   * @description
9400   * @param {boolean=} flag enable or disable debug level messages
9401   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9402   */
9403  this.debugEnabled = function(flag) {
9404    if (isDefined(flag)) {
9405      debug = flag;
9406    return this;
9407    } else {
9408      return debug;
9409    }
9410  };
9411  
9412  this.$get = ['$window', function($window){
9413    return {
9414      /**
9415       * @ngdoc method
9416       * @name ng.$log#log
9417       * @methodOf ng.$log
9418       *
9419       * @description
9420       * Write a log message
9421       */
9422      log: consoleLog('log'),
9423
9424      /**
9425       * @ngdoc method
9426       * @name ng.$log#info
9427       * @methodOf ng.$log
9428       *
9429       * @description
9430       * Write an information message
9431       */
9432      info: consoleLog('info'),
9433
9434      /**
9435       * @ngdoc method
9436       * @name ng.$log#warn
9437       * @methodOf ng.$log
9438       *
9439       * @description
9440       * Write a warning message
9441       */
9442      warn: consoleLog('warn'),
9443
9444      /**
9445       * @ngdoc method
9446       * @name ng.$log#error
9447       * @methodOf ng.$log
9448       *
9449       * @description
9450       * Write an error message
9451       */
9452      error: consoleLog('error'),
9453      
9454      /**
9455       * @ngdoc method
9456       * @name ng.$log#debug
9457       * @methodOf ng.$log
9458       * 
9459       * @description
9460       * Write a debug message
9461       */
9462      debug: (function () {
9463        var fn = consoleLog('debug');
9464
9465        return function() {
9466          if (debug) {
9467            fn.apply(self, arguments);
9468          }
9469        };
9470      }())
9471    };
9472
9473    function formatError(arg) {
9474      if (arg instanceof Error) {
9475        if (arg.stack) {
9476          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
9477              ? 'Error: ' + arg.message + '\n' + arg.stack
9478              : arg.stack;
9479        } else if (arg.sourceURL) {
9480          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
9481        }
9482      }
9483      return arg;
9484    }
9485
9486    function consoleLog(type) {
9487      var console = $window.console || {},
9488          logFn = console[type] || console.log || noop,
9489          hasApply = false;
9490
9491      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
9492      // The reason behind this is that console.log has type "object" in IE8...
9493      try {
9494        hasApply = !! logFn.apply;
9495      } catch (e) {}
9496
9497      if (hasApply) {
9498        return function() {
9499          var args = [];
9500          forEach(arguments, function(arg) {
9501            args.push(formatError(arg));
9502          });
9503          return logFn.apply(console, args);
9504        };
9505      }
9506
9507      // we are IE which either doesn't have window.console => this is noop and we do nothing,
9508      // or we are IE where console.log doesn't have apply so we log at least first 2 args
9509      return function(arg1, arg2) {
9510        logFn(arg1, arg2 == null ? '' : arg2);
9511      };
9512    }
9513  }];
9514}
9515
9516var $parseMinErr = minErr('$parse');
9517var promiseWarningCache = {};
9518var promiseWarning;
9519
9520// Sandboxing Angular Expressions
9521// ------------------------------
9522// Angular expressions are generally considered safe because these expressions only have direct
9523// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9524// obtaining a reference to native JS functions such as the Function constructor.
9525//
9526// As an example, consider the following Angular expression:
9527//
9528//   {}.toString.constructor(alert("evil JS code"))
9529//
9530// We want to prevent this type of access. For the sake of performance, during the lexing phase we
9531// disallow any "dotted" access to any member named "constructor".
9532//
9533// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
9534// while evaluating the expression, which is a stronger but more expensive test. Since reflective
9535// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
9536//
9537// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9538// against the expression language, but not to prevent exploits that were enabled by exposing
9539// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
9540// practice and therefore we are not even trying to protect against interaction with an object
9541// explicitly exposed in this way.
9542//
9543// A developer could foil the name check by aliasing the Function constructor under a different
9544// name on the scope.
9545//
9546// In general, it is not possible to access a Window object from an angular expression unless a
9547// window or some DOM object that has a reference to window is published onto a Scope.
9548
9549function ensureSafeMemberName(name, fullExpression) {
9550  if (name === "constructor") {
9551    throw $parseMinErr('isecfld',
9552        'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
9553        fullExpression);
9554  }
9555  return name;
9556}
9557
9558function ensureSafeObject(obj, fullExpression) {
9559  // nifty check if obj is Function that is fast and works across iframes and other contexts
9560  if (obj) {
9561    if (obj.constructor === obj) {
9562      throw $parseMinErr('isecfn',
9563          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9564          fullExpression);
9565    } else if (// isWindow(obj)
9566        obj.document && obj.location && obj.alert && obj.setInterval) {
9567      throw $parseMinErr('isecwindow',
9568          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9569          fullExpression);
9570    } else if (// isElement(obj)
9571        obj.children && (obj.nodeName || (obj.on && obj.find))) {
9572      throw $parseMinErr('isecdom',
9573          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9574          fullExpression);
9575    }
9576  }
9577  return obj;
9578}
9579
9580var OPERATORS = {
9581    /* jshint bitwise : false */
9582    'null':function(){return null;},
9583    'true':function(){return true;},
9584    'false':function(){return false;},
9585    undefined:noop,
9586    '+':function(self, locals, a,b){
9587      a=a(self, locals); b=b(self, locals);
9588      if (isDefined(a)) {
9589        if (isDefined(b)) {
9590          return a + b;
9591        }
9592        return a;
9593      }
9594      return isDefined(b)?b:undefined;},
9595    '-':function(self, locals, a,b){
9596          a=a(self, locals); b=b(self, locals);
9597          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
9598        },
9599    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
9600    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
9601    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
9602    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
9603    '=':noop,
9604    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
9605    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
9606    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
9607    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
9608    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
9609    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
9610    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
9611    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
9612    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
9613    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
9614    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
9615//    '|':function(self, locals, a,b){return a|b;},
9616    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
9617    '!':function(self, locals, a){return !a(self, locals);}
9618};
9619/* jshint bitwise: true */
9620var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
9621
9622
9623/////////////////////////////////////////
9624
9625
9626/**
9627 * @constructor
9628 */
9629var Lexer = function (options) {
9630  this.options = options;
9631};
9632
9633Lexer.prototype = {
9634  constructor: Lexer,
9635
9636  lex: function (text) {
9637    this.text = text;
9638
9639    this.index = 0;
9640    this.ch = undefined;
9641    this.lastCh = ':'; // can start regexp
9642
9643    this.tokens = [];
9644
9645    var token;
9646    var json = [];
9647
9648    while (this.index < this.text.length) {
9649      this.ch = this.text.charAt(this.index);
9650      if (this.is('"\'')) {
9651        this.readString(this.ch);
9652      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
9653        this.readNumber();
9654      } else if (this.isIdent(this.ch)) {
9655        this.readIdent();
9656        // identifiers can only be if the preceding char was a { or ,
9657        if (this.was('{,') && json[0] === '{' &&
9658            (token = this.tokens[this.tokens.length - 1])) {
9659          token.json = token.text.indexOf('.') === -1;
9660        }
9661      } else if (this.is('(){}[].,;:?')) {
9662        this.tokens.push({
9663          index: this.index,
9664          text: this.ch,
9665          json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
9666        });
9667        if (this.is('{[')) json.unshift(this.ch);
9668        if (this.is('}]')) json.shift();
9669        this.index++;
9670      } else if (this.isWhitespace(this.ch)) {
9671        this.index++;
9672        continue;
9673      } else {
9674        var ch2 = this.ch + this.peek();
9675        var ch3 = ch2 + this.peek(2);
9676        var fn = OPERATORS[this.ch];
9677        var fn2 = OPERATORS[ch2];
9678        var fn3 = OPERATORS[ch3];
9679        if (fn3) {
9680          this.tokens.push({index: this.index, text: ch3, fn: fn3});
9681          this.index += 3;
9682        } else if (fn2) {
9683          this.tokens.push({index: this.index, text: ch2, fn: fn2});
9684          this.index += 2;
9685        } else if (fn) {
9686          this.tokens.push({
9687            index: this.index,
9688            text: this.ch,
9689            fn: fn,
9690            json: (this.was('[,:') && this.is('+-'))
9691          });
9692          this.index += 1;
9693        } else {
9694          this.throwError('Unexpected next character ', this.index, this.index + 1);
9695        }
9696      }
9697      this.lastCh = this.ch;
9698    }
9699    return this.tokens;
9700  },
9701
9702  is: function(chars) {
9703    return chars.indexOf(this.ch) !== -1;
9704  },
9705
9706  was: function(chars) {
9707    return chars.indexOf(this.lastCh) !== -1;
9708  },
9709
9710  peek: function(i) {
9711    var num = i || 1;
9712    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
9713  },
9714
9715  isNumber: function(ch) {
9716    return ('0' <= ch && ch <= '9');
9717  },
9718
9719  isWhitespace: function(ch) {
9720    // IE treats non-breaking space as \u00A0
9721    return (ch === ' ' || ch === '\r' || ch === '\t' ||
9722            ch === '\n' || ch === '\v' || ch === '\u00A0');
9723  },
9724
9725  isIdent: function(ch) {
9726    return ('a' <= ch && ch <= 'z' ||
9727            'A' <= ch && ch <= 'Z' ||
9728            '_' === ch || ch === '$');
9729  },
9730
9731  isExpOperator: function(ch) {
9732    return (ch === '-' || ch === '+' || this.isNumber(ch));
9733  },
9734
9735  throwError: function(error, start, end) {
9736    end = end || this.index;
9737    var colStr = (isDefined(start)
9738            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
9739            : ' ' + end);
9740    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
9741        error, colStr, this.text);
9742  },
9743
9744  readNumber: function() {
9745    var number = '';
9746    var start = this.index;
9747    while (this.index < this.text.length) {
9748      var ch = lowercase(this.text.charAt(this.index));
9749      if (ch == '.' || this.isNumber(ch)) {
9750        number += ch;
9751      } else {
9752        var peekCh = this.peek();
9753        if (ch == 'e' && this.isExpOperator(peekCh)) {
9754          number += ch;
9755        } else if (this.isExpOperator(ch) &&
9756            peekCh && this.isNumber(peekCh) &&
9757            number.charAt(number.length - 1) == 'e') {
9758          number += ch;
9759        } else if (this.isExpOperator(ch) &&
9760            (!peekCh || !this.isNumber(peekCh)) &&
9761            number.charAt(number.length - 1) == 'e') {
9762          this.throwError('Invalid exponent');
9763        } else {
9764          break;
9765        }
9766      }
9767      this.index++;
9768    }
9769    number = 1 * number;
9770    this.tokens.push({
9771      index: start,
9772      text: number,
9773      json: true,
9774      fn: function() { return number; }
9775    });
9776  },
9777
9778  readIdent: function() {
9779    var parser = this;
9780
9781    var ident = '';
9782    var start = this.index;
9783
9784    var lastDot, peekIndex, methodName, ch;
9785
9786    while (this.index < this.text.length) {
9787      ch = this.text.charAt(this.index);
9788      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
9789        if (ch === '.') lastDot = this.index;
9790        ident += ch;
9791      } else {
9792        break;
9793      }
9794      this.index++;
9795    }
9796
9797    //check if this is not a method invocation and if it is back out to last dot
9798    if (lastDot) {
9799      peekIndex = this.index;
9800      while (peekIndex < this.text.length) {
9801        ch = this.text.charAt(peekIndex);
9802        if (ch === '(') {
9803          methodName = ident.substr(lastDot - start + 1);
9804          ident = ident.substr(0, lastDot - start);
9805          this.index = peekIndex;
9806          break;
9807        }
9808        if (this.isWhitespace(ch)) {
9809          peekIndex++;
9810        } else {
9811          break;
9812        }
9813      }
9814    }
9815
9816
9817    var token = {
9818      index: start,
9819      text: ident
9820    };
9821
9822    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
9823    if (OPERATORS.hasOwnProperty(ident)) {
9824      token.fn = OPERATORS[ident];
9825      token.json = OPERATORS[ident];
9826    } else {
9827      var getter = getterFn(ident, this.options, this.text);
9828      token.fn = extend(function(self, locals) {
9829        return (getter(self, locals));
9830      }, {
9831        assign: function(self, value) {
9832          return setter(self, ident, value, parser.text, parser.options);
9833        }
9834      });
9835    }
9836
9837    this.tokens.push(token);
9838
9839    if (methodName) {
9840      this.tokens.push({
9841        index:lastDot,
9842        text: '.',
9843        json: false
9844      });
9845      this.tokens.push({
9846        index: lastDot + 1,
9847        text: methodName,
9848        json: false
9849      });
9850    }
9851  },
9852
9853  readString: function(quote) {
9854    var start = this.index;
9855    this.index++;
9856    var string = '';
9857    var rawString = quote;
9858    var escape = false;
9859    while (this.index < this.text.length) {
9860      var ch = this.text.charAt(this.index);
9861      rawString += ch;
9862      if (escape) {
9863        if (ch === 'u') {
9864          var hex = this.text.substring(this.index + 1, this.index + 5);
9865          if (!hex.match(/[\da-f]{4}/i))
9866            this.throwError('Invalid unicode escape [\\u' + hex + ']');
9867          this.index += 4;
9868          string += String.fromCharCode(parseInt(hex, 16));
9869        } else {
9870          var rep = ESCAPE[ch];
9871          if (rep) {
9872            string += rep;
9873          } else {
9874            string += ch;
9875          }
9876        }
9877        escape = false;
9878      } else if (ch === '\\') {
9879        escape = true;
9880      } else if (ch === quote) {
9881        this.index++;
9882        this.tokens.push({
9883          index: start,
9884          text: rawString,
9885          string: string,
9886          json: true,
9887          fn: function() { return string; }
9888        });
9889        return;
9890      } else {
9891        string += ch;
9892      }
9893      this.index++;
9894    }
9895    this.throwError('Unterminated quote', start);
9896  }
9897};
9898
9899
9900/**
9901 * @constructor
9902 */
9903var Parser = function (lexer, $filter, options) {
9904  this.lexer = lexer;
9905  this.$filter = $filter;
9906  this.options = options;
9907};
9908
9909Parser.ZERO = function () { return 0; };
9910
9911Parser.prototype = {
9912  constructor: Parser,
9913
9914  parse: function (text, json) {
9915    this.text = text;
9916
9917    //TODO(i): strip all the obsolte json stuff from this file
9918    this.json = json;
9919
9920    this.tokens = this.lexer.lex(text);
9921
9922    if (json) {
9923      // The extra level of aliasing is here, just in case the lexer misses something, so that
9924      // we prevent any accidental execution in JSON.
9925      this.assignment = this.logicalOR;
9926
9927      this.functionCall =
9928      this.fieldAccess =
9929      this.objectIndex =
9930      this.filterChain = function() {
9931        this.throwError('is not valid json', {text: text, index: 0});
9932      };
9933    }
9934
9935    var value = json ? this.primary() : this.statements();
9936
9937    if (this.tokens.length !== 0) {
9938      this.throwError('is an unexpected token', this.tokens[0]);
9939    }
9940
9941    value.literal = !!value.literal;
9942    value.constant = !!value.constant;
9943
9944    return value;
9945  },
9946
9947  primary: function () {
9948    var primary;
9949    if (this.expect('(')) {
9950      primary = this.filterChain();
9951      this.consume(')');
9952    } else if (this.expect('[')) {
9953      primary = this.arrayDeclaration();
9954    } else if (this.expect('{')) {
9955      primary = this.object();
9956    } else {
9957      var token = this.expect();
9958      primary = token.fn;
9959      if (!primary) {
9960        this.throwError('not a primary expression', token);
9961      }
9962      if (token.json) {
9963        primary.constant = true;
9964        primary.literal = true;
9965      }
9966    }
9967
9968    var next, context;
9969    while ((next = this.expect('(', '[', '.'))) {
9970      if (next.text === '(') {
9971        primary = this.functionCall(primary, context);
9972        context = null;
9973      } else if (next.text === '[') {
9974        context = primary;
9975        primary = this.objectIndex(primary);
9976      } else if (next.text === '.') {
9977        context = primary;
9978        primary = this.fieldAccess(primary);
9979      } else {
9980        this.throwError('IMPOSSIBLE');
9981      }
9982    }
9983    return primary;
9984  },
9985
9986  throwError: function(msg, token) {
9987    throw $parseMinErr('syntax',
9988        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
9989          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
9990  },
9991
9992  peekToken: function() {
9993    if (this.tokens.length === 0)
9994      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
9995    return this.tokens[0];
9996  },
9997
9998  peek: function(e1, e2, e3, e4) {
9999    if (this.tokens.length > 0) {
10000      var token = this.tokens[0];
10001      var t = token.text;
10002      if (t === e1 || t === e2 || t === e3 || t === e4 ||
10003          (!e1 && !e2 && !e3 && !e4)) {
10004        return token;
10005      }
10006    }
10007    return false;
10008  },
10009
10010  expect: function(e1, e2, e3, e4){
10011    var token = this.peek(e1, e2, e3, e4);
10012    if (token) {
10013      if (this.json && !token.json) {
10014        this.throwError('is not valid json', token);
10015      }
10016      this.tokens.shift();
10017      return token;
10018    }
10019    return false;
10020  },
10021
10022  consume: function(e1){
10023    if (!this.expect(e1)) {
10024      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10025    }
10026  },
10027
10028  unaryFn: function(fn, right) {
10029    return extend(function(self, locals) {
10030      return fn(self, locals, right);
10031    }, {
10032      constant:right.constant
10033    });
10034  },
10035
10036  ternaryFn: function(left, middle, right){
10037    return extend(function(self, locals){
10038      return left(self, locals) ? middle(self, locals) : right(self, locals);
10039    }, {
10040      constant: left.constant && middle.constant && right.constant
10041    });
10042  },
10043
10044  binaryFn: function(left, fn, right) {
10045    return extend(function(self, locals) {
10046      return fn(self, locals, left, right);
10047    }, {
10048      constant:left.constant && right.constant
10049    });
10050  },
10051
10052  statements: function() {
10053    var statements = [];
10054    while (true) {
10055      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10056        statements.push(this.filterChain());
10057      if (!this.expect(';')) {
10058        // optimize for the common case where there is only one statement.
10059        // TODO(size): maybe we should not support multiple statements?
10060        return (statements.length === 1)
10061            ? statements[0]
10062            : function(self, locals) {
10063                var value;
10064                for (var i = 0; i < statements.length; i++) {
10065                  var statement = statements[i];
10066                  if (statement) {
10067                    value = statement(self, locals);
10068                  }
10069                }
10070                return value;
10071              };
10072      }
10073    }
10074  },
10075
10076  filterChain: function() {
10077    var left = this.expression();
10078    var token;
10079    while (true) {
10080      if ((token = this.expect('|'))) {
10081        left = this.binaryFn(left, token.fn, this.filter());
10082      } else {
10083        return left;
10084      }
10085    }
10086  },
10087
10088  filter: function() {
10089    var token = this.expect();
10090    var fn = this.$filter(token.text);
10091    var argsFn = [];
10092    while (true) {
10093      if ((token = this.expect(':'))) {
10094        argsFn.push(this.expression());
10095      } else {
10096        var fnInvoke = function(self, locals, input) {
10097          var args = [input];
10098          for (var i = 0; i < argsFn.length; i++) {
10099            args.push(argsFn[i](self, locals));
10100          }
10101          return fn.apply(self, args);
10102        };
10103        return function() {
10104          return fnInvoke;
10105        };
10106      }
10107    }
10108  },
10109
10110  expression: function() {
10111    return this.assignment();
10112  },
10113
10114  assignment: function() {
10115    var left = this.ternary();
10116    var right;
10117    var token;
10118    if ((token = this.expect('='))) {
10119      if (!left.assign) {
10120        this.throwError('implies assignment but [' +
10121            this.text.substring(0, token.index) + '] can not be assigned to', token);
10122      }
10123      right = this.ternary();
10124      return function(scope, locals) {
10125        return left.assign(scope, right(scope, locals), locals);
10126      };
10127    }
10128    return left;
10129  },
10130
10131  ternary: function() {
10132    var left = this.logicalOR();
10133    var middle;
10134    var token;
10135    if ((token = this.expect('?'))) {
10136      middle = this.ternary();
10137      if ((token = this.expect(':'))) {
10138        return this.ternaryFn(left, middle, this.ternary());
10139      } else {
10140        this.throwError('expected :', token);
10141      }
10142    } else {
10143      return left;
10144    }
10145  },
10146
10147  logicalOR: function() {
10148    var left = this.logicalAND();
10149    var token;
10150    while (true) {
10151      if ((token = this.expect('||'))) {
10152        left = this.binaryFn(left, token.fn, this.logicalAND());
10153      } else {
10154        return left;
10155      }
10156    }
10157  },
10158
10159  logicalAND: function() {
10160    var left = this.equality();
10161    var token;
10162    if ((token = this.expect('&&'))) {
10163      left = this.binaryFn(left, token.fn, this.logicalAND());
10164    }
10165    return left;
10166  },
10167
10168  equality: function() {
10169    var left = this.relational();
10170    var token;
10171    if ((token = this.expect('==','!=','===','!=='))) {
10172      left = this.binaryFn(left, token.fn, this.equality());
10173    }
10174    return left;
10175  },
10176
10177  relational: function() {
10178    var left = this.additive();
10179    var token;
10180    if ((token = this.expect('<', '>', '<=', '>='))) {
10181      left = this.binaryFn(left, token.fn, this.relational());
10182    }
10183    return left;
10184  },
10185
10186  additive: function() {
10187    var left = this.multiplicative();
10188    var token;
10189    while ((token = this.expect('+','-'))) {
10190      left = this.binaryFn(left, token.fn, this.multiplicative());
10191    }
10192    return left;
10193  },
10194
10195  multiplicative: function() {
10196    var left = this.unary();
10197    var token;
10198    while ((token = this.expect('*','/','%'))) {
10199      left = this.binaryFn(left, token.fn, this.unary());
10200    }
10201    return left;
10202  },
10203
10204  unary: function() {
10205    var token;
10206    if (this.expect('+')) {
10207      return this.primary();
10208    } else if ((token = this.expect('-'))) {
10209      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10210    } else if ((token = this.expect('!'))) {
10211      return this.unaryFn(token.fn, this.unary());
10212    } else {
10213      return this.primary();
10214    }
10215  },
10216
10217  fieldAccess: function(object) {
10218    var parser = this;
10219    var field = this.expect().text;
10220    var getter = getterFn(field, this.options, this.text);
10221
10222    return extend(function(scope, locals, self) {
10223      return getter(self || object(scope, locals));
10224    }, {
10225      assign: function(scope, value, locals) {
10226        return setter(object(scope, locals), field, value, parser.text, parser.options);
10227      }
10228    });
10229  },
10230
10231  objectIndex: function(obj) {
10232    var parser = this;
10233
10234    var indexFn = this.expression();
10235    this.consume(']');
10236
10237    return extend(function(self, locals) {
10238      var o = obj(self, locals),
10239          i = indexFn(self, locals),
10240          v, p;
10241
10242      if (!o) return undefined;
10243      v = ensureSafeObject(o[i], parser.text);
10244      if (v && v.then && parser.options.unwrapPromises) {
10245        p = v;
10246        if (!('$$v' in v)) {
10247          p.$$v = undefined;
10248          p.then(function(val) { p.$$v = val; });
10249        }
10250        v = v.$$v;
10251      }
10252      return v;
10253    }, {
10254      assign: function(self, value, locals) {
10255        var key = indexFn(self, locals);
10256        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10257        var safe = ensureSafeObject(obj(self, locals), parser.text);
10258        return safe[key] = value;
10259      }
10260    });
10261  },
10262
10263  functionCall: function(fn, contextGetter) {
10264    var argsFn = [];
10265    if (this.peekToken().text !== ')') {
10266      do {
10267        argsFn.push(this.expression());
10268      } while (this.expect(','));
10269    }
10270    this.consume(')');
10271
10272    var parser = this;
10273
10274    return function(scope, locals) {
10275      var args = [];
10276      var context = contextGetter ? contextGetter(scope, locals) : scope;
10277
10278      for (var i = 0; i < argsFn.length; i++) {
10279        args.push(argsFn[i](scope, locals));
10280      }
10281      var fnPtr = fn(scope, locals, context) || noop;
10282
10283      ensureSafeObject(context, parser.text);
10284      ensureSafeObject(fnPtr, parser.text);
10285
10286      // IE stupidity! (IE doesn't have apply for some native functions)
10287      var v = fnPtr.apply
10288            ? fnPtr.apply(context, args)
10289            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10290
10291      return ensureSafeObject(v, parser.text);
10292    };
10293  },
10294
10295  // This is used with json array declaration
10296  arrayDeclaration: function () {
10297    var elementFns = [];
10298    var allConstant = true;
10299    if (this.peekToken().text !== ']') {
10300      do {
10301        var elementFn = this.expression();
10302        elementFns.push(elementFn);
10303        if (!elementFn.constant) {
10304          allConstant = false;
10305        }
10306      } while (this.expect(','));
10307    }
10308    this.consume(']');
10309
10310    return extend(function(self, locals) {
10311      var array = [];
10312      for (var i = 0; i < elementFns.length; i++) {
10313        array.push(elementFns[i](self, locals));
10314      }
10315      return array;
10316    }, {
10317      literal: true,
10318      constant: allConstant
10319    });
10320  },
10321
10322  object: function () {
10323    var keyValues = [];
10324    var allConstant = true;
10325    if (this.peekToken().text !== '}') {
10326      do {
10327        var token = this.expect(),
10328        key = token.string || token.text;
10329        this.consume(':');
10330        var value = this.expression();
10331        keyValues.push({key: key, value: value});
10332        if (!value.constant) {
10333          allConstant = false;
10334        }
10335      } while (this.expect(','));
10336    }
10337    this.consume('}');
10338
10339    return extend(function(self, locals) {
10340      var object = {};
10341      for (var i = 0; i < keyValues.length; i++) {
10342        var keyValue = keyValues[i];
10343        object[keyValue.key] = keyValue.value(self, locals);
10344      }
10345      return object;
10346    }, {
10347      literal: true,
10348      constant: allConstant
10349    });
10350  }
10351};
10352
10353
10354//////////////////////////////////////////////////
10355// Parser helper functions
10356//////////////////////////////////////////////////
10357
10358function setter(obj, path, setValue, fullExp, options) {
10359  //needed?
10360  options = options || {};
10361
10362  var element = path.split('.'), key;
10363  for (var i = 0; element.length > 1; i++) {
10364    key = ensureSafeMemberName(element.shift(), fullExp);
10365    var propertyObj = obj[key];
10366    if (!propertyObj) {
10367      propertyObj = {};
10368      obj[key] = propertyObj;
10369    }
10370    obj = propertyObj;
10371    if (obj.then && options.unwrapPromises) {
10372      promiseWarning(fullExp);
10373      if (!("$$v" in obj)) {
10374        (function(promise) {
10375          promise.then(function(val) { promise.$$v = val; }); }
10376        )(obj);
10377      }
10378      if (obj.$$v === undefined) {
10379        obj.$$v = {};
10380      }
10381      obj = obj.$$v;
10382    }
10383  }
10384  key = ensureSafeMemberName(element.shift(), fullExp);
10385  obj[key] = setValue;
10386  return setValue;
10387}
10388
10389var getterFnCache = {};
10390
10391/**
10392 * Implementation of the "Black Hole" variant from:
10393 * - http://jsperf.com/angularjs-parse-getter/4
10394 * - http://jsperf.com/path-evaluation-simplified/7
10395 */
10396function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10397  ensureSafeMemberName(key0, fullExp);
10398  ensureSafeMemberName(key1, fullExp);
10399  ensureSafeMemberName(key2, fullExp);
10400  ensureSafeMemberName(key3, fullExp);
10401  ensureSafeMemberName(key4, fullExp);
10402
10403  return !options.unwrapPromises
10404      ? function cspSafeGetter(scope, locals) {
10405          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10406
10407          if (pathVal == null) return pathVal;
10408          pathVal = pathVal[key0];
10409
10410          if (!key1) return pathVal;
10411          if (pathVal == null) return undefined;
10412          pathVal = pathVal[key1];
10413
10414          if (!key2) return pathVal;
10415          if (pathVal == null) return undefined;
10416          pathVal = pathVal[key2];
10417
10418          if (!key3) return pathVal;
10419          if (pathVal == null) return undefined;
10420          pathVal = pathVal[key3];
10421
10422          if (!key4) return pathVal;
10423          if (pathVal == null) return undefined;
10424          pathVal = pathVal[key4];
10425
10426          return pathVal;
10427        }
10428      : function cspSafePromiseEnabledGetter(scope, locals) {
10429          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10430              promise;
10431
10432          if (pathVal == null) return pathVal;
10433
10434          pathVal = pathVal[key0];
10435          if (pathVal && pathVal.then) {
10436            promiseWarning(fullExp);
10437            if (!("$$v" in pathVal)) {
10438              promise = pathVal;
10439              promise.$$v = undefined;
10440              promise.then(function(val) { promise.$$v = val; });
10441            }
10442            pathVal = pathVal.$$v;
10443          }
10444
10445          if (!key1) return pathVal;
10446          if (pathVal == null) return undefined;
10447          pathVal = pathVal[key1];
10448          if (pathVal && pathVal.then) {
10449            promiseWarning(fullExp);
10450            if (!("$$v" in pathVal)) {
10451              promise = pathVal;
10452              promise.$$v = undefined;
10453              promise.then(function(val) { promise.$$v = val; });
10454            }
10455            pathVal = pathVal.$$v;
10456          }
10457
10458          if (!key2) return pathVal;
10459          if (pathVal == null) return undefined;
10460          pathVal = pathVal[key2];
10461          if (pathVal && pathVal.then) {
10462            promiseWarning(fullExp);
10463            if (!("$$v" in pathVal)) {
10464              promise = pathVal;
10465              promise.$$v = undefined;
10466              promise.then(function(val) { promise.$$v = val; });
10467            }
10468            pathVal = pathVal.$$v;
10469          }
10470
10471          if (!key3) return pathVal;
10472          if (pathVal == null) return undefined;
10473          pathVal = pathVal[key3];
10474          if (pathVal && pathVal.then) {
10475            promiseWarning(fullExp);
10476            if (!("$$v" in pathVal)) {
10477              promise = pathVal;
10478              promise.$$v = undefined;
10479              promise.then(function(val) { promise.$$v = val; });
10480            }
10481            pathVal = pathVal.$$v;
10482          }
10483
10484          if (!key4) return pathVal;
10485          if (pathVal == null) return undefined;
10486          pathVal = pathVal[key4];
10487          if (pathVal && pathVal.then) {
10488            promiseWarning(fullExp);
10489            if (!("$$v" in pathVal)) {
10490              promise = pathVal;
10491              promise.$$v = undefined;
10492              promise.then(function(val) { promise.$$v = val; });
10493            }
10494            pathVal = pathVal.$$v;
10495          }
10496          return pathVal;
10497        };
10498}
10499
10500function simpleGetterFn1(key0, fullExp) {
10501  ensureSafeMemberName(key0, fullExp);
10502
10503  return function simpleGetterFn1(scope, locals) {
10504    if (scope == null) return undefined;
10505    return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10506  };
10507}
10508
10509function simpleGetterFn2(key0, key1, fullExp) {
10510  ensureSafeMemberName(key0, fullExp);
10511  ensureSafeMemberName(key1, fullExp);
10512
10513  return function simpleGetterFn2(scope, locals) {
10514    if (scope == null) return undefined;
10515    scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10516    return scope == null ? undefined : scope[key1];
10517  };
10518}
10519
10520function getterFn(path, options, fullExp) {
10521  // Check whether the cache has this getter already.
10522  // We can use hasOwnProperty directly on the cache because we ensure,
10523  // see below, that the cache never stores a path called 'hasOwnProperty'
10524  if (getterFnCache.hasOwnProperty(path)) {
10525    return getterFnCache[path];
10526  }
10527
10528  var pathKeys = path.split('.'),
10529      pathKeysLength = pathKeys.length,
10530      fn;
10531
10532  // When we have only 1 or 2 tokens, use optimized special case closures.
10533  // http://jsperf.com/angularjs-parse-getter/6
10534  if (!options.unwrapPromises && pathKeysLength === 1) {
10535    fn = simpleGetterFn1(pathKeys[0], fullExp);
10536  } else if (!options.unwrapPromises && pathKeysLength === 2) {
10537    fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
10538  } else if (options.csp) {
10539    if (pathKeysLength < 6) {
10540      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
10541                          options);
10542    } else {
10543      fn = function(scope, locals) {
10544        var i = 0, val;
10545        do {
10546          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
10547                                pathKeys[i++], fullExp, options)(scope, locals);
10548
10549          locals = undefined; // clear after first iteration
10550          scope = val;
10551        } while (i < pathKeysLength);
10552        return val;
10553      };
10554    }
10555  } else {
10556    var code = 'var p;\n';
10557    forEach(pathKeys, function(key, index) {
10558      ensureSafeMemberName(key, fullExp);
10559      code += 'if(s == null) return undefined;\n' +
10560              's='+ (index
10561                      // we simply dereference 's' on any .dot notation
10562                      ? 's'
10563                      // but if we are first then we check locals first, and if so read it first
10564                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
10565              (options.unwrapPromises
10566                ? 'if (s && s.then) {\n' +
10567                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
10568                  ' if (!("$$v" in s)) {\n' +
10569                    ' p=s;\n' +
10570                    ' p.$$v = undefined;\n' +
10571                    ' p.then(function(v) {p.$$v=v;});\n' +
10572                    '}\n' +
10573                  ' s=s.$$v\n' +
10574                '}\n'
10575                : '');
10576    });
10577    code += 'return s;';
10578
10579    /* jshint -W054 */
10580    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
10581    /* jshint +W054 */
10582    evaledFnGetter.toString = valueFn(code);
10583    fn = options.unwrapPromises ? function(scope, locals) {
10584      return evaledFnGetter(scope, locals, promiseWarning);
10585    } : evaledFnGetter;
10586  }
10587
10588  // Only cache the value if it's not going to mess up the cache object
10589  // This is more performant that using Object.prototype.hasOwnProperty.call
10590  if (path !== 'hasOwnProperty') {
10591    getterFnCache[path] = fn;
10592  }
10593  return fn;
10594}
10595
10596///////////////////////////////////
10597
10598/**
10599 * @ngdoc function
10600 * @name ng.$parse
10601 * @function
10602 *
10603 * @description
10604 *
10605 * Converts Angular {@link guide/expression expression} into a function.
10606 *
10607 * <pre>
10608 *   var getter = $parse('user.name');
10609 *   var setter = getter.assign;
10610 *   var context = {user:{name:'angular'}};
10611 *   var locals = {user:{name:'local'}};
10612 *
10613 *   expect(getter(context)).toEqual('angular');
10614 *   setter(context, 'newValue');
10615 *   expect(context.user.name).toEqual('newValue');
10616 *   expect(getter(context, locals)).toEqual('local');
10617 * </pre>
10618 *
10619 *
10620 * @param {string} expression String expression to compile.
10621 * @returns {function(context, locals)} a function which represents the compiled expression:
10622 *
10623 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
10624 *      are evaluated against (typically a scope object).
10625 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
10626 *      `context`.
10627 *
10628 *    The returned function also has the following properties:
10629 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
10630 *        literal.
10631 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
10632 *        constant literals.
10633 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
10634 *        set to a function to change its value on the given context.
10635 *
10636 */
10637
10638
10639/**
10640 * @ngdoc object
10641 * @name ng.$parseProvider
10642 * @function
10643 *
10644 * @description
10645 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
10646 *  service.
10647 */
10648function $ParseProvider() {
10649  var cache = {};
10650
10651  var $parseOptions = {
10652    csp: false,
10653    unwrapPromises: false,
10654    logPromiseWarnings: true
10655  };
10656
10657
10658  /**
10659   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
10660   *
10661   * @ngdoc method
10662   * @name ng.$parseProvider#unwrapPromises
10663   * @methodOf ng.$parseProvider
10664   * @description
10665   *
10666   * **This feature is deprecated, see deprecation notes below for more info**
10667   *
10668   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
10669   * found at any part of the expression. In other words, if set to true, the expression will always
10670   * result in a non-promise value.
10671   *
10672   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
10673   * the fulfillment value is used in place of the promise while evaluating the expression.
10674   *
10675   * **Deprecation notice**
10676   *
10677   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
10678   * dichotomy between data access in templates (accessed as raw values) and controller code
10679   * (accessed as promises).
10680   *
10681   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
10682   * the model access there.
10683   *
10684   * Other downsides of automatic promise unwrapping:
10685   *
10686   * - when building components it's often desirable to receive the raw promises
10687   * - adds complexity and slows down expression evaluation
10688   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
10689   *   generated
10690   * - makes IDE auto-completion and tool support hard
10691   *
10692   * **Warning Logs**
10693   *
10694   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
10695   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
10696   * `$parseProvider.logPromiseWarnings(false)` api.
10697   *
10698   *
10699   * @param {boolean=} value New value.
10700   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
10701   *                         setter.
10702   */
10703  this.unwrapPromises = function(value) {
10704    if (isDefined(value)) {
10705      $parseOptions.unwrapPromises = !!value;
10706      return this;
10707    } else {
10708      return $parseOptions.unwrapPromises;
10709    }
10710  };
10711
10712
10713  /**
10714   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
10715   *
10716   * @ngdoc method
10717   * @name ng.$parseProvider#logPromiseWarnings
10718   * @methodOf ng.$parseProvider
10719   * @description
10720   *
10721   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
10722   *
10723   * The default is set to `true`.
10724   *
10725   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
10726   *
10727   * @param {boolean=} value New value.
10728   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
10729   *                         setter.
10730   */
10731 this.logPromiseWarnings = function(value) {
10732    if (isDefined(value)) {
10733      $parseOptions.logPromiseWarnings = value;
10734      return this;
10735    } else {
10736      return $parseOptions.logPromiseWarnings;
10737    }
10738  };
10739
10740
10741  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
10742    $parseOptions.csp = $sniffer.csp;
10743
10744    promiseWarning = function promiseWarningFn(fullExp) {
10745      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
10746      promiseWarningCache[fullExp] = true;
10747      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
10748          'Automatic unwrapping of promises in Angular expressions is deprecated.');
10749    };
10750
10751    return function(exp) {
10752      var parsedExpression;
10753
10754      switch (typeof exp) {
10755        case 'string':
10756
10757          if (cache.hasOwnProperty(exp)) {
10758            return cache[exp];
10759          }
10760
10761          var lexer = new Lexer($parseOptions);
10762          var parser = new Parser(lexer, $filter, $parseOptions);
10763          parsedExpression = parser.parse(exp, false);
10764
10765          if (exp !== 'hasOwnProperty') {
10766            // Only cache the value if it's not going to mess up the cache object
10767            // This is more performant that using Object.prototype.hasOwnProperty.call
10768            cache[exp] = parsedExpression;
10769          }
10770
10771          return parsedExpression;
10772
10773        case 'function':
10774          return exp;
10775
10776        default:
10777          return noop;
10778      }
10779    };
10780  }];
10781}
10782
10783/**
10784 * @ngdoc service
10785 * @name ng.$q
10786 * @requires $rootScope
10787 *
10788 * @description
10789 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
10790 *
10791 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
10792 * interface for interacting with an object that represents the result of an action that is
10793 * performed asynchronously, and may or may not be finished at any given point in time.
10794 *
10795 * From the perspective of dealing with error handling, deferred and promise APIs are to
10796 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
10797 *
10798 * <pre>
10799 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
10800 *   // are available in the current lexical scope (they could have been injected or passed in).
10801 * 
10802 *   function asyncGreet(name) {
10803 *     var deferred = $q.defer();
10804 *
10805 *     setTimeout(function() {
10806 *       // since this fn executes async in a future turn of the event loop, we need to wrap
10807 *       // our code into an $apply call so that the model changes are properly observed.
10808 *       scope.$apply(function() {
10809 *         deferred.notify('About to greet ' + name + '.');
10810 *
10811 *         if (okToGreet(name)) {
10812 *           deferred.resolve('Hello, ' + name + '!');
10813 *         } else {
10814 *           deferred.reject('Greeting ' + name + ' is not allowed.');
10815 *         }
10816 *       });
10817 *     }, 1000);
10818 *
10819 *     return deferred.promise;
10820 *   }
10821 *
10822 *   var promise = asyncGreet('Robin Hood');
10823 *   promise.then(function(greeting) {
10824 *     alert('Success: ' + greeting);
10825 *   }, function(reason) {
10826 *     alert('Failed: ' + reason);
10827 *   }, function(update) {
10828 *     alert('Got notification: ' + update);
10829 *   });
10830 * </pre>
10831 *
10832 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
10833 * comes in the way of guarantees that promise and deferred APIs make, see
10834 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
10835 *
10836 * Additionally the promise api allows for composition that is very hard to do with the
10837 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
10838 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
10839 * section on serial or parallel joining of promises.
10840 *
10841 *
10842 * # The Deferred API
10843 *
10844 * A new instance of deferred is constructed by calling `$q.defer()`.
10845 *
10846 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
10847 * that can be used for signaling the successful or unsuccessful completion, as well as the status
10848 * of the task.
10849 *
10850 * **Methods**
10851 *
10852 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
10853 *   constructed via `$q.reject`, the promise will be rejected instead.
10854 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
10855 *   resolving it with a rejection constructed via `$q.reject`.
10856 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
10857 *   multiple times before the promise is either resolved or rejected.
10858 *
10859 * **Properties**
10860 *
10861 * - promise – `{Promise}` – promise object associated with this deferred.
10862 *
10863 *
10864 * # The Promise API
10865 *
10866 * A new promise instance is created when a deferred instance is created and can be retrieved by
10867 * calling `deferred.promise`.
10868 *
10869 * The purpose of the promise object is to allow for interested parties to get access to the result
10870 * of the deferred task when it completes.
10871 *
10872 * **Methods**
10873 *
10874 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
10875 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
10876 *   as soon as the result is available. The callbacks are called with a single argument: the result
10877 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
10878 *   provide a progress indication, before the promise is resolved or rejected.
10879 *
10880 *   This method *returns a new promise* which is resolved or rejected via the return value of the
10881 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
10882 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
10883 *   method.
10884 *
10885 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
10886 *
10887 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
10888 *   but to do so without modifying the final value. This is useful to release resources or do some
10889 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
10890 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
10891 *   more information.
10892 *
10893 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
10894 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
10895 *   make your code IE8 compatible.
10896 *
10897 * # Chaining promises
10898 *
10899 * Because calling the `then` method of a promise returns a new derived promise, it is easily
10900 * possible to create a chain of promises:
10901 *
10902 * <pre>
10903 *   promiseB = promiseA.then(function(result) {
10904 *     return result + 1;
10905 *   });
10906 *
10907 *   // promiseB will be resolved immediately after promiseA is resolved and its value
10908 *   // will be the result of promiseA incremented by 1
10909 * </pre>
10910 *
10911 * It is possible to create chains of any length and since a promise can be resolved with another
10912 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
10913 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
10914 * $http's response interceptors.
10915 *
10916 *
10917 * # Differences between Kris Kowal's Q and $q
10918 *
10919 *  There are two main differences:
10920 *
10921 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
10922 *   mechanism in angular, which means faster propagation of resolution or rejection into your
10923 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
10924 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
10925 *   all the important functionality needed for common async tasks.
10926 *
10927 *  # Testing
10928 *
10929 *  <pre>
10930 *    it('should simulate promise', inject(function($q, $rootScope) {
10931 *      var deferred = $q.defer();
10932 *      var promise = deferred.promise;
10933 *      var resolvedValue;
10934 *
10935 *      promise.then(function(value) { resolvedValue = value; });
10936 *      expect(resolvedValue).toBeUndefined();
10937 *
10938 *      // Simulate resolving of promise
10939 *      deferred.resolve(123);
10940 *      // Note that the 'then' function does not get called synchronously.
10941 *      // This is because we want the promise API to always be async, whether or not
10942 *      // it got called synchronously or asynchronously.
10943 *      expect(resolvedValue).toBeUndefined();
10944 *
10945 *      // Propagate promise resolution to 'then' functions using $apply().
10946 *      $rootScope.$apply();
10947 *      expect(resolvedValue).toEqual(123);
10948 *    }));
10949 *  </pre>
10950 */
10951function $QProvider() {
10952
10953  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
10954    return qFactory(function(callback) {
10955      $rootScope.$evalAsync(callback);
10956    }, $exceptionHandler);
10957  }];
10958}
10959
10960
10961/**
10962 * Constructs a promise manager.
10963 *
10964 * @param {function(function)} nextTick Function for executing functions in the next turn.
10965 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
10966 *     debugging purposes.
10967 * @returns {object} Promise manager.
10968 */
10969function qFactory(nextTick, exceptionHandler) {
10970
10971  /**
10972   * @ngdoc
10973   * @name ng.$q#defer
10974   * @methodOf ng.$q
10975   * @description
10976   * Creates a `Deferred` object which represents a task which will finish in the future.
10977   *
10978   * @returns {Deferred} Returns a new instance of deferred.
10979   */
10980  var defer = function() {
10981    var pending = [],
10982        value, deferred;
10983
10984    deferred = {
10985
10986      resolve: function(val) {
10987        if (pending) {
10988          var callbacks = pending;
10989          pending = undefined;
10990          value = ref(val);
10991
10992          if (callbacks.length) {
10993            nextTick(function() {
10994              var callback;
10995              for (var i = 0, ii = callbacks.length; i < ii; i++) {
10996                callback = callbacks[i];
10997                value.then(callback[0], callback[1], callback[2]);
10998              }
10999            });
11000          }
11001        }
11002      },
11003
11004
11005      reject: function(reason) {
11006        deferred.resolve(createInternalRejectedPromise(reason));
11007      },
11008
11009
11010      notify: function(progress) {
11011        if (pending) {
11012          var callbacks = pending;
11013
11014          if (pending.length) {
11015            nextTick(function() {
11016              var callback;
11017              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11018                callback = callbacks[i];
11019                callback[2](progress);
11020              }
11021            });
11022          }
11023        }
11024      },
11025
11026
11027      promise: {
11028        then: function(callback, errback, progressback) {
11029          var result = defer();
11030
11031          var wrappedCallback = function(value) {
11032            try {
11033              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11034            } catch(e) {
11035              result.reject(e);
11036              exceptionHandler(e);
11037            }
11038          };
11039
11040          var wrappedErrback = function(reason) {
11041            try {
11042              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11043            } catch(e) {
11044              result.reject(e);
11045              exceptionHandler(e);
11046            }
11047          };
11048
11049          var wrappedProgressback = function(progress) {
11050            try {
11051              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11052            } catch(e) {
11053              exceptionHandler(e);
11054            }
11055          };
11056
11057          if (pending) {
11058            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11059          } else {
11060            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11061          }
11062
11063          return result.promise;
11064        },
11065
11066        "catch": function(callback) {
11067          return this.then(null, callback);
11068        },
11069
11070        "finally": function(callback) {
11071
11072          function makePromise(value, resolved) {
11073            var result = defer();
11074            if (resolved) {
11075              result.resolve(value);
11076            } else {
11077              result.reject(value);
11078            }
11079            return result.promise;
11080          }
11081
11082          function handleCallback(value, isResolved) {
11083            var callbackOutput = null;
11084            try {
11085              callbackOutput = (callback ||defaultCallback)();
11086            } catch(e) {
11087              return makePromise(e, false);
11088            }
11089            if (callbackOutput && isFunction(callbackOutput.then)) {
11090              return callbackOutput.then(function() {
11091                return makePromise(value, isResolved);
11092              }, function(error) {
11093                return makePromise(error, false);
11094              });
11095            } else {
11096              return makePromise(value, isResolved);
11097            }
11098          }
11099
11100          return this.then(function(value) {
11101            return handleCallback(value, true);
11102          }, function(error) {
11103            return handleCallback(error, false);
11104          });
11105        }
11106      }
11107    };
11108
11109    return deferred;
11110  };
11111
11112
11113  var ref = function(value) {
11114    if (value && isFunction(value.then)) return value;
11115    return {
11116      then: function(callback) {
11117        var result = defer();
11118        nextTick(function() {
11119          result.resolve(callback(value));
11120        });
11121        return result.promise;
11122      }
11123    };
11124  };
11125
11126
11127  /**
11128   * @ngdoc
11129   * @name ng.$q#reject
11130   * @methodOf ng.$q
11131   * @description
11132   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11133   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11134   * a promise chain, you don't need to worry about it.
11135   *
11136   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11137   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11138   * a promise error callback and you want to forward the error to the promise derived from the
11139   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11140   * `reject`.
11141   *
11142   * <pre>
11143   *   promiseB = promiseA.then(function(result) {
11144   *     // success: do something and resolve promiseB
11145   *     //          with the old or a new result
11146   *     return result;
11147   *   }, function(reason) {
11148   *     // error: handle the error if possible and
11149   *     //        resolve promiseB with newPromiseOrValue,
11150   *     //        otherwise forward the rejection to promiseB
11151   *     if (canHandle(reason)) {
11152   *      // handle the error and recover
11153   *      return newPromiseOrValue;
11154   *     }
11155   *     return $q.reject(reason);
11156   *   });
11157   * </pre>
11158   *
11159   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11160   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11161   */
11162  var reject = function(reason) {
11163    var result = defer();
11164    result.reject(reason);
11165    return result.promise;
11166  };
11167
11168  var createInternalRejectedPromise = function(reason) {
11169    return {
11170      then: function(callback, errback) {
11171        var result = defer();
11172        nextTick(function() {
11173          try {
11174            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11175          } catch(e) {
11176            result.reject(e);
11177            exceptionHandler(e);
11178          }
11179        });
11180        return result.promise;
11181      }
11182    };
11183  };
11184
11185
11186  /**
11187   * @ngdoc
11188   * @name ng.$q#when
11189   * @methodOf ng.$q
11190   * @description
11191   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11192   * This is useful when you are dealing with an object that might or might not be a promise, or if
11193   * the promise comes from a source that can't be trusted.
11194   *
11195   * @param {*} value Value or a promise
11196   * @returns {Promise} Returns a promise of the passed value or promise
11197   */
11198  var when = function(value, callback, errback, progressback) {
11199    var result = defer(),
11200        done;
11201
11202    var wrappedCallback = function(value) {
11203      try {
11204        return (isFunction(callback) ? callback : defaultCallback)(value);
11205      } catch (e) {
11206        exceptionHandler(e);
11207        return reject(e);
11208      }
11209    };
11210
11211    var wrappedErrback = function(reason) {
11212      try {
11213        return (isFunction(errback) ? errback : defaultErrback)(reason);
11214      } catch (e) {
11215        exceptionHandler(e);
11216        return reject(e);
11217      }
11218    };
11219
11220    var wrappedProgressback = function(progress) {
11221      try {
11222        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11223      } catch (e) {
11224        exceptionHandler(e);
11225      }
11226    };
11227
11228    nextTick(function() {
11229      ref(value).then(function(value) {
11230        if (done) return;
11231        done = true;
11232        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11233      }, function(reason) {
11234        if (done) return;
11235        done = true;
11236        result.resolve(wrappedErrback(reason));
11237      }, function(progress) {
11238        if (done) return;
11239        result.notify(wrappedProgressback(progress));
11240      });
11241    });
11242
11243    return result.promise;
11244  };
11245
11246
11247  function defaultCallback(value) {
11248    return value;
11249  }
11250
11251
11252  function defaultErrback(reason) {
11253    return reject(reason);
11254  }
11255
11256
11257  /**
11258   * @ngdoc
11259   * @name ng.$q#all
11260   * @methodOf ng.$q
11261   * @description
11262   * Combines multiple promises into a single promise that is resolved when all of the input
11263   * promises are resolved.
11264   *
11265   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11266   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11267   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11268   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11269   *   with the same rejection value.
11270   */
11271  function all(promises) {
11272    var deferred = defer(),
11273        counter = 0,
11274        results = isArray(promises) ? [] : {};
11275
11276    forEach(promises, function(promise, key) {
11277      counter++;
11278      ref(promise).then(function(value) {
11279        if (results.hasOwnProperty(key)) return;
11280        results[key] = value;
11281        if (!(--counter)) deferred.resolve(results);
11282      }, function(reason) {
11283        if (results.hasOwnProperty(key)) return;
11284        deferred.reject(reason);
11285      });
11286    });
11287
11288    if (counter === 0) {
11289      deferred.resolve(results);
11290    }
11291
11292    return deferred.promise;
11293  }
11294
11295  return {
11296    defer: defer,
11297    reject: reject,
11298    when: when,
11299    all: all
11300  };
11301}
11302
11303/**
11304 * DESIGN NOTES
11305 *
11306 * The design decisions behind the scope are heavily favored for speed and memory consumption.
11307 *
11308 * The typical use of scope is to watch the expressions, which most of the time return the same
11309 * value as last time so we optimize the operation.
11310 *
11311 * Closures construction is expensive in terms of speed as well as memory:
11312 *   - No closures, instead use prototypical inheritance for API
11313 *   - Internal state needs to be stored on scope directly, which means that private state is
11314 *     exposed as $$____ properties
11315 *
11316 * Loop operations are optimized by using while(count--) { ... }
11317 *   - this means that in order to keep the same order of execution as addition we have to add
11318 *     items to the array at the beginning (shift) instead of at the end (push)
11319 *
11320 * Child scopes are created and removed often
11321 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11322 *
11323 * There are few watches then a lot of observers. This is why you don't want the observer to be
11324 * implemented in the same way as watch. Watch requires return of initialization function which
11325 * are expensive to construct.
11326 */
11327
11328
11329/**
11330 * @ngdoc object
11331 * @name ng.$rootScopeProvider
11332 * @description
11333 *
11334 * Provider for the $rootScope service.
11335 */
11336
11337/**
11338 * @ngdoc function
11339 * @name ng.$rootScopeProvider#digestTtl
11340 * @methodOf ng.$rootScopeProvider
11341 * @description
11342 *
11343 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11344 * assuming that the model is unstable.
11345 *
11346 * The current default is 10 iterations.
11347 *
11348 * In complex applications it's possible that the dependencies between `$watch`s will result in
11349 * several digest iterations. However if an application needs more than the default 10 digest
11350 * iterations for its model to stabilize then you should investigate what is causing the model to
11351 * continuously change during the digest.
11352 *
11353 * Increasing the TTL could have performance implications, so you should not change it without
11354 * proper justification.
11355 *
11356 * @param {number} limit The number of digest iterations.
11357 */
11358
11359
11360/**
11361 * @ngdoc object
11362 * @name ng.$rootScope
11363 * @description
11364 *
11365 * Every application has a single root {@link ng.$rootScope.Scope scope}.
11366 * All other scopes are descendant scopes of the root scope. Scopes provide separation
11367 * between the model and the view, via a mechanism for watching the model for changes.
11368 * They also provide an event emission/broadcast and subscription facility. See the
11369 * {@link guide/scope developer guide on scopes}.
11370 */
11371function $RootScopeProvider(){
11372  var TTL = 10;
11373  var $rootScopeMinErr = minErr('$rootScope');
11374  var lastDirtyWatch = null;
11375
11376  this.digestTtl = function(value) {
11377    if (arguments.length) {
11378      TTL = value;
11379    }
11380    return TTL;
11381  };
11382
11383  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11384      function( $injector,   $exceptionHandler,   $parse,   $browser) {
11385
11386    /**
11387     * @ngdoc function
11388     * @name ng.$rootScope.Scope
11389     *
11390     * @description
11391     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11392     * {@link AUTO.$injector $injector}. Child scopes are created using the
11393     * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when
11394     * compiled HTML template is executed.)
11395     *
11396     * Here is a simple scope snippet to show how you can interact with the scope.
11397     * <pre>
11398     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11399     * </pre>
11400     *
11401     * # Inheritance
11402     * A scope can inherit from a parent scope, as in this example:
11403     * <pre>
11404         var parent = $rootScope;
11405         var child = parent.$new();
11406
11407         parent.salutation = "Hello";
11408         child.name = "World";
11409         expect(child.salutation).toEqual('Hello');
11410
11411         child.salutation = "Welcome";
11412         expect(child.salutation).toEqual('Welcome');
11413         expect(parent.salutation).toEqual('Hello');
11414     * </pre>
11415     *
11416     *
11417     * @param {Object.<string, function()>=} providers Map of service factory which need to be
11418     *                                       provided for the current scope. Defaults to {@link ng}.
11419     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11420     *                              append/override services provided by `providers`. This is handy
11421     *                              when unit-testing and having the need to override a default
11422     *                              service.
11423     * @returns {Object} Newly created scope.
11424     *
11425     */
11426    function Scope() {
11427      this.$id = nextUid();
11428      this.$$phase = this.$parent = this.$$watchers =
11429                     this.$$nextSibling = this.$$prevSibling =
11430                     this.$$childHead = this.$$childTail = null;
11431      this['this'] = this.$root =  this;
11432      this.$$destroyed = false;
11433      this.$$asyncQueue = [];
11434      this.$$postDigestQueue = [];
11435      this.$$listeners = {};
11436      this.$$listenerCount = {};
11437      this.$$isolateBindings = {};
11438    }
11439
11440    /**
11441     * @ngdoc property
11442     * @name ng.$rootScope.Scope#$id
11443     * @propertyOf ng.$rootScope.Scope
11444     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11445     *   debugging.
11446     */
11447
11448
11449    Scope.prototype = {
11450      constructor: Scope,
11451      /**
11452       * @ngdoc function
11453       * @name ng.$rootScope.Scope#$new
11454       * @methodOf ng.$rootScope.Scope
11455       * @function
11456       *
11457       * @description
11458       * Creates a new child {@link ng.$rootScope.Scope scope}.
11459       *
11460       * The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and
11461       * {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the
11462       * scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}.
11463       *
11464       * {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is
11465       * desired for the scope and its child scopes to be permanently detached from the parent and
11466       * thus stop participating in model change detection and listener notification by invoking.
11467       *
11468       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
11469       *         parent scope. The scope is isolated, as it can not see parent scope properties.
11470       *         When creating widgets, it is useful for the widget to not accidentally read parent
11471       *         state.
11472       *
11473       * @returns {Object} The newly created child scope.
11474       *
11475       */
11476      $new: function(isolate) {
11477        var ChildScope,
11478            child;
11479
11480        if (isolate) {
11481          child = new Scope();
11482          child.$root = this.$root;
11483          // ensure that there is just one async queue per $rootScope and its children
11484          child.$$asyncQueue = this.$$asyncQueue;
11485          child.$$postDigestQueue = this.$$postDigestQueue;
11486        } else {
11487          ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
11488            // the name it does not become random set of chars. This will then show up as class
11489            // name in the web inspector.
11490          ChildScope.prototype = this;
11491          child = new ChildScope();
11492          child.$id = nextUid();
11493        }
11494        child['this'] = child;
11495        child.$$listeners = {};
11496        child.$$listenerCount = {};
11497        child.$parent = this;
11498        child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
11499        child.$$prevSibling = this.$$childTail;
11500        if (this.$$childHead) {
11501          this.$$childTail.$$nextSibling = child;
11502          this.$$childTail = child;
11503        } else {
11504          this.$$childHead = this.$$childTail = child;
11505        }
11506        return child;
11507      },
11508
11509      /**
11510       * @ngdoc function
11511       * @name ng.$rootScope.Scope#$watch
11512       * @methodOf ng.$rootScope.Scope
11513       * @function
11514       *
11515       * @description
11516       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
11517       *
11518       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest
11519       *   $digest()} and should return the value that will be watched. (Since
11520       *   {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the
11521       *   `watchExpression` can execute multiple times per
11522       *   {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.)
11523       * - The `listener` is called only when the value from the current `watchExpression` and the
11524       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
11525       *   see below). The inequality is determined according to
11526       *   {@link angular.equals} function. To save the value of the object for later comparison,
11527       *   the {@link angular.copy} function is used. It also means that watching complex options
11528       *   will have adverse memory and performance implications.
11529       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
11530       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
11531       *   iteration limit is 10 to prevent an infinite loop deadlock.
11532       *
11533       *
11534       * If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called,
11535       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
11536       * can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a
11537       * change is detected, be prepared for multiple calls to your listener.)
11538       *
11539       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
11540       * (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the
11541       * watcher. In rare cases, this is undesirable because the listener is called when the result
11542       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
11543       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
11544       * listener was called due to initialization.
11545       *
11546       * The example below contains an illustration of using a function as your $watch listener
11547       *
11548       *
11549       * # Example
11550       * <pre>
11551           // let's assume that scope was dependency injected as the $rootScope
11552           var scope = $rootScope;
11553           scope.name = 'misko';
11554           scope.counter = 0;
11555
11556           expect(scope.counter).toEqual(0);
11557           scope.$watch('name', function(newValue, oldValue) {
11558             scope.counter = scope.counter + 1;
11559           });
11560           expect(scope.counter).toEqual(0);
11561
11562           scope.$digest();
11563           // no variable change
11564           expect(scope.counter).toEqual(0);
11565
11566           scope.name = 'adam';
11567           scope.$digest();
11568           expect(scope.counter).toEqual(1);
11569
11570
11571
11572           // Using a listener function
11573           var food;
11574           scope.foodCounter = 0;
11575           expect(scope.foodCounter).toEqual(0);
11576           scope.$watch(
11577             // This is the listener function
11578             function() { return food; },
11579             // This is the change handler
11580             function(newValue, oldValue) {
11581               if ( newValue !== oldValue ) {
11582                 // Only increment the counter if the value changed
11583                 scope.foodCounter = scope.foodCounter + 1;
11584               }
11585             }
11586           );
11587           // No digest has been run so the counter will be zero
11588           expect(scope.foodCounter).toEqual(0);
11589
11590           // Run the digest but since food has not changed count will still be zero
11591           scope.$digest();
11592           expect(scope.foodCounter).toEqual(0);
11593
11594           // Update food and run digest.  Now the counter will increment
11595           food = 'cheeseburger';
11596           scope.$digest();
11597           expect(scope.foodCounter).toEqual(1);
11598
11599       * </pre>
11600       *
11601       *
11602       *
11603       * @param {(function()|string)} watchExpression Expression that is evaluated on each
11604       *    {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers
11605       *    a call to the `listener`.
11606       *
11607       *    - `string`: Evaluated as {@link guide/expression expression}
11608       *    - `function(scope)`: called with current `scope` as a parameter.
11609       * @param {(function()|string)=} listener Callback called whenever the return value of
11610       *   the `watchExpression` changes.
11611       *
11612       *    - `string`: Evaluated as {@link guide/expression expression}
11613       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
11614       *      parameters.
11615       *
11616       * @param {boolean=} objectEquality Compare object for equality rather than for reference.
11617       * @returns {function()} Returns a deregistration function for this listener.
11618       */
11619      $watch: function(watchExp, listener, objectEquality) {
11620        var scope = this,
11621            get = compileToFn(watchExp, 'watch'),
11622            array = scope.$$watchers,
11623            watcher = {
11624              fn: listener,
11625              last: initWatchVal,
11626              get: get,
11627              exp: watchExp,
11628              eq: !!objectEquality
11629            };
11630
11631        lastDirtyWatch = null;
11632
11633        // in the case user pass string, we need to compile it, do we really need this ?
11634        if (!isFunction(listener)) {
11635          var listenFn = compileToFn(listener || noop, 'listener');
11636          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
11637        }
11638
11639        if (typeof watchExp == 'string' && get.constant) {
11640          var originalFn = watcher.fn;
11641          watcher.fn = function(newVal, oldVal, scope) {
11642            originalFn.call(this, newVal, oldVal, scope);
11643            arrayRemove(array, watcher);
11644          };
11645        }
11646
11647        if (!array) {
11648          array = scope.$$watchers = [];
11649        }
11650        // we use unshift since we use a while loop in $digest for speed.
11651        // the while loop reads in reverse order.
11652        array.unshift(watcher);
11653
11654        return function() {
11655          arrayRemove(array, watcher);
11656          lastDirtyWatch = null;
11657        };
11658      },
11659
11660
11661      /**
11662       * @ngdoc function
11663       * @name ng.$rootScope.Scope#$watchCollection
11664       * @methodOf ng.$rootScope.Scope
11665       * @function
11666       *
11667       * @description
11668       * Shallow watches the properties of an object and fires whenever any of the properties change
11669       * (for arrays, this implies watching the array items; for object maps, this implies watching
11670       * the properties). If a change is detected, the `listener` callback is fired.
11671       *
11672       * - The `obj` collection is observed via standard $watch operation and is examined on every
11673       *   call to $digest() to see if any items have been added, removed, or moved.
11674       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
11675       *   adding, removing, and moving items belonging to an object or array.
11676       *
11677       *
11678       * # Example
11679       * <pre>
11680          $scope.names = ['igor', 'matias', 'misko', 'james'];
11681          $scope.dataCount = 4;
11682
11683          $scope.$watchCollection('names', function(newNames, oldNames) {
11684            $scope.dataCount = newNames.length;
11685          });
11686
11687          expect($scope.dataCount).toEqual(4);
11688          $scope.$digest();
11689
11690          //still at 4 ... no changes
11691          expect($scope.dataCount).toEqual(4);
11692
11693          $scope.names.pop();
11694          $scope.$digest();
11695
11696          //now there's been a change
11697          expect($scope.dataCount).toEqual(3);
11698       * </pre>
11699       *
11700       *
11701       * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
11702       *    expression value should evaluate to an object or an array which is observed on each
11703       *    {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the
11704       *    collection will trigger a call to the `listener`.
11705       *
11706       * @param {function(newCollection, oldCollection, scope)} listener a callback function that is
11707       *    fired with both the `newCollection` and `oldCollection` as parameters.
11708       *    The `newCollection` object is the newly modified data obtained from the `obj` expression
11709       *    and the `oldCollection` object is a copy of the former collection data.
11710       *    The `scope` refers to the current scope.
11711       *
11712       * @returns {function()} Returns a de-registration function for this listener. When the
11713       *    de-registration function is executed, the internal watch operation is terminated.
11714       */
11715      $watchCollection: function(obj, listener) {
11716        var self = this;
11717        var oldValue;
11718        var newValue;
11719        var changeDetected = 0;
11720        var objGetter = $parse(obj);
11721        var internalArray = [];
11722        var internalObject = {};
11723        var oldLength = 0;
11724
11725        function $watchCollectionWatch() {
11726          newValue = objGetter(self);
11727          var newLength, key;
11728
11729          if (!isObject(newValue)) {
11730            if (oldValue !== newValue) {
11731              oldValue = newValue;
11732              changeDetected++;
11733            }
11734          } else if (isArrayLike(newValue)) {
11735            if (oldValue !== internalArray) {
11736              // we are transitioning from something which was not an array into array.
11737              oldValue = internalArray;
11738              oldLength = oldValue.length = 0;
11739              changeDetected++;
11740            }
11741
11742            newLength = newValue.length;
11743
11744            if (oldLength !== newLength) {
11745              // if lengths do not match we need to trigger change notification
11746              changeDetected++;
11747              oldValue.length = oldLength = newLength;
11748            }
11749            // copy the items to oldValue and look for changes.
11750            for (var i = 0; i < newLength; i++) {
11751              if (oldValue[i] !== newValue[i]) {
11752                changeDetected++;
11753                oldValue[i] = newValue[i];
11754              }
11755            }
11756          } else {
11757            if (oldValue !== internalObject) {
11758              // we are transitioning from something which was not an object into object.
11759              oldValue = internalObject = {};
11760              oldLength = 0;
11761              changeDetected++;
11762            }
11763            // copy the items to oldValue and look for changes.
11764            newLength = 0;
11765            for (key in newValue) {
11766              if (newValue.hasOwnProperty(key)) {
11767                newLength++;
11768                if (oldValue.hasOwnProperty(key)) {
11769                  if (oldValue[key] !== newValue[key]) {
11770                    changeDetected++;
11771                    oldValue[key] = newValue[key];
11772                  }
11773                } else {
11774                  oldLength++;
11775                  oldValue[key] = newValue[key];
11776                  changeDetected++;
11777                }
11778              }
11779            }
11780            if (oldLength > newLength) {
11781              // we used to have more keys, need to find them and destroy them.
11782              changeDetected++;
11783              for(key in oldValue) {
11784                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
11785                  oldLength--;
11786                  delete oldValue[key];
11787                }
11788              }
11789            }
11790          }
11791          return changeDetected;
11792        }
11793
11794        function $watchCollectionAction() {
11795          listener(newValue, oldValue, self);
11796        }
11797
11798        return this.$watch($watchCollectionWatch, $watchCollectionAction);
11799      },
11800
11801      /**
11802       * @ngdoc function
11803       * @name ng.$rootScope.Scope#$digest
11804       * @methodOf ng.$rootScope.Scope
11805       * @function
11806       *
11807       * @description
11808       * Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and
11809       * its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change
11810       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers}
11811       * until no more listeners are firing. This means that it is possible to get into an infinite
11812       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
11813       * iterations exceeds 10.
11814       *
11815       * Usually, you don't call `$digest()` directly in
11816       * {@link ng.directive:ngController controllers} or in
11817       * {@link ng.$compileProvider#methods_directive directives}.
11818       * Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within
11819       * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
11820       *
11821       * If you want to be notified whenever `$digest()` is called,
11822       * you can register a `watchExpression` function with
11823       * {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`.
11824       *
11825       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
11826       *
11827       * # Example
11828       * <pre>
11829           var scope = ...;
11830           scope.name = 'misko';
11831           scope.counter = 0;
11832
11833           expect(scope.counter).toEqual(0);
11834           scope.$watch('name', function(newValue, oldValue) {
11835             scope.counter = scope.counter + 1;
11836           });
11837           expect(scope.counter).toEqual(0);
11838
11839           scope.$digest();
11840           // no variable change
11841           expect(scope.counter).toEqual(0);
11842
11843           scope.name = 'adam';
11844           scope.$digest();
11845           expect(scope.counter).toEqual(1);
11846       * </pre>
11847       *
11848       */
11849      $digest: function() {
11850        var watch, value, last,
11851            watchers,
11852            asyncQueue = this.$$asyncQueue,
11853            postDigestQueue = this.$$postDigestQueue,
11854            length,
11855            dirty, ttl = TTL,
11856            next, current, target = this,
11857            watchLog = [],
11858            logIdx, logMsg, asyncTask;
11859
11860        beginPhase('$digest');
11861
11862        lastDirtyWatch = null;
11863
11864        do { // "while dirty" loop
11865          dirty = false;
11866          current = target;
11867
11868          while(asyncQueue.length) {
11869            try {
11870              asyncTask = asyncQueue.shift();
11871              asyncTask.scope.$eval(asyncTask.expression);
11872            } catch (e) {
11873              clearPhase();
11874              $exceptionHandler(e);
11875            }
11876            lastDirtyWatch = null;
11877          }
11878
11879          traverseScopesLoop:
11880          do { // "traverse the scopes" loop
11881            if ((watchers = current.$$watchers)) {
11882              // process our watches
11883              length = watchers.length;
11884              while (length--) {
11885                try {
11886                  watch = watchers[length];
11887                  // Most common watches are on primitives, in which case we can short
11888                  // circuit it with === operator, only when === fails do we use .equals
11889                  if (watch) {
11890                    if ((value = watch.get(current)) !== (last = watch.last) &&
11891                        !(watch.eq
11892                            ? equals(value, last)
11893                            : (typeof value == 'number' && typeof last == 'number'
11894                               && isNaN(value) && isNaN(last)))) {
11895                      dirty = true;
11896                      lastDirtyWatch = watch;
11897                      watch.last = watch.eq ? copy(value) : value;
11898                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
11899                      if (ttl < 5) {
11900                        logIdx = 4 - ttl;
11901                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
11902                        logMsg = (isFunction(watch.exp))
11903                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
11904                            : watch.exp;
11905                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
11906                        watchLog[logIdx].push(logMsg);
11907                      }
11908                    } else if (watch === lastDirtyWatch) {
11909                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
11910                      // have already been tested.
11911                      dirty = false;
11912                      break traverseScopesLoop;
11913                    }
11914                  }
11915                } catch (e) {
11916                  clearPhase();
11917                  $exceptionHandler(e);
11918                }
11919              }
11920            }
11921
11922            // Insanity Warning: scope depth-first traversal
11923            // yes, this code is a bit crazy, but it works and we have tests to prove it!
11924            // this piece should be kept in sync with the traversal in $broadcast
11925            if (!(next = (current.$$childHead ||
11926                (current !== target && current.$$nextSibling)))) {
11927              while(current !== target && !(next = current.$$nextSibling)) {
11928                current = current.$parent;
11929              }
11930            }
11931          } while ((current = next));
11932
11933          // `break traverseScopesLoop;` takes us to here
11934
11935          if((dirty || asyncQueue.length) && !(ttl--)) {
11936            clearPhase();
11937            throw $rootScopeMinErr('infdig',
11938                '{0} $digest() iterations reached. Aborting!\n' +
11939                'Watchers fired in the last 5 iterations: {1}',
11940                TTL, toJson(watchLog));
11941          }
11942
11943        }
11943 while (dirty || asyncQueue.length);
11944
11945        clearPhase();
11946
11947        while(postDigestQueue.length) {
11948          try {
11949            postDigestQueue.shift()();
11950          } catch (e) {
11951            $exceptionHandler(e);
11952          }
11953        }
11954      },
11955
11956
11957      /**
11958       * @ngdoc event
11959       * @name ng.$rootScope.Scope#$destroy
11960       * @eventOf ng.$rootScope.Scope
11961       * @eventType broadcast on scope being destroyed
11962       *
11963       * @description
11964       * Broadcasted when a scope and its children are being destroyed.
11965       *
11966       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
11967       * clean up DOM bindings before an element is removed from the DOM.
11968       */
11969
11970      /**
11971       * @ngdoc function
11972       * @name ng.$rootScope.Scope#$destroy
11973       * @methodOf ng.$rootScope.Scope
11974       * @function
11975       *
11976       * @description
11977       * Removes the current scope (and all of its children) from the parent scope. Removal implies
11978       * that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer
11979       * propagate to the current scope and its children. Removal also implies that the current
11980       * scope is eligible for garbage collection.
11981       *
11982       * The `$destroy()` is usually used by directives such as
11983       * {@link ng.directive:ngRepeat ngRepeat} for managing the
11984       * unrolling of the loop.
11985       *
11986       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
11987       * Application code can register a `$destroy` event handler that will give it a chance to
11988       * perform any necessary cleanup.
11989       *
11990       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
11991       * clean up DOM bindings before an element is removed from the DOM.
11992       */
11993      $destroy: function() {
11994        // we can't destroy the root scope or a scope that has been already destroyed
11995        if (this.$$destroyed) return;
11996        var parent = this.$parent;
11997
11998        this.$broadcast('$destroy');
11999        this.$$destroyed = true;
12000        if (this === $rootScope) return;
12001
12002        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12003
12004        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12005        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12006        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12007        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12008
12009        // This is bogus code that works around Chrome's GC leak
12010        // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12011        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12012            this.$$childTail = null;
12013      },
12014
12015      /**
12016       * @ngdoc function
12017       * @name ng.$rootScope.Scope#$eval
12018       * @methodOf ng.$rootScope.Scope
12019       * @function
12020       *
12021       * @description
12022       * Executes the `expression` on the current scope and returns the result. Any exceptions in
12023       * the expression are propagated (uncaught). This is useful when evaluating Angular
12024       * expressions.
12025       *
12026       * # Example
12027       * <pre>
12028           var scope = ng.$rootScope.Scope();
12029           scope.a = 1;
12030           scope.b = 2;
12031
12032           expect(scope.$eval('a+b')).toEqual(3);
12033           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12034       * </pre>
12035       *
12036       * @param {(string|function())=} expression An angular expression to be executed.
12037       *
12038       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12039       *    - `function(scope)`: execute the function with the current `scope` parameter.
12040       *
12041       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12042       * @returns {*} The result of evaluating the expression.
12043       */
12044      $eval: function(expr, locals) {
12045        return $parse(expr)(this, locals);
12046      },
12047
12048      /**
12049       * @ngdoc function
12050       * @name ng.$rootScope.Scope#$evalAsync
12051       * @methodOf ng.$rootScope.Scope
12052       * @function
12053       *
12054       * @description
12055       * Executes the expression on the current scope at a later point in time.
12056       *
12057       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12058       * that:
12059       *
12060       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12061       *     rendering).
12062       *   - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after
12063       *     `expression` execution.
12064       *
12065       * Any exceptions from the execution of the expression are forwarded to the
12066       * {@link ng.$exceptionHandler $exceptionHandler} service.
12067       *
12068       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12069       * will be scheduled. However, it is encouraged to always call code that changes the model
12070       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12071       *
12072       * @param {(string|function())=} expression An angular expression to be executed.
12073       *
12074       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12075       *    - `function(scope)`: execute the function with the current `scope` parameter.
12076       *
12077       */
12078      $evalAsync: function(expr) {
12079        // if we are outside of an $digest loop and this is the first time we are scheduling async
12080        // task also schedule async auto-flush
12081        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12082          $browser.defer(function() {
12083            if ($rootScope.$$asyncQueue.length) {
12084              $rootScope.$digest();
12085            }
12086          });
12087        }
12088
12089        this.$$asyncQueue.push({scope: this, expression: expr});
12090      },
12091
12092      $$postDigest : function(fn) {
12093        this.$$postDigestQueue.push(fn);
12094      },
12095
12096      /**
12097       * @ngdoc function
12098       * @name ng.$rootScope.Scope#$apply
12099       * @methodOf ng.$rootScope.Scope
12100       * @function
12101       *
12102       * @description
12103       * `$apply()` is used to execute an expression in angular from outside of the angular
12104       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12105       * Because we are calling into the angular framework we need to perform proper scope life
12106       * cycle of {@link ng.$exceptionHandler exception handling},
12107       * {@link ng.$rootScope.Scope#methods_$digest executing watches}.
12108       *
12109       * ## Life cycle
12110       *
12111       * # Pseudo-Code of `$apply()`
12112       * <pre>
12113           function $apply(expr) {
12114             try {
12115               return $eval(expr);
12116             } catch (e) {
12117               $exceptionHandler(e);
12118             } finally {
12119               $root.$digest();
12120             }
12121           }
12122       * </pre>
12123       *
12124       *
12125       * Scope's `$apply()` method transitions through the following stages:
12126       *
12127       * 1. The {@link guide/expression expression} is executed using the
12128       *    {@link ng.$rootScope.Scope#methods_$eval $eval()} method.
12129       * 2. Any exceptions from the execution of the expression are forwarded to the
12130       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12131       * 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the
12132       *    expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method.
12133       *
12134       *
12135       * @param {(string|function())=} exp An angular expression to be executed.
12136       *
12137       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12138       *    - `function(scope)`: execute the function with current `scope` parameter.
12139       *
12140       * @returns {*} The result of evaluating the expression.
12141       */
12142      $apply: function(expr) {
12143        try {
12144          beginPhase('$apply');
12145          return this.$eval(expr);
12146        } catch (e) {
12147          $exceptionHandler(e);
12148        } finally {
12149          clearPhase();
12150          try {
12151            $rootScope.$digest();
12152          } catch (e) {
12153            $exceptionHandler(e);
12154            throw e;
12155          }
12156        }
12157      },
12158
12159      /**
12160       * @ngdoc function
12161       * @name ng.$rootScope.Scope#$on
12162       * @methodOf ng.$rootScope.Scope
12163       * @function
12164       *
12165       * @description
12166       * Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for
12167       * discussion of event life cycle.
12168       *
12169       * The event listener function format is: `function(event, args...)`. The `event` object
12170       * passed into the listener has the following attributes:
12171       *
12172       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12173       *     `$broadcast`-ed.
12174       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12175       *   - `name` - `{string}`: name of the event.
12176       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12177       *     further event propagation (available only for events that were `$emit`-ed).
12178       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12179       *     to true.
12180       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12181       *
12182       * @param {string} name Event name to listen on.
12183       * @param {function(event, args...)} listener Function to call when the event is emitted.
12184       * @returns {function()} Returns a deregistration function for this listener.
12185       */
12186      $on: function(name, listener) {
12187        var namedListeners = this.$$listeners[name];
12188        if (!namedListeners) {
12189          this.$$listeners[name] = namedListeners = [];
12190        }
12191        namedListeners.push(listener);
12192
12193        var current = this;
12194        do {
12195          if (!current.$$listenerCount[name]) {
12196            current.$$listenerCount[name] = 0;
12197          }
12198          current.$$listenerCount[name]++;
12199        } while ((current = current.$parent));
12200
12201        var self = this;
12202        return function() {
12203          namedListeners[indexOf(namedListeners, listener)] = null;
12204          decrementListenerCount(self, 1, name);
12205        };
12206      },
12207
12208
12209      /**
12210       * @ngdoc function
12211       * @name ng.$rootScope.Scope#$emit
12212       * @methodOf ng.$rootScope.Scope
12213       * @function
12214       *
12215       * @description
12216       * Dispatches an event `name` upwards through the scope hierarchy notifying the
12217       * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
12218       *
12219       * The event life cycle starts at the scope on which `$emit` was called. All
12220       * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
12221       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12222       * registered listeners along the way. The event will stop propagating if one of the listeners
12223       * cancels it.
12224       *
12225       * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
12226       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12227       *
12228       * @param {string} name Event name to emit.
12229       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12230       * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
12231       */
12232      $emit: function(name, args) {
12233        var empty = [],
12234            namedListeners,
12235            scope = this,
12236            stopPropagation = false,
12237            event = {
12238              name: name,
12239              targetScope: scope,
12240              stopPropagation: function() {stopPropagation = true;},
12241              preventDefault: function() {
12242                event.defaultPrevented = true;
12243              },
12244              defaultPrevented: false
12245            },
12246            listenerArgs = concat([event], arguments, 1),
12247            i, length;
12248
12249        do {
12250          namedListeners = scope.$$listeners[name] || empty;
12251          event.currentScope = scope;
12252          for (i=0, length=namedListeners.length; i<length; i++) {
12253
12254            // if listeners were deregistered, defragment the array
12255            if (!namedListeners[i]) {
12256              namedListeners.splice(i, 1);
12257              i--;
12258              length--;
12259              continue;
12260            }
12261            try {
12262              //allow all listeners attached to the current scope to run
12263              namedListeners[i].apply(null, listenerArgs);
12264            } catch (e) {
12265              $exceptionHandler(e);
12266            }
12267          }
12268          //if any listener on the current scope stops propagation, prevent bubbling
12269          if (stopPropagation) return event;
12270          //traverse upwards
12271          scope = scope.$parent;
12272        } while (scope);
12273
12274        return event;
12275      },
12276
12277
12278      /**
12279       * @ngdoc function
12280       * @name ng.$rootScope.Scope#$broadcast
12281       * @methodOf ng.$rootScope.Scope
12282       * @function
12283       *
12284       * @description
12285       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12286       * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
12287       *
12288       * The event life cycle starts at the scope on which `$broadcast` was called. All
12289       * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
12290       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12291       * scope and calls all registered listeners along the way. The event cannot be canceled.
12292       *
12293       * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
12294       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12295       *
12296       * @param {string} name Event name to broadcast.
12297       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12298       * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
12299       */
12300      $broadcast: function(name, args) {
12301        var target = this,
12302            current = target,
12303            next = target,
12304            event = {
12305              name: name,
12306              targetScope: target,
12307              preventDefault: function() {
12308                event.defaultPrevented = true;
12309              },
12310              defaultPrevented: false
12311            },
12312            listenerArgs = concat([event], arguments, 1),
12313            listeners, i, length;
12314
12315        //down while you can, then up and next sibling or up and next sibling until back at root
12316        while ((current = next)) {
12317          event.currentScope = current;
12318          listeners = current.$$listeners[name] || [];
12319          for (i=0, length = listeners.length; i<length; i++) {
12320            // if listeners were deregistered, defragment the array
12321            if (!listeners[i]) {
12322              listeners.splice(i, 1);
12323              i--;
12324              length--;
12325              continue;
12326            }
12327
12328            try {
12329              listeners[i].apply(null, listenerArgs);
12330            } catch(e) {
12331              $exceptionHandler(e);
12332            }
12333          }
12334
12335          // Insanity Warning: scope depth-first traversal
12336          // yes, this code is a bit crazy, but it works and we have tests to prove it!
12337          // this piece should be kept in sync with the traversal in $digest
12338          // (though it differs due to having the extra check for $$listenerCount)
12339          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12340              (current !== target && current.$$nextSibling)))) {
12341            while(current !== target && !(next = current.$$nextSibling)) {
12342              current = current.$parent;
12343            }
12344          }
12345        }
12346
12347        return event;
12348      }
12349    };
12350
12351    var $rootScope = new Scope();
12352
12353    return $rootScope;
12354
12355
12356    function beginPhase(phase) {
12357      if ($rootScope.$$phase) {
12358        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12359      }
12360
12361      $rootScope.$$phase = phase;
12362    }
12363
12364    function clearPhase() {
12365      $rootScope.$$phase = null;
12366    }
12367
12368    function compileToFn(exp, name) {
12369      var fn = $parse(exp);
12370      assertArgFn(fn, name);
12371      return fn;
12372    }
12373
12374    function decrementListenerCount(current, count, name) {
12375      do {
12376        current.$$listenerCount[name] -= count;
12377
12378        if (current.$$listenerCount[name] === 0) {
12379          delete current.$$listenerCount[name];
12380        }
12381      } while ((current = current.$parent));
12382    }
12383
12384    /**
12385     * function used as an initial value for watchers.
12386     * because it's unique we can easily tell it apart from other values
12387     */
12388    function initWatchVal() {}
12389  }];
12390}
12391
12392/**
12393 * @description
12394 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
12395 */
12396function $$SanitizeUriProvider() {
12397  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12398    imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12399
12400  /**
12401   * @description
12402   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12403   * urls during a[href] sanitization.
12404   *
12405   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12406   *
12407   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12408   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12409   * regular expression. If a match is found, the original url is 
12409written into the dom. Otherwise,
12410   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12411   *
12412   * @param {RegExp=} regexp New regexp to whitelist urls with.
12413   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12414   *    chaining otherwise.
12415   */
12416  this.aHrefSanitizationWhitelist = function(regexp) {
12417    if (isDefined(regexp)) {
12418      aHrefSanitizationWhitelist = regexp;
12419      return this;
12420    }
12421    return aHrefSanitizationWhitelist;
12422  };
12423
12424
12425  /**
12426   * @description
12427   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12428   * urls during img[src] sanitization.
12429   *
12430   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12431   *
12432   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12433   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12434   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12435   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12436   *
12437   * @param {RegExp=} regexp New regexp to whitelist urls with.
12438   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12439   *    chaining otherwise.
12440   */
12441  this.imgSrcSanitizationWhitelist = function(regexp) {
12442    if (isDefined(regexp)) {
12443      imgSrcSanitizationWhitelist = regexp;
12444      return this;
12445    }
12446    return imgSrcSanitizationWhitelist;
12447  };
12448
12449  this.$get = function() {
12450    return function sanitizeUri(uri, isImage) {
12451      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12452      var normalizedVal;
12453      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12454      if (!msie || msie >= 8 ) {
12455        normalizedVal = urlResolve(uri).href;
12456        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
12457          return 'unsafe:'+normalizedVal;
12458        }
12459      }
12460      return uri;
12461    };
12462  };
12463}
12464
12465var $sceMinErr = minErr('$sce');
12466
12467var SCE_CONTEXTS = {
12468  HTML: 'html',
12469  CSS: 'css',
12470  URL: 'url',
12471  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
12472  // url.  (e.g. ng-include, script src, templateUrl)
12473  RESOURCE_URL: 'resourceUrl',
12474  JS: 'js'
12475};
12476
12477// Helper functions follow.
12478
12479// Copied from:
12480// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
12481// Prereq: s is a string.
12482function escapeForRegexp(s) {
12483  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
12484           replace(/\x08/g, '\\x08');
12485}
12486
12487
12488function adjustMatcher(matcher) {
12489  if (matcher === 'self') {
12490    return matcher;
12491  } else if (isString(matcher)) {
12492    // Strings match exactly except for 2 wildcards - '*' and '**'.
12493    // '*' matches any character except those from the set ':/.?&'.
12494    // '**' matches any character (like .* in a RegExp).
12495    // More than 2 *'s raises an error as it's ill defined.
12496    if (matcher.indexOf('***') > -1) {
12497      throw $sceMinErr('iwcard',
12498          'Illegal sequence *** in string matcher.  String: {0}', matcher);
12499    }
12500    matcher = escapeForRegexp(matcher).
12501                  replace('\\*\\*', '.*').
12502                  replace('\\*', '[^:/.?&;]*');
12503    return new RegExp('^' + matcher + '$');
12504  } else if (isRegExp(matcher)) {
12505    // The only other type of matcher allowed is a Regexp.
12506    // Match entire URL / disallow partial matches.
12507    // Flags are reset (i.e. no global, ignoreCase or multiline)
12508    return new RegExp('^' + matcher.source + '$');
12509  } else {
12510    throw $sceMinErr('imatcher',
12511        'Matchers may only be "self", string patterns or RegExp objects');
12512  }
12513}
12514
12515
12516function adjustMatchers(matchers) {
12517  var adjustedMatchers = [];
12518  if (isDefined(matchers)) {
12519    forEach(matchers, function(matcher) {
12520      adjustedMatchers.push(adjustMatcher(matcher));
12521    });
12522  }
12523  return adjustedMatchers;
12524}
12525
12526
12527/**
12528 * @ngdoc service
12529 * @name ng.$sceDelegate
12530 * @function
12531 *
12532 * @description
12533 *
12534 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
12535 * Contextual Escaping (SCE)} services to AngularJS.
12536 *
12537 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
12538 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
12539 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
12540 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
12541 * work because `$sce` delegates to `$sceDelegate` for these operations.
12542 *
12543 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
12544 *
12545 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
12546 * can override it completely to change the behavior of `$sce`, the common case would
12547 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
12548 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
12549 * templates.  Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist
12550 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
12551 * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12552 */
12553
12554/**
12555 * @ngdoc object
12556 * @name ng.$sceDelegateProvider
12557 * @description
12558 *
12559 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
12560 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
12561 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
12562 * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
12563 * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12564 *
12565 * For the general details about this service in Angular, read the main page for {@link ng.$sce
12566 * Strict Contextual Escaping (SCE)}.
12567 *
12568 * **Example**:  Consider the following case. <a name="example"></a>
12569 *
12570 * - your app is hosted at url `http://myapp.example.com/`
12571 * - but some of your templates are hosted on other domains you control such as
12572 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
12573 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
12574 *
12575 * Here is what a secure configuration for this scenario might look like:
12576 *
12577 * <pre class="prettyprint">
12578 *    angular.module('myApp', []).config(function($sceDelegateProvider) {
12579 *      $sceDelegateProvider.resourceUrlWhitelist([
12580 *        // Allow same origin resource loads.
12581 *        'self',
12582 *        // Allow loading from our assets domain.  Notice the difference between * and **.
12583 *        'http://srv*.assets.example.com/**']);
12584 *
12585 *      // The blacklist overrides the whitelist so the open redirect here is blocked.
12586 *      $sceDelegateProvider.resourceUrlBlacklist([
12587 *        'http://myapp.example.com/clickThru**']);
12588 *      });
12589 * </pre>
12590 */
12591
12592function $SceDelegateProvider() {
12593  this.SCE_CONTEXTS = SCE_CONTEXTS;
12594
12595  // Resource URLs can also be trusted by policy.
12596  var resourceUrlWhitelist = ['self'],
12597      resourceUrlBlacklist = [];
12598
12599  /**
12600   * @ngdoc function
12601   * @name ng.sceDelegateProvider#resourceUrlWhitelist
12602   * @methodOf ng.$sceDelegateProvider
12603   * @function
12604   *
12605   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
12606   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12607   *     changes to the array are ignored.
12608   *
12609   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
12610   *     allowed in this array.
12611   *
12612   *     Note: **an empty whitelist array will block all URLs**!
12613   *
12614   * @return {Array} the currently set whitelist array.
12615   *
12616   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
12617   * same origin resource requests.
12618   *
12619   * @description
12620   * Sets/Gets the whitelist of trusted resource URLs.
12621   */
12622  this.resourceUrlWhitelist = function (value) {
12623    if (arguments.length) {
12624      resourceUrlWhitelist = adjustMatchers(value);
12625    }
12626    return resourceUrlWhitelist;
12627  };
12628
12629  /**
12630   * @ngdoc function
12631   * @name ng.sceDelegateProvider#resourceUrlBlacklist
12632   * @methodOf ng.$sceDelegateProvider
12633   * @function
12634   *
12635   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
12636   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12637   *     changes to the array are ignored.
12638   *
12639   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
12640   *     allowed in this array.
12641   *
12642   *     The typical usage for the blacklist is to **block
12643   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
12644   *     these would otherwise be trusted but actually return content from the redirected domain.
12645   *
12646   *     Finally, **the blacklist overrides the whitelist** and has the final say.
12647   *
12648   * @return {Array} the currently set blacklist array.
12649   *
12650   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
12651   * is no blacklist.)
12652   *
12653   * @description
12654   * Sets/Gets the blacklist of trusted resource URLs.
12655   */
12656
12657  this.resourceUrlBlacklist = function (value) {
12658    if (arguments.length) {
12659      resourceUrlBlacklist = adjustMatchers(value);
12660    }
12661    return resourceUrlBlacklist;
12662  };
12663
12664  this.$get = ['$injector', function($injector) {
12665
12666    var htmlSanitizer = function htmlSanitizer(html) {
12667      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
12668    };
12669
12670    if ($injector.has('$sanitize')) {
12671      htmlSanitizer = $injector.get('$sanitize');
12672    }
12673
12674
12675    function matchUrl(matcher, parsedUrl) {
12676      if (matcher === 'self') {
12677        return urlIsSameOrigin(parsedUrl);
12678      } else {
12679        // definitely a regex.  See adjustMatchers()
12680        return !!matcher.exec(parsedUrl.href);
12681      }
12682    }
12683
12684    function isResourceUrlAllowedByPolicy(url) {
12685      var parsedUrl = urlResolve(url.toString());
12686      var i, n, allowed = false;
12687      // Ensure that at least one item from the whitelist allows this url.
12688      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
12689        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
12690          allowed = true;
12691          break;
12692        }
12693      }
12694      if (allowed) {
12695        // Ensure that no item from the blacklist blocked this url.
12696        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
12697          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
12698            allowed = false;
12699            break;
12700          }
12701        }
12702      }
12703      return allowed;
12704    }
12705
12706    function generateHolderType(Base) {
12707      var holderType = function TrustedValueHolderType(trustedValue) {
12708        this.$$unwrapTrustedValue = function() {
12709          return trustedValue;
12710        };
12711      };
12712      if (Base) {
12713        holderType.prototype = new Base();
12714      }
12715      holderType.prototype.valueOf = function sceValueOf() {
12716        return this.$$unwrapTrustedValue();
12717      };
12718      holderType.prototype.toString = function sceToString() {
12719        return this.$$unwrapTrustedValue().toString();
12720      };
12721      return holderType;
12722    }
12723
12724    var trustedValueHolderBase = generateHolderType(),
12725        byType = {};
12726
12727    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
12728    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
12729    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
12730    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
12731    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
12732
12733    /**
12734     * @ngdoc method
12735     * @name ng.$sceDelegate#trustAs
12736     * @methodOf ng.$sceDelegate
12737     *
12738     * @description
12739     * Returns an object that is trusted by angular for use in specified strict
12740     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
12741     * attribute interpolation, any dom event binding attribute interpolation
12742     * such as for onclick,  etc.) that uses the provided value.
12743     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
12744     *
12745     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
12746     *   resourceUrl, html, js and css.
12747     * @param {*} value The value that that should be considered trusted/safe.
12748     * @returns {*} A value that can be used to stand in for the provided `value` in places
12749     * where Angular expects a $sce.trustAs() return value.
12750     */
12751    function trustAs(type, trustedValue) {
12752      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
12753      if (!Constructor) {
12754        throw $sceMinErr('icontext',
vendor: 5,263 bytes, lines 12755-12880
12755            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
12756            type, trustedValue);
12757      }
12758      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
12759        return trustedValue;
12760      }
12761      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
12762      // mutable objects, we ensure here that the value passed in is actually a string.
12763      if (typeof trustedValue !== 'string') {
12764        throw $sceMinErr('itype',
12765            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
12766            type);
12767      }
12768      return new Constructor(trustedValue);
12769    }
12770
12771    /**
12772     * @ngdoc method
12773     * @name ng.$sceDelegate#valueOf
12774     * @methodOf ng.$sceDelegate
12775     *
12776     * @description
12777     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs
12778     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
12779     * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.
12780     *
12781     * If the passed parameter is not a value that had been returned by {@link
12782     * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is.
12783     *
12784     * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
12785     *      call or anything else.
12786     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#methods_trustAs
12787     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
12788     *     `value` unchanged.
12789     */
12790    function valueOf(maybeTrusted) {
12791      if (maybeTrusted instanceof trustedValueHolderBase) {
12792        return maybeTrusted.$$unwrapTrustedValue();
12793      } else {
12794        return maybeTrusted;
12795      }
12796    }
12797
12798    /**
12799     * @ngdoc method
12800     * @name ng.$sceDelegate#getTrusted
12801     * @methodOf ng.$sceDelegate
12802     *
12803     * @description
12804     * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and
12805     * returns the originally supplied value if the queried context type is a supertype of the
12806     * created type.  If this condition isn't satisfied, throws an exception.
12807     *
12808     * @param {string} type The kind of context in which this value is to be used.
12809     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs
12810     *     `$sceDelegate.trustAs`} call.
12811     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
12812     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
12813     */
12814    function getTrusted(type, maybeTrusted) {
12815      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
12816        return maybeTrusted;
12817      }
12818      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
12819      if (constructor && maybeTrusted instanceof constructor) {
12820        return maybeTrusted.$$unwrapTrustedValue();
12821      }
12822      // If we get here, then we may only take one of two actions.
12823      // 1. sanitize the value for the requested type, or
12824      // 2. throw an exception.
12825      if (type === SCE_CONTEXTS.RESOURCE_URL) {
12826        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
12827          return maybeTrusted;
12828        } else {
12829          throw $sceMinErr('insecurl',
12830              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
12831              maybeTrusted.toString());
12832        }
12833      } else if (type === SCE_CONTEXTS.HTML) {
12834        return htmlSanitizer(maybeTrusted);
12835      }
12836      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
12837    }
12838
12839    return { trustAs: trustAs,
12840             getTrusted: getTrusted,
12841             valueOf: valueOf };
12842  }];
12843}
12844
12845
12846/**
12847 * @ngdoc object
12848 * @name ng.$sceProvider
12849 * @description
12850 *
12851 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
12852 * -   enable/disable Strict Contextual Escaping (SCE) in a module
12853 * -   override the default implementation with a custom delegate
12854 *
12855 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
12856 */
12857
12858/* jshint maxlen: false*/
12859
12860/**
12861 * @ngdoc service
12862 * @name ng.$sce
12863 * @function
12864 *
12865 * @description
12866 *
12867 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
12868 *
12869 * # Strict Contextual Escaping
12870 *
12871 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
12872 * contexts to result in a value that is marked as safe to use for that context.  One example of
12873 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
12874 * to these contexts as privileged or SCE contexts.
12875 *
12876 * As of version 1.2, Angular ships with SCE enabled by default.
12877 *
12878 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
12879 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
12880 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
12881 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
12882 * to the top of your HTML document.
12883 *
12884 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
12885 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
12886 *
12887 * Here's an example of a binding in a privileged context:
12888 *
12889 * <pre class="prettyprint">
12890 *     <input ng-model="userHtml">
12891 *     <div ng-bind-html="userHtml">
12892 * </pre>
12893 *
12894 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
12895 * disabled, this application allows the user to render arbitrary HTML into the DIV.
12896 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
12897 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
12898 * security vulnerabilities.)
12899 *
12900 * For the case of HTML, you might use a library, either on the client side, or on the server side,
12901 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
12902 *
12903 * How would you ensure that every place that used these types of bindings was bound to a value that
12904 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
12905 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
12906 * properties/fields and forgot to update the binding to the sanitized value?
12907 *
12908 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
12909 * determine that something explicitly says it's safe to use a value for binding in that
12910 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
12911 * for those values that you can easily tell are safe - because they were received from your server,
12912 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
12913 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
12914 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
12915 *
12916 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs} 
12917 * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to
12918 * obtain values that will be accepted by SCE / privileged contexts.
12919 *
12920 *
12921 * ## How does it work?
12922 *
12923 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted
12924 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
12925 * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
12926 * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
12927 *
12928 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
12929 * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
12930 * simplified):
12931 *
12932 * <pre class="prettyprint">
12933 *   var ngBindHtmlDirective = ['$sce', function($sce) {
12934 *     return function(scope, element, attr) {
12935 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
12936 *         element.html(value || '');
12937 *       });
12938 *     };
12939 *   }];
12940 * </pre>
12941 *
12942 * ## Impact on loading templates
12943 *
12944 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
12945 * `templateUrl`'s specified by {@link guide/directive directives}.
12946 *
12947 * By default, Angular only loads templates from the same domain and protocol as the application
12948 * document.  This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
12949 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
12950 * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist
12951 * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value.
12952 *
12953 * *Please note*:
12954 * The browser's
12955 * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
12956 * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
12957 * policy apply in addition to this and may further restrict whether the template is successfully
12958 * loaded.  This means that without the right CORS policy, loading templates from a different domain
12959 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
12960 * browsers.
12961 *
12962 * ## This feels like too much overhead for the developer?
12963 *
12964 * It's important to remember that SCE only applies to interpolation expressions.
12965 *
12966 * If your expressions are constant literals, they're automatically trusted and you don't need to
12967 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
12968 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
12969 *
12970 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
12971 * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
12972 *
12973 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
12974 * templates in `ng-include` from your application's domain without having to even know about SCE.
12975 * It blocks loading templates from other domains or loading templates over http from an https
12976 * served document.  You can change these by setting your own custom {@link
12977 * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link
12978 * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs.
12979 *
12980 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
12981 * application that's secure and can be audited to verify that with much more ease than bolting
12982 * security onto an application later.
12983 *
12984 * <a name="contexts"></a>
12985 * ## What trusted context types are supported?
12986 *
12987 * | Context             | Notes          |
12988 * |---------------------|----------------|
12989 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
12990 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
12991 * | `$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. |
12992 * | `$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. |
12993 * | `$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. |
12994 *
12995 * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
12996 *
12997 *  Each element in these arrays must be one of the following:
12998 *
12999 *  - **'self'**
13000 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13001 *      domain** as the application document using the **same protocol**.
13002 *  - **String** (except the special value `'self'`)
13003 *    - The string is matched against the full *normalized / absolute URL* of the resource
13004 *      being tested (substring matches are not good enough.)
13005 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13006 *      match themselves.
13007 *    - `*`: matches zero or more occurances of any character other than one of the following 6
13008 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13009 *      in a whitelist.
13010 *    - `**`: matches zero or more occurances of *any* character.  As such, it's not
13011 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13012 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13013 *      not have been the intention.)  It's usage at the very end of the path is ok.  (e.g.
13014 *      http://foo.example.com/templates/**).
13015 *  - **RegExp** (*see caveat below*)
13016 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13017 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13018 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13019 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13020 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13021 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13022 *      is highly recommended to use the string patterns and only fall back to regular expressions
13023 *      if they as a last resort.
13024 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13025 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13026 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13027 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13028 *    - If you are generating your JavaScript from some other templating engine (not
13029 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13030 *      remember to escape your regular expression (and be aware that you might need more than
13031 *      one level of escaping depending on your templating engine and the way you interpolated
13032 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13033 *      enough before coding your own.  e.g. Ruby has
13034 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13035 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13036 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13037 *      Closure library's [goog.string.regExpEscape(s)](
13038 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13039 *
13040 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13041 *
13042 * ## Show me an example using SCE.
13043 *
13044 * @example
13045<example module="mySceApp" deps="angular-sanitize.js">
13046<file name="index.html">
13047  <div ng-controller="myAppController as myCtrl">
13048    <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13049    <b>User comments</b><br>
13050    By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13051    $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13052    exploit.
13053    <div class="well">
13054      <div ng-repeat="userComment in myCtrl.userComments">
13055        <b>{{userComment.name}}</b>:
13056        <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13057        <br>
13058      </div>
13059    </div>
13060  </div>
13061</file>
13062
13063<file name="script.js">
13064  var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13065
13066  mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13067    var self = this;
13068    $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13069      self.userComments = userComments;
13070    });
13071    self.explicitlyTrustedHtml = $sce.trustAsHtml(
13072        '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13073        'sanitization.&quot;">Hover over this text.</span>');
13074  });
13075</file>
13076
13077<file name="test_data.json">
13078[
13079  { "name": "Alice",
13080    "htmlComment":
13081        "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13082  },
13083  { "name": "Bob",
13084    "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13085  }
13086]
13087</file>
13088
13089<file name="protractorTest.js">
13090  describe('SCE doc demo', function() {
13091    it('should sanitize untrusted values', function() {
13092      expect(element(by.css('.htmlComment')).getInnerHtml())
13093          .toBe('<span>Is <i>anyone</i> reading this?</span>');
13094    });
13095
13096    it('should NOT sanitize explicitly trusted values', function() {
13097      expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13098          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13099          'sanitization.&quot;">Hover over this text.</span>');
13100    });
13101  });
13102</file>
13103</example>
13104 *
13105 *
13106 *
13107 * ## Can I disable SCE completely?
13108 *
13109 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13110 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13111 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13112 * for cases where you have a lot of existing code that was written before SCE was introduced and
13113 * you're migrating them a module at a time.
13114 *
13115 * That said, here's how you can completely disable SCE:
13116 *
13117 * <pre class="prettyprint">
13118 *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13119 *     // Completely disable SCE.  For demonstration purposes only!
13120 *     // Do not use in new projects.
13121 *     $sceProvider.enabled(false);
13122 *   });
13123 * </pre>
13124 *
13125 */
13126/* jshint maxlen: 100 */
13127
13128function $SceProvider() {
13129  var enabled = true;
13130
13131  /**
13132   * @ngdoc function
13133   * @name ng.sceProvider#enabled
13134   * @methodOf ng.$sceProvider
13135   * @function
13136   *
13137   * @param {boolean=} value If provided, then enables/disables SCE.
13138   * @return {boolean} true if SCE is enabled, false otherwise.
13139   *
13140   * @description
13141   * Enables/disables SCE and returns the current value.
13142   */
13143  this.enabled = function (value) {
13144    if (arguments.length) {
13145      enabled = !!value;
13146    }
13147    return enabled;
13148  };
13149
13150
13151  /* Design notes on the default implementation for SCE.
13152   *
13153   * The API contract for the SCE delegate
13154   * -------------------------------------
13155   * The SCE delegate object must provide the following 3 methods:
13156   *
13157   * - trustAs(contextEnum, value)
13158   *     This method is used to tell the SCE service that the provided value is OK to use in the
13159   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13160   *     getTrusted() for a compatible contextEnum and return this value.
13161   *
13162   * - valueOf(value)
13163   *     For values that were not produced by trustAs(), return them as is.  For values that were
13164   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13165   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13166   *     such a value.
13167   *
13168   * - getTrusted(contextEnum, value)
13169   *     This function should return the a value that is safe to use in the context specified by
13170   *     contextEnum or throw and exception otherwise.
13171   *
13172   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13173   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13174   * instance, an implementation could maintain a registry of all trusted objects by context.  In
13175   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13176   * return the same object passed in if it was found in the registry under a compatible context or
13177   * throw an exception otherwise.  An implementation might only wrap values some of the time based
13178   * on some criteria.  getTrusted() might return a value and not throw an exception for special
13179   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13180   *
13181   *
13182   * A note on the inheritance model for SCE contexts
13183   * ------------------------------------------------
13184   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13185   * is purely an implementation details.
13186   *
13187   * The contract is simply this:
13188   *
13189   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13190   *     will also succeed.
13191   *
13192   * Inheritance happens to capture this in a natural way.  In some future, we
13193   * may not use inheritance anymore.  That is OK because no code outside of
13194   * sce.js and sceSpecs.js would need to be aware of this detail.
13195   */
13196
13197  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13198                $parse,   $sniffer,   $sceDelegate) {
13199    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13200    // the "expression(javascript expression)" syntax which is insecure.
13201    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13202      throw $sceMinErr('iequirks',
13203        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13204        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13205        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13206    }
13207
13208    var sce = copy(SCE_CONTEXTS);
13209
13210    /**
13211     * @ngdoc function
13212     * @name ng.sce#isEnabled
13213     * @methodOf ng.$sce
13214     * @function
13215     *
13216     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13217     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13218     *
13219     * @description
13220     * Returns a boolean indicating if SCE is enabled.
13221     */
13222    sce.isEnabled = function () {
13223      return enabled;
13224    };
13225    sce.trustAs = $sceDelegate.trustAs;
13226    sce.getTrusted = $sceDelegate.getTrusted;
13227    sce.valueOf = $sceDelegate.valueOf;
13228
13229    if (!enabled) {
13230      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13231      sce.valueOf = identity;
13232    }
13233
13234    /**
13235     * @ngdoc method
13236     * @name ng.$sce#parse
13237     * @methodOf ng.$sce
13238     *
13239     * @description
13240     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13241     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13242     * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*,
13243     * *result*)}
13244     *
13245     * @param {string} type The kind of SCE context in which this result will be used.
13246     * @param {string} expression String expression to compile.
13247     * @returns {function(context, locals)} a function which represents the compiled expression:
13248     *
13249     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13250     *      are evaluated against (typically a scope object).
13251     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13252     *      `context`.
13253     */
13254    sce.parseAs = function sceParseAs(type, expr) {
13255      var parsed = $parse(expr);
13256      if (parsed.literal && parsed.constant) {
13257        return parsed;
13258      } else {
13259        return function sceParseAsTrusted(self, locals) {
13260          return sce.getTrusted(type, parsed(self, locals));
13261        };
13262      }
13263    };
13264
13265    /**
13266     * @ngdoc method
13267     * @name ng.$sce#trustAs
13268     * @methodOf ng.$sce
13269     *
13270     * @description
13271     * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.  As such,
13272     * returns an object that is trusted by angular for use in specified strict contextual
13273     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13274     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13275     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13276     * escaping.
13277     *
13278     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13279     *   resource_url, html, js and css.
13280     * @param {*} value The value that that should be considered trusted/safe.
13281     * @returns {*} A value that can be used to stand in for the provided `value` in places
13282     * where Angular expects a $sce.trustAs() return value.
13283     */
13284
13285    /**
13286     * @ngdoc method
13287     * @name ng.$sce#trustAsHtml
13288     * @methodOf ng.$sce
13289     *
13290     * @description
13291     * Shorthand method.  `$sce.trustAsHtml(value)` →
13292     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13293     *
13294     * @param {*} value The value to trustAs.
13295     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml
13296     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13297     *     only accept expressions that are either literal constants or are the
13298     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13299     */
13300
13301    /**
13302     * @ngdoc method
13303     * @name ng.$sce#trustAsUrl
13304     * @methodOf ng.$sce
13305     *
13306     * @description
13307     * Shorthand method.  `$sce.trustAsUrl(value)` →
13308     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13309     *
13310     * @param {*} value The value to trustAs.
13311     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl
13312     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13313     *     only accept expressions that are either literal constants or are the
13314     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13315     */
13316
13317    /**
13318     * @ngdoc method
13319     * @name ng.$sce#trustAsResourceUrl
13320     * @methodOf ng.$sce
13321     *
13322     * @description
13323     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13324     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13325     *
13326     * @param {*} value The value to trustAs.
13327     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl
13328     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13329     *     only accept expressions that are either literal constants or are the return
13330     *     value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13331     */
13332
13333    /**
13334     * @ngdoc method
13335     * @name ng.$sce#trustAsJs
13336     * @methodOf ng.$sce
13337     *
13338     * @description
13339     * Shorthand method.  `$sce.trustAsJs(value)` →
13340     *     {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13341     *
13342     * @param {*} value The value to trustAs.
13343     * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs
13344     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13345     *     only accept expressions that are either literal constants or are the
13346     *     return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
13347     */
13348
13349    /**
13350     * @ngdoc method
13351     * @name ng.$sce#getTrusted
13352     * @methodOf ng.$sce
13353     *
13354     * @description
13355     * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}.  As such,
13356     * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the
13357     * originally supplied value if the queried context type is a supertype of the created type.
13358     * If this condition isn't satisfied, throws an exception.
13359     *
13360     * @param {string} type The kind of context in which this value is to be used.
13361     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`}
13362     *                         call.
13363     * @returns {*} The value the was originally provided to
13364     *              {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context.
13365     *              Otherwise, throws an exception.
13366     */
13367
13368    /**
13369     * @ngdoc method
13370     * @name ng.$sce#getTrustedHtml
13371     * @methodOf ng.$sce
13372     *
13373     * @description
13374     * Shorthand method.  `$sce.getTrustedHtml(value)` →
13375     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13376     *
13377     * @param {*} value The value to pass to `$sce.getTrusted`.
13378     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13379     */
13380
13381    /**
13382     * @ngdoc method
13383     * @name ng.$sce#getTrustedCss
13384     * @methodOf ng.$sce
13385     *
13386     * @description
13387     * Shorthand method.  `$sce.getTrustedCss(value)` →
13388     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13389     *
13390     * @param {*} value The value to pass to `$sce.getTrusted`.
13391     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13392     */
13393
13394    /**
13395     * @ngdoc method
13396     * @name ng.$sce#getTrustedUrl
13397     * @methodOf ng.$sce
13398     *
13399     * @description
13400     * Shorthand method.  `$sce.getTrustedUrl(value)` →
13401     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13402     *
13403     * @param {*} value The value to pass to `$sce.getTrusted`.
13404     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13405     */
13406
13407    /**
13408     * @ngdoc method
13409     * @name ng.$sce#getTrustedResourceUrl
13410     * @methodOf ng.$sce
13411     *
13412     * @description
13413     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
13414     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
13415     *
13416     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
13417     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
13418     */
13419
13420    /**
13421     * @ngdoc method
13422     * @name ng.$sce#getTrustedJs
13423     * @methodOf ng.$sce
13424     *
13425     * @description
13426     * Shorthand method.  `$sce.getTrustedJs(value)` →
13427     *     {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
13428     *
13429     * @param {*} value The value to pass to `$sce.getTrusted`.
13430     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
13431     */
13432
13433    /**
13434     * @ngdoc method
13435     * @name ng.$sce#parseAsHtml
13436     * @methodOf ng.$sce
13437     *
13438     * @description
13439     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
13440     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`}
13441     *
13442     * @param {string} expression String expression to compile.
13443     * @returns {function(context, locals)} a function which represents the compiled expression:
13444     *
13445     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13446     *      are evaluated against (typically a scope object).
13447     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13448     *      `context`.
13449     */
13450
13451    /**
13452     * @ngdoc method
13453     * @name ng.$sce#parseAsCss
13454     * @methodOf ng.$sce
13455     *
13456     * @description
13457     * Shorthand method.  `$sce.parseAsCss(value)` →
13458     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`}
13459     *
13460     * @param {string} expression String expression to compile.
13461     * @returns {function(context, locals)} a function which represents the compiled expression:
13462     *
13463     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13464     *      are evaluated against (typically a scope object).
13465     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13466     *      `context`.
13467     */
13468
13469    /**
13470     * @ngdoc method
13471     * @name ng.$sce#parseAsUrl
13472     * @methodOf ng.$sce
13473     *
13474     * @description
13475     * Shorthand method.  `$sce.parseAsUrl(value)` →
13476     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`}
13477     *
13478     * @param {string} expression String expression to compile.
13479     * @returns {function(context, locals)} a function which represents the compiled expression:
13480     *
13481     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13482     *      are evaluated against (typically a scope object).
13483     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13484     *      `context`.
13485     */
13486
13487    /**
13488     * @ngdoc method
13489     * @name ng.$sce#parseAsResourceUrl
13490     * @methodOf ng.$sce
13491     *
13492     * @description
13493     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
13494     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
13495     *
13496     * @param {string} expression String expression to compile.
13497     * @returns {function(context, locals)} a function which represents the compiled expression:
13498     *
13499     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13500     *      are evaluated against (typically a scope object).
13501     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13502     *      `context`.
13503     */
13504
13505    /**
13506     * @ngdoc method
13507     * @name ng.$sce#parseAsJs
13508     * @methodOf ng.$sce
13509     *
13510     * @description
13511     * Shorthand method.  `$sce.parseAsJs(value)` →
13512     *     {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`}
13513     *
13514     * @param {string} expression String expression to compile.
13515     * @returns {function(context, locals)} a function which represents the compiled expression:
13516     *
13517     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13518     *      are evaluated against (typically a scope object).
13519     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13520     *      `context`.
13521     */
13522
13523    // Shorthand delegations.
13524    var parse = sce.parseAs,
13525        getTrusted = sce.getTrusted,
13526        trustAs = sce.trustAs;
13527
13528    forEach(SCE_CONTEXTS, function (enumValue, name) {
13529      var lName = lowercase(name);
13530      sce[camelCase("parse_as_" + lName)] = function (expr) {
13531        return parse(enumValue, expr);
13532      };
13533      sce[camelCase("get_trusted_" + lName)] = function (value) {
13534        return getTrusted(enumValue, value);
13535      };
13536      sce[camelCase("trust_as_" + lName)] = function (value) {
13537        return trustAs(enumValue, value);
13538      };
13539    });
13540
13541    return sce;
13542  }];
13543}
13544
13545/**
13546 * !!! This is an undocumented "private" service !!!
13547 *
13548 * @name ng.$sniffer
13549 * @requires $window
13550 * @requires $document
13551 *
13552 * @property {boolean} history Does the browser support html5 history api ?
13553 * @property {boolean} hashchange Does the browser support hashchange event ?
13554 * @property {boolean} transitions Does the browser support CSS transition events ?
13555 * @property {boolean} animations Does the browser support CSS animation events ?
13556 *
13557 * @description
13558 * This is very simple implementation of testing browser's features.
13559 */
13560function $SnifferProvider() {
13561  this.$get = ['$window', '$document', function($window, $document) {
13562    var eventSupport = {},
13563        android =
13564          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
13565        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
13566        document = $document[0] || {},
13567        documentMode = document.documentMode,
13568        vendorPrefix,
13569        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
13570        bodyStyle = document.body && document.body.style,
13571        transitions = false,
13572        animations = false,
13573        match;
13574
13575    if (bodyStyle) {
13576      for(var prop in bodyStyle) {
13577        if(match = vendorRegex.exec(prop)) {
13578          vendorPrefix = match[0];
13579          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
13580          break;
13581        }
13582      }
13583
13584      if(!vendorPrefix) {
13585        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
13586      }
13587
13588      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
13589      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
13590
13591      if (android && (!transitions||!animations)) {
13592        transitions = isString(document.body.style.webkitTransition);
13593        animations = isString(document.body.style.webkitAnimation);
13594      }
13595    }
13596
13597
13598    return {
13599      // Android has history.pushState, but it does not update location correctly
13600      // so let's not use the history API at all.
13601      // http://code.google.com/p/android/issues/detail?id=17471
13602      // https://github.com/angular/angular.js/issues/904
13603
13604      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
13605      // so let's not use the history API also
13606      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
13607      // jshint -W018
13608      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
13609      // jshint +W018
13610      hashchange: 'onhashchange' in $window &&
13611                  // IE8 compatible mode lies
13612                  (!documentMode || documentMode > 7),
13613      hasEvent: function(event) {
13614        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
13615        // it. In particular the event is not fired when backspace or delete key are pressed or
13616        // when cut operation is performed.
13617        if (event == 'input' && msie == 9) return false;
13618
13619        if (isUndefined(eventSupport[event])) {
13620          var divElm = document.createElement('div');
13621          eventSupport[event] = 'on' + event in divElm;
13622        }
13623
13624        return eventSupport[event];
13625      },
13626      csp: csp(),
13627      vendorPrefix: vendorPrefix,
13628      transitions : transitions,
13629      animations : animations,
13630      android: android,
13631      msie : msie,
13632      msieDocumentMode: documentMode
13633    };
13634  }];
13635}
13636
13637function $TimeoutProvider() {
13638  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
13639       function($rootScope,   $browser,   $q,   $exceptionHandler) {
13640    var deferreds = {};
13641
13642
13643     /**
13644      * @ngdoc function
13645      * @name ng.$timeout
13646      * @requires $browser
13647      *
13648      * @description
13649      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
13650      * block and delegates any exceptions to
13651      * {@link ng.$exceptionHandler $exceptionHandler} service.
13652      *
13653      * The return value of registering a timeout function is a promise, which will be resolved when
13654      * the timeout is reached and the timeout function is executed.
13655      *
13656      * To cancel a timeout request, call `$timeout.cancel(promise)`.
13657      *
13658      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
13659      * synchronously flush the queue of deferred functions.
13660      *
13661      * @param {function()} fn A function, whose execution should be delayed.
13662      * @param {number=} [delay=0] Delay in milliseconds.
13663      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
13664      *   will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
13665      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
13666      *   promise will be resolved with is the return value of the `fn` function.
13667      * 
13668      */
13669    function timeout(fn, delay, invokeApply) {
13670      var deferred = $q.defer(),
13671          promise = deferred.promise,
13672          skipApply = (isDefined(invokeApply) && !invokeApply),
13673          timeoutId;
13674
13675      timeoutId = $browser.defer(function() {
13676        try {
13677          deferred.resolve(fn());
13678        } catch(e) {
13679          deferred.reject(e);
13680          $exceptionHandler(e);
13681        }
13682        finally {
13683          delete deferreds[promise.$$timeoutId];
13684        }
13685
13686        if (!skipApply) $rootScope.$apply();
13687      }, delay);
13688
13689      promise.$$timeoutId = timeoutId;
13690      deferreds[timeoutId] = deferred;
13691
13692      return promise;
13693    }
13694
13695
13696     /**
13697      * @ngdoc function
13698      * @name ng.$timeout#cancel
13699      * @methodOf ng.$timeout
13700      *
13701      * @description
13702      * Cancels a task associated with the `promise`. As a result of this, the promise will be
13703      * resolved with a rejection.
13704      *
13705      * @param {Promise=} promise Promise returned by the `$timeout` function.
13706      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
13707      *   canceled.
13708      */
13709    timeout.cancel = function(promise) {
13710      if (promise && promise.$$timeoutId in deferreds) {
13711        deferreds[promise.$$timeoutId].reject('canceled');
13712        delete deferreds[promise.$$timeoutId];
13713        return $browser.defer.cancel(promise.$$timeoutId);
13714      }
13715      return false;
13716    };
13717
13718    return timeout;
13719  }];
13720}
13721
13722// NOTE:  The usage of window and document instead of $window and $document here is
13723// deliberate.  This service depends on the specific behavior of anchor nodes created by the
13724// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
13725// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
13726// doesn't know about mocked locations and resolves URLs to the real document - which is
13727// exactly the behavior needed here.  There is little value is mocking these out for this
13728// service.
13729var urlParsingNode = document.createElement("a");
13730var originUrl = urlResolve(window.location.href, true);
13731
13732
13733/**
13734 *
13735 * Implementation Notes for non-IE browsers
13736 * ----------------------------------------
13737 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
13738 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
13739 * URL will be resolved into an absolute URL in the context of the application document.
13740 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
13741 * properties are all populated to reflect the normalized URL.  This approach has wide
13742 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
13743 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
13744 *
13745 * Implementation Notes for IE
13746 * ---------------------------
13747 * IE >
13747= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
13748 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
13749 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
13750 * work around that by performing the parsing in a 2nd step by taking a previously normalized
13751 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
13752 * properties such as protocol, hostname, port, etc.
13753 *
13754 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
13755 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
13756 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
13757 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
13758 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
13759 * method and IE < 8 is unsupported.
13760 *
13761 * References:
13762 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
13763 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
13764 *   http://url.spec.whatwg.org/#urlutils
13765 *   https://github.com/angular/angular.js/pull/2902
13766 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
13767 *
13768 * @function
13769 * @param {string} url The URL to be parsed.
13770 * @description Normalizes and parses a URL.
13771 * @returns {object} Returns the normalized URL as a dictionary.
13772 *
13773 *   | member name   | Description    |
13774 *   |---------------|----------------|
13775 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
13776 *   | protocol      | The protocol including the trailing colon                              |
13777 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
13778 *   | search        | The search params, minus the question mark                             |
13779 *   | hash          | The hash string, minus the hash symbol
13780 *   | hostname      | The hostname
13781 *   | port          | The port, without ":"
13782 *   | pathname      | The pathname, beginning with "/"
13783 *
13784 */
13785function urlResolve(url, base) {
13786  var href = url;
13787
13788  if (msie) {
13789    // Normalize before parse.  Refer Implementation Notes on why this is
13790    // done in two steps on IE.
13791    urlParsingNode.setAttribute("href", href);
13792    href = urlParsingNode.href;
13793  }
13794
13795  urlParsingNode.setAttribute('href', href);
13796
13797  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
13798  return {
13799    href: urlParsingNode.href,
13800    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
13801    host: urlParsingNode.host,
13802    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
13803    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
13804    hostname: urlParsingNode.hostname,
13805    port: urlParsingNode.port,
13806    pathname: (urlParsingNode.pathname.charAt(0) === '/')
13807      ? urlParsingNode.pathname
13808      : '/' + urlParsingNode.pathname
13809  };
13810}
13811
13812/**
13813 * Parse a request URL and determine whether this is a same-origin request as the application document.
13814 *
13815 * @param {string|object} requestUrl The url of the request as a string that will be resolved
13816 * or a parsed URL object.
13817 * @returns {boolean} Whether the request is for the same origin as the application document.
13818 */
13819function urlIsSameOrigin(requestUrl) {
13820  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
13821  return (parsed.protocol === originUrl.protocol &&
13822          parsed.host === originUrl.host);
13823}
13824
13825/**
13826 * @ngdoc object
13827 * @name ng.$window
13828 *
13829 * @description
13830 * A reference to the browser's `window` object. While `window`
13831 * is globally available in JavaScript, it causes testability problems, because
13832 * it is a global variable. In angular we always refer to it through the
13833 * `$window` service, so it may be overridden, removed or mocked for testing.
13834 *
13835 * Expressions, like the one defined for the `ngClick` directive in the example
13836 * below, are evaluated with respect to the current scope.  Therefore, there is
13837 * no risk of inadvertently coding in a dependency on a global value in such an
13838 * expression.
13839 *
13840 * @example
13841   <doc:example>
13842     <doc:source>
13843       <script>
13844         function Ctrl($scope, $window) {
13845           $scope.greeting = 'Hello, World!';
13846           $scope.doGreeting = function(greeting) {
13847               $window.alert(greeting);
13848           };
13849         }
13850       </script>
13851       <div ng-controller="Ctrl">
13852         <input type="text" ng-model="greeting" />
13853         <button ng-click="doGreeting(greeting)">ALERT</button>
13854       </div>
13855     </doc:source>
13856     <doc:protractor>
13857      it('should display the greeting in the input box', function() {
13858       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
13859       // If we click the button it will block the test runner
13860       // element(':button').click();
13861      });
13862     </doc:protractor>
13863   </doc:example>
13864 */
13865function $WindowProvider(){
13866  this.$get = valueFn(window);
13867}
13868
13869/**
13870 * @ngdoc object
13871 * @name ng.$filterProvider
13872 * @description
13873 *
13874 * Filters are just functions which transform input to an output. However filters need to be
13875 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
13876 * annotated with dependencies and is responsible for creating a filter function.
13877 *
13878 * <pre>
13879 *   // Filter registration
13880 *   function MyModule($provide, $filterProvider) {
13881 *     // create a service to demonstrate injection (not always needed)
13882 *     $provide.value('greet', function(name){
13883 *       return 'Hello ' + name + '!';
13884 *     });
13885 *
13886 *     // register a filter factory which uses the
13887 *     // greet service to demonstrate DI.
13888 *     $filterProvider.register('greet', function(greet){
13889 *       // return the filter function which uses the greet service
13890 *       // to generate salutation
13891 *       return function(text) {
13892 *         // filters need to be forgiving so check input validity
13893 *         return text && greet(text) || text;
13894 *       };
13895 *     });
13896 *   }
13897 * </pre>
13898 *
13899 * The filter function is registered with the `$injector` under the filter name suffix with
13900 * `Filter`.
13901 * 
13902 * <pre>
13903 *   it('should be the same instance', inject(
13904 *     function($filterProvider) {
13905 *       $filterProvider.register('reverse', function(){
13906 *         return ...;
13907 *       });
13908 *     },
13909 *     function($filter, reverseFilter) {
13910 *       expect($filter('reverse')).toBe(reverseFilter);
13911 *     });
13912 * </pre>
13913 *
13914 *
13915 * For more information about how angular filters work, and how to create your own filters, see
13916 * {@link guide/filter Filters} in the Angular Developer Guide.
13917 */
13918/**
13919 * @ngdoc method
13920 * @name ng.$filterProvider#register
13921 * @methodOf ng.$filterProvider
13922 * @description
13923 * Register filter factory function.
13924 *
13925 * @param {String} name Name of the filter.
13926 * @param {function} fn The filter factory function which is injectable.
13927 */
13928
13929
13930/**
13931 * @ngdoc function
13932 * @name ng.$filter
13933 * @function
13934 * @description
13935 * Filters are used for formatting data displayed to the user.
13936 *
13937 * The general syntax in templates is as follows:
13938 *
13939 *         {{ expression [| filter_name[:parameter_value] ... ] }}
13940 *
13941 * @param {String} name Name of the filter function to retrieve
13942 * @return {Function} the filter function
13943 */
13944$FilterProvider.$inject = ['$provide'];
13945function $FilterProvider($provide) {
13946  var suffix = 'Filter';
13947
13948  /**
13949   * @ngdoc function
13950   * @name ng.$controllerProvider#register
13951   * @methodOf ng.$controllerProvider
13952   * @param {string|Object} name Name of the filter function, or an object map of filters where
13953   *    the keys are the filter names and the values are the filter factories.
13954   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
13955   *    of the registered filter instances.
13956   */
13957  function register(name, factory) {
13958    if(isObject(name)) {
13959      var filters = {};
13960      forEach(name, function(filter, key) {
13961        filters[key] = register(key, filter);
13962      });
13963      return filters;
13964    } else {
13965      return $provide.factory(name + suffix, factory);
13966    }
13967  }
13968  this.register = register;
13969
13970  this.$get = ['$injector', function($injector) {
13971    return function(name) {
13972      return $injector.get(name + suffix);
13973    };
13974  }];
13975
13976  ////////////////////////////////////////
13977  
13978  /* global
13979    currencyFilter: false,
13980    dateFilter: false,
13981    filterFilter: false,
13982    jsonFilter: false,
13983    limitToFilter: false,
13984    lowercaseFilter: false,
13985    numberFilter: false,
13986    orderByFilter: false,
13987    uppercaseFilter: false,
13988  */
13989
13990  register('currency', currencyFilter);
13991  register('date', dateFilter);
13992  register('filter', filterFilter);
13993  register('json', jsonFilter);
13994  register('limitTo', limitToFilter);
13995  register('lowercase', lowercaseFilter);
13996  register('number', numberFilter);
13997  register('orderBy', orderByFilter);
13998  register('uppercase', uppercaseFilter);
13999}
14000
14001/**
14002 * @ngdoc filter
14003 * @name ng.filter:filter
14004 * @function
14005 *
14006 * @description
14007 * Selects a subset of items from `array` and returns it as a new array.
14008 *
14009 * @param {Array} array The source array.
14010 * @param {string|Object|function()} expression The predicate to be used for selecting items from
14011 *   `array`.
14012 *
14013 *   Can be one of:
14014 *
14015 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14016 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14017 *     will be returned. The predicate can be negated by prefixing the string with `!`.
14018 *
14019 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14020 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14021 *     which have property `name` containing "M" and property `phone` containing "1". A special
14022 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14023 *     property of the object. That's equivalent to the simple substring match with a `string`
14024 *     as described above.
14025 *
14026 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14027 *     called for each element of `array`. The final result is an array of those elements that
14028 *     the predicate returned true for.
14029 *
14030 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14031 *     determining if the expected value (from the filter expression) and actual value (from
14032 *     the object in the array) should be considered a match.
14033 *
14034 *   Can be one of:
14035 *
14036 *     - `function(actual, expected)`:
14037 *       The function will be given the object value and the predicate value to compare and
14038 *       should return true if the item should be included in filtered result.
14039 *
14040 *     - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14041 *       this is essentially strict comparison of expected and actual.
14042 *
14043 *     - `false|undefined`: A short hand for a function which will look for a substring match in case
14044 *       insensitive way.
14045 *
14046 * @example
14047   <doc:example>
14048     <doc:source>
14049       <div ng-init="friends = [{name:'John', phone:'555-1276'},
14050                                {name:'Mary', phone:'800-BIG-MARY'},
14051                                {name:'Mike', phone:'555-4321'},
14052                                {name:'Adam', phone:'555-5678'},
14053                                {name:'Julie', phone:'555-8765'},
14054                                {name:'Juliette', phone:'555-5678'}]"></div>
14055
14056       Search: <input ng-model="searchText">
14057       <table id="searchTextResults">
14058         <tr><th>Name</th><th>Phone</th></tr>
14059         <tr ng-repeat="friend in friends | filter:searchText">
14060           <td>{{friend.name}}</td>
14061           <td>{{friend.phone}}</td>
14062         </tr>
14063       </table>
14064       <hr>
14065       Any: <input ng-model="search.$"> <br>
14066       Name only <input ng-model="search.name"><br>
14067       Phone only <input ng-model="search.phone"><br>
14068       Equality <input type="checkbox" ng-model="strict"><br>
14069       <table id="searchObjResults">
14070         <tr><th>Name</th><th>Phone</th></tr>
14071         <tr ng-repeat="friendObj in friends | filter:search:strict">
14072           <td>{{friendObj.name}}</td>
14073           <td>{{friendObj.phone}}</td>
14074         </tr>
14075       </table>
14076     </doc:source>
14077     <doc:protractor>
14078       var expectFriendNames = function(expectedNames, key) {
14079         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14080           arr.forEach(function(wd, i) {
14081             expect(wd.getText()).toMatch(expectedNames[i]);
14082           });
14083         });
14084       };
14085
14086       it('should search across all fields when filtering with a string', function() {
14087         var searchText = element(by.model('searchText'));
14088         searchText.clear();
14089         searchText.sendKeys('m');
14090         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14091
14092         searchText.clear();
14093         searchText.sendKeys('76');
14094         expectFriendNames(['John', 'Julie'], 'friend');
14095       });
14096
14097       it('should search in specific fields when filtering with a predicate object', function() {
14098         var searchAny = element(by.model('search.$'));
14099         searchAny.clear();
14100         searchAny.sendKeys('i');
14101         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14102       });
14103       it('should use a equal comparison when comparator is true', function() {
14104         var searchName = element(by.model('search.name'));
14105         var strict = element(by.model('strict'));
14106         searchName.clear();
14107         searchName.sendKeys('Julie');
14108         strict.click();
14109         expectFriendNames(['Julie'], 'friendObj');
14110       });
14111     </doc:protractor>
14112   </doc:example>
14113 */
14114function filterFilter() {
14115  return function(array, expression, comparator) {
14116    if (!isArray(array)) return array;
14117
14118    var comparatorType = typeof(comparator),
14119        predicates = [];
14120
14121    predicates.check = function(value) {
14122      for (var j = 0; j < predicates.length; j++) {
14123        if(!predicates[j](value)) {
14124          return false;
14125        }
14126      }
14127      return true;
14128    };
14129
14130    if (comparatorType !== 'function') {
14131      if (comparatorType === 'boolean' && comparator) {
14132        comparator = function(obj, text) {
14133          return angular.equals(obj, text);
14134        };
14135      } else {
14136        comparator = function(obj, text) {
14137          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14138            for (var objKey in obj) {
14139              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14140                  comparator(obj[objKey], text[objKey])) {
14141                return true;
14142              }
14143            }
14144            return false;
14145          }
14146          text = (''+text).toLowerCase();
14147          return (''+obj).toLowerCase().indexOf(text) > -1;
14148        };
14149      }
14150    }
14151
14152    var search = function(obj, text){
14153      if (typeof text == 'string' && text.charAt(0) === '!') {
14154        return !search(obj, text.substr(1));
14155      }
14156      switch (typeof obj) {
14157        case "boolean":
14158        case "number":
14159        case "string":
14160          return comparator(obj, text);
14161        case "object":
14162          switch (typeof text) {
14163            case "object":
14164              return comparator(obj, text);
14165            default:
14166              for ( var objKey in obj) {
14167                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14168                  return true;
14169                }
14170              }
14171              break;
14172          }
14173          return false;
14174        case "array":
14175          for ( var i = 0; i < obj.length; i++) {
14176            if (search(obj[i], text)) {
14177              return true;
14178            }
14179          }
14180          return false;
14181        default:
14182          return false;
14183      }
14184    };
14185    switch (typeof expression) {
14186      case "boolean":
14187      case "number":
14188      case "string":
14189        // Set up expression object and fall through
14190        expression = {$:expression};
14191        // jshint -W086
14192      case "object":
14193        // jshint +W086
14194        for (var key in expression) {
14195          (function(path) {
14196            if (typeof expression[path] == 'undefined') return;
14197            predicates.push(function(value) {
14198              return search(path == '$' ? value : (value && value[path]), expression[path]);
14199            });
14200          })(key);
14201        }
14202        break;
14203      case 'function':
14204        predicates.push(expression);
14205        break;
14206      default:
14207        return array;
14208    }
14209    var filtered = [];
14210    for ( var j = 0; j < array.length; j++) {
14211      var value = array[j];
14212      if (predicates.check(value)) {
14213        filtered.push(value);
14214      }
14215    }
14216    return filtered;
14217  };
14218}
14219
14220/**
14221 * @ngdoc filter
14222 * @name ng.filter:currency
14223 * @function
14224 *
14225 * @description
14226 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14227 * symbol for current locale is used.
14228 *
14229 * @param {number} amount Input to filter.
14230 * @param {string=} symbol Currency symbol or identifier to be displayed.
14231 * @returns {string} Formatted number.
14232 *
14233 *
14234 * @example
14235   <doc:example>
14236     <doc:source>
14237       <script>
14238         function Ctrl($scope) {
14239           $scope.amount = 1234.56;
14240         }
14241       </script>
14242       <div ng-controller="Ctrl">
14243         <input type="number" ng-model="amount"> <br>
14244         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14245         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14246       </div>
14247     </doc:source>
14248     <doc:protractor>
14249       it('should init with 1234.56', function() {
14250         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14251         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14252       });
14253       it('should update', function() {
14254         if (browser.params.browser == 'safari') {
14255           // Safari does not understand the minus key. See
14256           // https://github.com/angular/protractor/issues/481
14257           return;
14258         }
14259         element(by.model('amount')).clear();
14260         element(by.model('amount')).sendKeys('-1234');
14261         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14262         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14263       });
14264     </doc:protractor>
14265   </doc:example>
14266 */
14267currencyFilter.$inject = ['$locale'];
14268function currencyFilter($locale) {
14269  var formats = $locale.NUMBER_FORMATS;
14270  return function(amount, currencySymbol){
14271    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14272    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14273                replace(/\u00A4/g, currencySymbol);
14274  };
14275}
14276
14277/**
14278 * @ngdoc filter
14279 * @name ng.filter:number
14280 * @function
14281 *
14282 * @description
14283 * Formats a number as text.
14284 *
14285 * If the input is not a number an empty string is returned.
14286 *
14287 * @param {number|string} number Number to format.
14288 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14289 * If this is not provided then the fraction size is computed from the current locale's number
14290 * formatting pattern. In the case of the default locale, it will be 3.
14291 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14292 *
14293 * @example
14294   <doc:example>
14295     <doc:source>
14296       <script>
14297         function Ctrl($scope) {
14298           $scope.val = 1234.56789;
14299         }
14300       </script>
14301       <div ng-controller="Ctrl">
14302         Enter number: <input ng-model='val'><br>
14303         Default formatting: <span id='number-default'>{{val | number}}</span><br>
14304         No fractions: <span>{{val | number:0}}</span><br>
14305         Negative number: <span>{{-val | number:4}}</span>
14306       </div>
14307     </doc:source>
14308     <doc:protractor>
14309       it('should format numbers', function() {
14310         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14311         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14312         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14313       });
14314
14315       it('should update', function() {
14316         element(by.model('val')).clear();
14317         element(by.model('val')).sendKeys('3374.333');
14318         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14319         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14320         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14321      });
14322     </doc:protractor>
14323   </doc:example>
14324 */
14325
14326
14327numberFilter.$inject = ['$locale'];
14328function numberFilter($locale) {
14329  var formats = $locale.NUMBER_FORMATS;
14330  return function(number, fractionSize) {
14331    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14332      fractionSize);
14333  };
14334}
14335
14336var DECIMAL_SEP = '.';
14337function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14338  if (isNaN(number) || !isFinite(number)) return '';
14339
14340  var isNegative = number < 0;
14341  number = Math.abs(number);
14342  var numStr = number + '',
14343      formatedText = '',
14344      parts = [];
14345
14346  var hasExponent = false;
14347  if (numStr.indexOf('e') !== -1) {
14348    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14349    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14350      numStr = '0';
14351    } else {
14352      formatedText = numStr;
14353      hasExponent = true;
14354    }
14355  }
14356
14357  if (!hasExponent) {
14358    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14359
14360    // determine fractionSize if it is not specified
14361    if (isUndefined(fractionSize)) {
14362      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14363    }
14364
14365    var pow = Math.pow(10, fractionSize);
14366    number = Math.round(number * pow) / pow;
14367    var fraction = ('' + number).split(DECIMAL_SEP);
14368    var whole = fraction[0];
14369    fraction = fraction[1] || '';
14370
14371    var i, pos = 0,
14372        lgroup = pattern.lgSize,
14373        group = pattern.gSize;
14374
14375    if (whole.length >= (lgroup + group)) {
14376      pos = whole.length - lgroup;
14377      for (i = 0; i < pos; i++) {
14378        if ((pos - i)%group === 0 && i !== 0) {
14379          formatedText += groupSep;
14380        }
14381        formatedText += whole.charAt(i);
14382      }
14383    }
14384
14385    for (i = pos; i < whole.length; i++) {
14386      if ((whole.length - i)%lgroup === 0 && i !== 0) {
14387        formatedText += groupSep;
14388      }
14389      formatedText += whole.charAt(i);
14390    }
14391
14392    // format fraction part.
14393    while(fraction.length < fractionSize) {
14394      fraction += '0';
14395    }
14396
14397    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
14398  } else {
14399
14400    if (fractionSize > 0 && number > -1 && number < 1) {
14401      formatedText = number.toFixed(fractionSize);
14402    }
14403  }
14404
14405  parts.push(isNegative ? pattern.negPre : pattern.posPre);
14406  parts.push(formatedText);
14407  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
14408  return parts.join('');
14409}
14410
14411function padNumber(num, digits, trim) {
14412  var neg = '';
14413  if (num < 0) {
14414    neg =  '-';
14415    num = -num;
14416  }
14417  num = '' + num;
14418  while(num.length < digits) num = '0' + num;
14419  if (trim)
14420    num = num.substr(num.length - digits);
14421  return neg + num;
14422}
14423
14424
14425function dateGetter(name, size, offset, trim) {
14426  offset = offset || 0;
14427  return function(date) {
14428    var value = date['get' + name]();
14429    if (offset > 0 || value > -offset)
14430      value += offset;
14431    if (value === 0 && offset == -12 ) value = 12;
14432    return padNumber(value, size, trim);
14433  };
14434}
14435
14436function dateStrGetter(name, shortForm) {
14437  return function(date, formats) {
14438    var value = date['get' + name]();
14439    var get = uppercase(shortForm ? ('SHORT' + name) : name);
14440
14441    return formats[get][value];
14442  };
14443}
14444
14445function timeZoneGetter(date) {
14446  var zone = -1 * date.getTimezoneOffset();
14447  var paddedZone = (zone >= 0) ? "+" : "";
14448
14449  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
14450                padNumber(Math.abs(zone % 60), 2);
14451
14452  return paddedZone;
14453}
14454
14455function ampmGetter(date, formats) {
14456  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
14457}
14458
14459var DATE_FORMATS = {
14460  yyyy: dateGetter('FullYear', 4),
14461    yy: dateGetter('FullYear', 2, 0, true),
14462     y: dateGetter('FullYear', 1),
14463  MMMM: dateStrGetter('Month'),
14464   MMM: dateStrGetter('Month', true),
14465    MM: dateGetter('Month', 2, 1),
14466     M: dateGetter('Month', 1, 1),
14467    dd: dateGetter('Date', 2),
14468     d: dateGetter('Date', 1),
14469    HH: dateGetter('Hours', 2),
14470     H: dateGetter('Hours', 1),
14471    hh: dateGetter('Hours', 2, -12),
14472     h: dateGetter('Hours', 1, -12),
14473    mm: dateGetter('Minutes', 2),
14474     m: dateGetter('Minutes', 1),
14475    ss: dateGetter('Seconds', 2),
14476     s: dateGetter('Seconds', 1),
14477     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
14478     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
14479   sss: dateGetter('Milliseconds', 3),
14480  EEEE: dateStrGetter('Day'),
14481   EEE: dateStrGetter('Day', true),
14482     a: ampmGetter,
14483     Z: timeZoneGetter
14484};
14485
14486var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
14487    NUMBER_STRING = /^\-?\d+$/;
14488
14489/**
14490 * @ngdoc filter
14491 * @name ng.filter:date
14492 * @function
14493 *
14494 * @description
14495 *   Formats `date` to a string based on the requested `format`.
14496 *
14497 *   `format` string can be composed of the following elements:
14498 *
14499 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
14500 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
14501 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
14502 *   * `'MMMM'`: Month in year (January-December)
14503 *   * `'MMM'`: Month in year (Jan-Dec)
14504 *   * `'MM'`: Month in year, padded (01-12)
14505 *   * `'M'`: Month in year (1-12)
14506 *   * `'dd'`: Day in month, padded (01-31)
14507 *   * `'d'`: Day in month (1-31)
14508 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
14509 *   * `'EEE'`: Day in Week, (Sun-Sat)
14510 *   * `'HH'`: Hour in day, padded (00-23)
14511 *   * `'H'`: Hour in day (0-23)
14512 *   * `'hh'`: Hour in am/pm, padded (01-12)
14513 *   * `'h'`: Hour in am/pm, (1-12)
14514 *   * `'mm'`: Minute in hour, padded (00-59)
14515 *   * `'m'`: Minute in hour (0-59)
14516 *   * `'ss'`: Second in minute, padded (00-59)
14517 *   * `'s'`: Second in minute (0-59)
14518 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
14519 *   * `'a'`: am/pm marker
14520 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
14521 *
14522 *   `format` string can also be one of the following predefined
14523 *   {@link guide/i18n localizable formats}:
14524 *
14525 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
14526 *     (e.g. Sep 3, 2010 12:05:08 pm)
14527 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
14528 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
14529 *     (e.g. Friday, September 3, 2010)
14530 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
14531 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
14532 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
14533 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
14534 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
14535 *
14536 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
14537 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
14538 *   (e.g. `"h 'o''clock'"`).
14539 *
14540 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
14541 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
14542 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
14543 *    specified in the string input, the time is considered to be in the local timezone.
14544 * @param {string=} format Formatting rules (see Description). If not specified,
14545 *    `mediumDate` is used.
14546 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
14547 *
14548 * @example
14549   <doc:example>
14550     <doc:source>
14551       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
14552           <span>{{1288323623006 | date:'medium'}}</span><br>
14553       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
14554          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
14555       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
14556          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
14557     </doc:source>
14558     <doc:protractor>
14559       it('should format date', function() {
14560         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
14561            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
14562         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
14563            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
14564         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
14565            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
14566       });
14567     </doc:protractor>
14568   </doc:example>
14569 */
14570dateFilter.$inject = ['$locale'];
14571function dateFilter($locale) {
14572
14573
14574  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
14575                     // 1        2       3         4          5          6          7          8  9     10      11
14576  function jsonStringToDate(string) {
14577    var match;
14578    if (match = string.match(R_ISO8601_STR)) {
14579      var date = new Date(0),
14580          tzHour = 0,
14581          tzMin  = 0,
14582          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
14583          timeSetter = match[8] ? date.setUTCHours : date.setHours;
14584
14585      if (match[9]) {
14586        tzHour = int(match[9] + match[10]);
14587        tzMin = int(match[9] + match[11]);
14588      }
14589      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
14590      var h = int(match[4]||0) - tzHour;
14591      var m = int(match[5]||0) - tzMin;
14592      var s = int(match[6]||0);
14593      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
14594      timeSetter.call(date, h, m, s, ms);
14595      return date;
14596    }
14597    return string;
14598  }
14599
14600
14601  return function(date, format) {
14602    var text = '',
14603        parts = [],
14604        fn, match;
14605
14606    format = format || 'mediumDate';
14607    format = $locale.DATETIME_FORMATS[format] || format;
14608    if (isString(date)) {
14609      if (NUMBER_STRING.test(date)) {
14610        date = int(date);
14611      } else {
14612        date = jsonStringToDate(date);
14613      }
14614    }
14615
14616    if (isNumber(date)) {
14617      date = new Date(date);
14618    }
14619
14620    if (!isDate(date)) {
14621      return date;
14622    }
14623
14624    while(format) {
14625      match = DATE_FORMATS_SPLIT.exec(format);
14626      if (match) {
14627        parts = concat(parts, match, 1);
14628        format = parts.pop();
14629      } else {
14630        parts.push(format);
14631        format = null;
14632      }
14633    }
14634
14635    forEach(parts, function(value){
14636      fn = DATE_FORMATS[value];
14637      text += fn ? fn(date, $locale.DATETIME_FORMATS)
14638                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
14639    });
14640
14641    return text;
14642  };
14643}
14644
14645
14646/**
14647 * @ngdoc filter
14648 * @name ng.filter:json
14649 * @function
14650 *
14651 * @description
14652 *   Allows you to convert a JavaScript object into JSON string.
14653 *
14654 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
14655 *   the binding is automatically converted to JSON.
14656 *
14657 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
14658 * @returns {string} JSON string.
14659 *
14660 *
14661 * @example:
14662   <doc:example>
14663     <doc:source>
14664       <pre>{{ {'name':'value'} | json }}</pre>
14665     </doc:source>
14666     <doc:protractor>
14667       it('should jsonify filtered objects', function() {
14668         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
14669       });
14670     </doc:protractor>
14671   </doc:example>
14672 *
14673 */
14674function jsonFilter() {
14675  return function(object) {
14676    return toJson(object, true);
14677  };
14678}
14679
14680
14681/**
14682 * @ngdoc filter
14683 * @name ng.filter:lowercase
14684 * @function
14685 * @description
14686 * Converts string to lowercase.
14687 * @see angular.lowercase
14688 */
14689var lowercaseFilter = valueFn(lowercase);
14690
14691
14692/**
14693 * @ngdoc filter
14694 * @name ng.filter:uppercase
14695 * @function
14696 * @description
14697 * Converts string to uppercase.
14698 * @see angular.uppercase
14699 */
14700var uppercaseFilter = valueFn(uppercase);
14701
14702/**
14703 * @ngdoc function
14704 * @name ng.filter:limitTo
14705 * @function
14706 *
14707 * @description
14708 * Creates a new array or string containing only a specified number of elements. The elements
14709 * are taken from either the beginning or the end of the source array or string, as specified by
14710 * the value and sign (positive or negative) of `limit`.
14711 *
14712 * @param {Array|string} input Source array or string to be limited.
14713 * @param {string|number} limit The length of the returned array or string. If the `limit` number 
14714 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
14715 *     If the number is negative, `limit` number  of items from the end of the source array/string 
14716 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
14717 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
14718 *     had less than `limit` elements.
14719 *
14720 * @example
14721   <doc:example>
14722     <doc:source>
14723       <script>
14724         function Ctrl($scope) {
14725           $scope.numbers = [1,2,3,4,5,6,7,8,9];
14726           $scope.letters = "abcdefghi";
14727           $scope.numLimit = 3;
14728           $scope.letterLimit = 3;
14729         }
14730       </script>
14731       <div ng-controller="Ctrl">
14732         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
14733         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
14734         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
14735         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
14736       </div>
14737     </doc:source>
14738     <doc:protractor>
14739       var numLimitInput = element(by.model('numLimit'));
14740       var letterLimitInput = element(by.model('letterLimit'));
14741       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
14742       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
14743
14744       it('should limit the number array to first three items', function() {
14745         expect(numLimitInput.getAttribute('value')).toBe('3');
14746         expect(letterLimitInput.getAttribute('value')).toBe('3');
14747         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
14748         expect(limitedLetters.getText()).toEqual('Output letters: abc');
14749       });
14750
14751       it('should update the output when -3 is entered', function() {
14752         numLimitInput.clear();
14753         numLimitInput.sendKeys('-3');
14754         letterLimitInput.clear();
14755         letterLimitInput.sendKeys('-3');
14756         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
14757         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
14758       });
14759
14760       it('should not exceed the maximum size of input array', function() {
14761         numLimitInput.clear();
14762         numLimitInput.sendKeys('100');
14763         letterLimitInput.clear();
14764         letterLimitInput.sendKeys('100');
14765         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
14766         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
14767       });
14768     </doc:protractor>
14769   </doc:example>
14770 */
14771function limitToFilter(){
14772  return function(input, limit) {
14773    if (!isArray(input) && !isString(input)) return input;
14774    
14775    limit = int(limit);
14776
14777    if (isString(input)) {
14778      //NaN check on limit
14779      if (limit) {
14780        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
14781      } else {
14782        return "";
14783      }
14784    }
14785
14786    var out = [],
14787      i, n;
14788
14789    // if abs(limit) exceeds maximum length, trim it
14790    if (limit > input.length)
14791      limit = input.length;
14792    else if (limit < -input.length)
14793      limit = -input.length;
14794
14795    if (limit > 0) {
14796      i = 0;
14797      n = limit;
14798    } else {
14799      i = input.length + limit;
14800      n = input.length;
14801    }
14802
14803    for (; i<n; i++) {
14804      out.push(input[i]);
14805    }
14806
14807    return out;
14808  };
14809}
14810
14811/**
14812 * @ngdoc function
14813 * @name ng.filter:orderBy
14814 * @function
14815 *
14816 * @description
14817 * Orders a specified `array` by the `expression` predicate.
14818 *
14819 * @param {Array} array The array to sort.
14820 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
14821 *    used by the comparator to determine the order of elements.
14822 *
14823 *    Can be one of:
14824 *
14825 *    - `function`: Getter function. The result of this function will be sorted using the
14826 *      `<`, `=`, `>` operator.
14827 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
14828 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
14829 *      ascending or descending sort order (for example, +name or -name).
14830 *    - `Array`: An array of function or string predicates. The first predicate in the array
14831 *      is used for sorting, but when two items are equivalent, the next predicate is used.
14832 *
14833 * @param {boolean=} reverse Reverse the order the array.
14834 * @returns {Array} Sorted copy of the source array.
14835 *
14836 * @example
14837   <doc:example>
14838     <doc:source>
14839       <script>
14840         function Ctrl($scope) {
14841           $scope.friends =
14842               [{name:'John', phone:'555-1212', age:10},
14843                {name:'Mary', phone:'555-9876', age:19},
14844                {name:'Mike', phone:'555-4321', age:21},
14845                {name:'Adam', phone:'555-5678', age:35},
14846                {name:'Julie', phone:'555-8765', age:29}]
14847           $scope.predicate = '-age';
14848         }
14849       </script>
14850       <div ng-controller="Ctrl">
14851         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
14852         <hr/>
14853         [ <a href="" ng-click="predicate=''">unsorted</a> ]
14854         <table class="friend">
14855           <tr>
14856             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
14857                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
14858             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
14859             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
14860           </tr>
14861           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
14862             <td>{{friend.name}}</td>
14863             <td>{{friend.phone}}</td>
14864             <td>{{friend.age}}</td>
14865           </tr>
14866         </table>
14867       </div>
14868     </doc:source>
14869   </doc:example>
14870 */
14871orderByFilter.$inject = ['$parse'];
14872function orderByFilter($parse){
14873  return function(array, sortPredicate, reverseOrder) {
14874    if (!isArray(array)) return array;
14875    if (!sortPredicate) return array;
14876    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
14877    sortPredicate = map(sortPredicate, function(predicate){
14878      var descending = false, get = predicate || identity;
14879      if (isString(predicate)) {
14880        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
14881          descending = predicate.charAt(0) == '-';
14882          predicate = predicate.substring(1);
14883        }
14884        get = $parse(predicate);
14885      }
14886      return reverseComparator(function(a,b){
14887        return compare(get(a),get(b));
14888      }, descending);
14889    });
14890    var arrayCopy = [];
14891    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
14892    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
14893
14894    function comparator(o1, o2){
14895      for ( var i = 0; i < sortPredicate.length; i++) {
14896        var comp = sortPredicate[i](o1, o2);
14897        if (comp !== 0) return comp;
14898      }
14899      return 0;
14900    }
14901    function reverseComparator(comp, descending) {
14902      return toBoolean(descending)
14903          ? function(a,b){return comp(b,a);}
14904          : comp;
14905    }
14906    function compare(v1, v2){
14907      var t1 = typeof v1;
14908      var t2 = typeof v2;
14909      if (t1 == t2) {
14910        if (t1 == "string") {
14911           v1 = v1.toLowerCase();
14912           v2 = v2.toLowerCase();
14913        }
14914        if (v1 === v2) return 0;
14915        return v1 < v2 ? -1 : 1;
14916      } else {
14917        return t1 < t2 ? -1 : 1;
14918      }
14919    }
14920  };
14921}
14922
14923function ngDirective(directive) {
14924  if (isFunction(directive)) {
14925    directive = {
14926      link: directive
14927    };
14928  }
14929  directive.restrict = directive.restrict || 'AC';
14930  return valueFn(directive);
14931}
14932
14933/**
14934 * @ngdoc directive
14935 * @name ng.directive:a
14936 * @restrict E
14937 *
14938 * @description
14939 * Modifies the default behavior of the html A tag so that the default action is prevented when
14940 * the href attribute is empty.
14941 *
14942 * This change permits the easy creation of action links with the `ngClick` directive
14943 * without changing the location or causing page reloads, e.g.:
14944 * `<a href="" ng-click="list.addItem()">Add Item</a>`
14945 */
14946var htmlAnchorDirective = valueFn({
14947  restrict: 'E',
14948  compile: function(element, attr) {
14949
14950    if (msie <= 8) {
14951
14952      // turn <a href ng-click="..">link</a> into a stylable link in IE
14953      // but only if it doesn't have name attribute, in which case it's an anchor
14954      if (!attr.href && !attr.name) {
14955        attr.$set('href', '');
14956      }
14957
14958      // add a comment node to anchors to workaround IE bug that causes element content to be reset
14959      // to new attribute content if attribute is updated with value containing @ and element also
14960      // contains value with @
14961      // see issue #1949
14962      element.append(document.createComment('IE fix'));
14963    }
14964
14965    if (!attr.href && !attr.xlinkHref && !attr.name) {
14966      return function(scope, element) {
14967        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
14968        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
14969                   'xlink:href' : 'href';
14970        element.on('click', function(event){
14971          // if we have no href url, then don't navigate anywhere.
14972          if (!element.attr(href)) {
14973            event.preventDefault();
14974          }
14975        });
14976      };
14977    }
14978  }
14979});
14980
14981/**
14982 * @ngdoc directive
14983 * @name ng.directive:ngHref
14984 * @restrict A
14985 * @priority 99
14986 *
14987 * @description
14988 * Using Angular markup like `{{hash}}` in an href attribute will
14989 * make the link go to the wrong URL if the user clicks it before
14990 * Angular has a chance to replace the `{{hash}}` markup with its
14991 * value. Until Angular replaces the markup the link will be broken
14992 * and will most likely return a 404 error.
14993 *
14994 * The `ngHref` directive solves this problem.
14995 *
14996 * The wrong way to write it:
14997 * <pre>
14998 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
14999 * </pre>
15000 *
15001 * The correct way to write it:
15002 * <pre>
15003 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15004 * </pre>
15005 *
15006 * @element A
15007 * @param {template} ngHref any string which can contain `{{}}` markup.
15008 *
15009 * @example
15010 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15011 * in links and their different behaviors:
15012    <doc:example>
15013      <doc:source>
15014        <input ng-model="value" /><br />
15015        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15016        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15017        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15018        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15019        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15020        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15021      </doc:source>
15022      <doc:protractor>
15023        it('should execute ng-click but not reload when href without value', function() {
15024          element(by.id('link-1')).click();
15025          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15026          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15027        });
15028
15029        it('should execute ng-click but not reload when href empty string', function() {
15030          element(by.id('link-2')).click();
15031          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15032          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15033        });
15034
15035        it('should execute ng-click and change url when ng-href specified', function() {
15036          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15037
15038          element(by.id('link-3')).click();
15039
15040          // At this point, we navigate away from an Angular page, so we need
15041          // to use browser.driver to get the base webdriver.
15042
15043          browser.wait(function() {
15044            return browser.driver.getCurrentUrl().then(function(url) {
15045              return url.match(/\/123$/);
15046            });
15047          }, 1000, 'page should navigate to /123');
15048        });
15049
15050        it('should execute ng-click but not reload when href empty string and name specified', function() {
15051          element(by.id('link-4')).click();
15052          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15053          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15054        });
15055
15056        it('should execute ng-click but not reload when no href but name specified', function() {
15057          element(by.id('link-5')).click();
15058          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15059          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15060        });
15061
15062        it('should only change url when only ng-href', function() {
15063          element(by.model('value')).clear();
15064          element(by.model('value')).sendKeys('6');
15065          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15066
15067          element(by.id('link-6')).click();
15068          expect(browser.getCurrentUrl()).toMatch(/\/6$/);
15069        });
15070      </doc:protractor>
15071    </doc:example>
15072 */
15073
15074/**
15075 * @ngdoc directive
15076 * @name ng.directive:ngSrc
15077 * @restrict A
15078 * @priority 99
15079 *
15080 * @description
15081 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15082 * work right: The browser will fetch from the URL with the literal
15083 * text `{{hash}}` until Angular replaces the expression inside
15084 * `{{hash}}`. The `ngSrc` directive solves this problem.
15085 *
15086 * The buggy way to write it:
15087 * <pre>
15088 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15089 * </pre>
15090 *
15091 * The correct way to write it:
15092 * <pre>
15093 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15094 * </pre>
15095 *
15096 * @element IMG
15097 * @param {template} ngSrc any string which can contain `{{}}` markup.
15098 */
15099
15100/**
15101 * @ngdoc directive
15102 * @name ng.directive:ngSrcset
15103 * @restrict A
15104 * @priority 99
15105 *
15106 * @description
15107 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15108 * work right: The browser will fetch from the URL with the literal
15109 * text `{{hash}}` until Angular replaces the expression inside
15110 * `{{hash}}`. The `ngSrcset` directive solves this problem.
15111 *
15112 * The buggy way to write it:
15113 * <pre>
15114 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15115 * </pre>
15116 *
15117 * The correct way to write it:
15118 * <pre>
15119 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15120 * </pre>
15121 *
15122 * @element IMG
15123 * @param {template} ngSrcset any string which can contain `{{}}` markup.
15124 */
15125
15126/**
15127 * @ngdoc directive
15128 * @name ng.directive:ngDisabled
15129 * @restrict A
15130 * @priority 100
15131 *
15132 * @description
15133 *
15134 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15135 * <pre>
15136 * <div ng-init="scope = { isDisabled: false }">
15137 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15138 * </div>
15139 * </pre>
15140 *
15141 * The HTML specification does not require browsers to preserve the values of boolean attributes
15142 * such as disabled. (Their presence means true and their absence means false.)
15143 * If we put an Angular interpolation expression into such an attribute then the
15144 * binding information would be lost when the browser removes the attribute.
15145 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15146 * This complementary directive is not removed by the browser and so provides
15147 * a permanent reliable place to store the binding information.
15148 *
15149 * @example
15150    <doc:example>
15151      <doc:source>
15152        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15153        <button ng-model="button" ng-disabled="checked">Button</button>
15154      </doc:source>
15155      <doc:protractor>
15156        it('should toggle button', function() {
15157          expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeFalsy();
15158          element(by.model('checked')).click();
15159          expect(element(by.css('.doc-example-live button')).getAttribute('disabled')).toBeTruthy();
15160        });
15161      </doc:protractor>
15162    </doc:example>
15163 *
15164 * @element INPUT
15165 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, 
15166 *     then special attribute "disabled" will be set on the element
15167 */
15168
15169
15170/**
15171 * @ngdoc directive
15172 * @name ng.directive:ngChecked
15173 * @restrict A
15174 * @priority 100
15175 *
15176 * @description
15177 * The HTML specification does not require browsers to preserve the values of boolean attributes
15178 * such as checked. (Their presence means true and their absence means false.)
15179 * If we put an Angular interpolation expression into such an attribute then the
15180 * binding information would be lost when the browser removes the attribute.
15181 * The `ngChecked` directive solves this problem for the `checked` attribute.
15182 * This complementary directive is not removed by the browser and so provides
15183 * a permanent reliable place to store the binding information.
15184 * @example
15185    <doc:example>
15186      <doc:source>
15187        Check me to check both: <input type="checkbox" ng-model="master"><br/>
15188        <input id="checkSlave" type="checkbox" ng-checked="master">
15189      </doc:source>
15190      <doc:protractor>
15191        it('should check both checkBoxes', function() {
15192          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15193          element(by.model('master')).click();
15194          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15195        });
15196      </doc:protractor>
15197    </doc:example>
15198 *
15199 * @element INPUT
15200 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, 
15201 *     then special attribute "checked" will be set on the element
15202 */
15203
15204
15205/**
15206 * @ngdoc directive
15207 * @name ng.directive:ngReadonly
15208 * @restrict A
15209 * @priority 100
15210 *
15211 * @description
15212 * The HTML specification does not require browsers to preserve the values of boolean attributes
15213 * such as readonly. (Their presence means true and their absence means false.)
15214 * If we put an Angular interpolation expression into such an attribute then the
15215 * binding information would be lost when the browser removes the attribute.
15216 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15217 * This complementary directive is not removed by the browser and so provides
15218 * a permanent reliable place to store the binding information.
15219 * @example
15220    <doc:example>
15221      <doc:source>
15222        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15223        <input type="text" ng-readonly="checked" value="I'm Angular"/>
15224      </doc:source>
15225      <doc:protractor>
15226        it('should toggle readonly attr', function() {
15227          expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeFalsy();
15228          element(by.model('checked')).click();
15229          expect(element(by.css('.doc-example-live [type="text"]')).getAttribute('readonly')).toBeTruthy();
15230        });
15231      </doc:protractor>
15232    </doc:example>
15233 *
15234 * @element INPUT
15235 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, 
15236 *     then special attribute "readonly" will be set on the element
15237 */
15238
15239
15240/**
15241 * @ngdoc directive
15242 * @name ng.directive:ngSelected
15243 * @restrict A
15244 * @priority 100
15245 *
15246 * @description
15247 * The HTML specification does not require browsers to preserve the values of boolean attributes
15248 * such as selected. (Their presence means true and their absence means false.)
15249 * If we put an Angular interpolation expression into such an attribute then the
15250 * binding information would be lost when the browser removes the attribute.
15251 * The `ngSelected` directive solves this problem for the `selected` atttribute.
15252 * This complementary directive is not removed by the browser and so provides
15253 * a permanent reliable place to store the binding information.
15254 * 
15255 * @example
15256    <doc:example>
15257      <doc:source>
15258        Check me to select: <input type="checkbox" ng-model="selected"><br/>
15259        <select>
15260          <option>Hello!</option>
15261          <option id="greet" ng-selected="selected">Greetings!</option>
15262        </select>
15263      </doc:source>
15264      <doc:protractor>
15265        it('should select Greetings!', function() {
15266          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15267          element(by.model('selected')).click();
15268          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15269        });
15270      </doc:protractor>
15271    </doc:example>
15272 *
15273 * @element OPTION
15274 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, 
15275 *     then special attribute "selected" will be set on the element
15276 */
15277
15278/**
15279 * @ngdoc directive
15280 * @name ng.directive:ngOpen
15281 * @restrict A
15282 * @priority 100
15283 *
15284 * @description
15285 * The HTML specification does not require browsers to preserve the values of boolean attributes
15286 * such as open. (Their presence means true and their absence means false.)
15287 * If we put an Angular interpolation expression into such an attribute then the
15288 * binding information would be lost when the browser removes the attribute.
15289 * The `ngOpen` directive solves this problem for the `open` attribute.
15290 * This complementary directive is not removed by the browser and so provides
15291 * a permanent reliable place to store the binding information.
15292 * @example
15293     <doc:example>
15294       <doc:source>
15295         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15296         <details id="details" ng-open="open">
15297            <summary>Show/Hide me</summary>
15298         </details>
15299       </doc:source>
15300       <doc:protractor>
15301         it('should toggle open', function() {
15302           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15303           element(by.model('open')).click();
15304           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15305         });
15306       </doc:protractor>
15307     </doc:example>
15308 *
15309 * @element DETAILS
15310 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, 
15311 *     then special attribute "open" will be set on the element
15312 */
15313
15314var ngAttributeAliasDirectives = {};
15315
15316
15317// boolean attrs are evaluated
15318forEach(BOOLEAN_ATTR, function(propName, attrName) {
15319  // binding to multiple is not supported
15320  if (propName == "multiple") return;
15321
15322  var normalized = directiveNormalize('ng-' + attrName);
15323  ngAttributeAliasDirectives[normalized] = function() {
15324    return {
15325      priority: 100,
15326      link: function(scope, element, attr) {
15327        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
15328          attr.$set(attrName, !!value);
15329        });
15330      }
15331    };
15332  };
15333});
15334
15335
15336// ng-src, ng-srcset, ng-href are interpolated
15337forEach(['src', 'srcset', 'href'], function(attrName) {
15338  var normalized = directiveNormalize('ng-' + attrName);
15339  ngAttributeAliasDirectives[normalized] = function() {
15340    return {
15341      priority: 99, // it needs to run after the attributes are interpolated
15342      link: function(scope, element, attr) {
15343        attr.$observe(normalized, function(value) {
15344          if (!value)
15345             return;
15346
15347          attr.$set(attrName, value);
15348
15349          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
15350          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
15351          // to set the property as well to achieve the desired effect.
15352          // we use attr[attrName] value since $set can sanitize the url.
15353          if (msie) element.prop(attrName, attr[attrName]);
15354        });
15355      }
15356    };
15357  };
15358});
15359
15360/* global -nullFormCtrl */
15361var nullFormCtrl = {
15362  $addControl: noop,
15363  $removeControl: noop,
15364  $setValidity: noop,
15365  $setDirty: noop,
15366  $setPristine: noop
15367};
15368
15369/**
15370 * @ngdoc object
15371 * @name ng.directive:form.FormController
15372 *
15373 * @property {boolean} $pristine True if user has not interacted with the form yet.
15374 * @property {boolean} $dirty True if user has already interacted with the form.
15375 * @property {boolean} $valid True if all of the containing forms and controls are valid.
15376 * @property {boolean} $invalid True if at least one containing control or form is invalid.
15377 *
15378 * @property {Object} $error Is an object hash, containing references to all invalid controls or
15379 *  forms, where:
15380 *
15381 *  - keys are validation tokens (error names),
15382 *  - values are arrays of controls or forms that are invalid for given error name.
15383 *
15384 *
15385 *  Built-in validation tokens:
15386 *
15387 *  - `email`
15388 *  - `max`
15389 *  - `maxlength`
15390 *  - `min`
15391 *  - `minlength`
15392 *  - `number`
15393 *  - `pattern`
15394 *  - `required`
15395 *  - `url`
15396 * 
15397 * @description
15398 * `FormController` keeps track of all its controls and nested forms as well as state of them,
15399 * such as being valid/invalid or dirty/pristine.
15400 *
15401 * Each {@link ng.directive:form form} directive creates an instance
15402 * of `FormController`.
15403 *
15404 */
15405//asks for $scope to fool the BC controller module
15406FormController.$inject = ['$element', '$attrs', '$scope'];
15407function FormController(element, attrs) {
15408  var form = this,
15409      parentForm = element.parent().controller('form') || nullFormCtrl,
15410      invalidCount = 0, // used to easily determine if we are valid
15411      errors = form.$error = {},
15412      controls = [];
15413
15414  // init state
15415  form.$name = attrs.name || attrs.ngForm;
15416  form.$dirty = false;
15417  form.$pristine = true;
15418  form.$valid = true;
15419  form.$invalid = false;
15420
15421  parentForm.$addControl(form);
15422
15423  // Setup initial state of the control
15424  element.addClass(PRISTINE_CLASS);
15425  toggleValidCss(true);
15426
15427  // convenience method for easy toggling of classes
15428  function toggleValidCss(isValid, validationErrorKey) {
15429    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
15430    element.
15431      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
15432      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
15433  }
15434
15435  /**
15436   * @ngdoc function
15437   * @name ng.directive:form.FormController#$addControl
15438   * @methodOf ng.directive:form.FormController
15439   *
15440   * @description
15441   * Register a control with the form.
15442   *
15443   * Input elements using ngModelController do this automatically when they are linked.
15444   */
15445  form.$addControl = function(control) {
15446    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
15447    // and not added to the scope.  Now we throw an error.
15448    assertNotHasOwnProperty(control.$name, 'input');
15449    controls.push(control);
15450
15451    if (control.$name) {
15452      form[control.$name] = control;
15453    }
15454  };
15455
15456  /**
15457   * @ngdoc function
15458   * @name ng.directive:form.FormController#$removeControl
15459   * @methodOf ng.directive:form.FormController
15460   *
15461   * @description
15462   * Deregister a control from the form.
15463   *
15464   * Input elements using ngModelController do this automatically when they are destroyed.
15465   */
15466  form.$removeControl = function(control) {
15467    if (control.$name && form[control.$name] === control) {
15468      delete form[control.$name];
15469    }
15470    forEach(errors, function(queue, validationToken) {
15471      form.$setValidity(validationToken, true, control);
15472    });
15473
15474    arrayRemove(controls, control);
15475  };
15476
15477  /**
15478   * @ngdoc function
15479   * @name ng.directive:form.FormController#$setValidity
15480   * @methodOf ng.directive:form.FormController
15481   *
15482   * @description
15483   * Sets the validity of a form control.
15484   *
15485   * This method will also propagate to parent forms.
15486   */
15487  form.$setValidity = function(validationToken, isValid, control) {
15488    var queue = errors[validationToken];
15489
15490    if (isValid) {
15491      if (queue) {
15492        arrayRemove(queue, control);
15493        if (!queue.length) {
15494          invalidCount--;
15495          if (!invalidCount) {
15496            toggleValidCss(isValid);
15497            form.$valid = true;
15498            form.$invalid = false;
15499          }
15500          errors[validationToken] = false;
15501          toggleValidCss(true, validationToken);
15502          parentForm.$setValidity(validationToken, true, form);
15503        }
15504      }
15505
15506    } else {
15507      if (!invalidCount) {
15508        toggleValidCss(isValid);
15509      }
15510      if (queue) {
15511        if (includes(queue, control)) return;
15512      } else {
15513        errors[validationToken] = queue = [];
15514        invalidCount++;
15515        toggleValidCss(false, validationToken);
15516        parentForm.$setValidity(validationToken, false, form);
15517      }
15518      queue.push(control);
15519
15520      form.$valid = false;
15521      form.$invalid = true;
15522    }
15523  };
15524
15525  /**
15526   * @ngdoc function
15527   * @name ng.directive:form.FormController#$setDirty
15528   * @methodOf ng.directive:form.FormController
15529   *
15530   * @description
15531   * Sets the form to a dirty state.
15532   *
15533   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
15534   * state (ng-dirty class). This method will also propagate to parent forms.
15535   */
15536  form.$setDirty = function() {
15537    element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
15538    form.$dirty = true;
15539    form.$pristine = false;
15540    parentForm.$setDirty();
15541  };
15542
15543  /**
15544   * @ngdoc function
15545   * @name ng.directive:form.FormController#$setPristine
15546   * @methodOf ng.directive:form.FormController
15547   *
15548   * @description
15549   * Sets the form to its pristine state.
15550   *
15551   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
15552   * state (ng-pristine class). This method will also propagate to all the controls contained
15553   * in this form.
15554   *
15555   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
15556   * saving or resetting it.
15557   */
15558  form.$setPristine = function () {
15559    element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
15560    form.$dirty = false;
15561    form.$pristine = true;
15562    forEach(controls, function(control) {
15563      control.$setPristine();
15564    });
15565  };
15566}
15567
15568
15569/**
15570 * @ngdoc directive
15571 * @name ng.directive:ngForm
15572 * @restrict EAC
15573 *
15574 * @description
15575 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
15576 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
15577 * sub-group of controls needs to be determined.
15578 *
15579 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
15580 *                       related scope, under this name.
15581 *
15582 */
15583
15584 /**
15585 * @ngdoc directive
15586 * @name ng.directive:form
15587 * @restrict E
15588 *
15589 * @description
15590 * Directive that instantiates
15591 * {@link ng.directive:form.FormController FormController}.
15592 *
15593 * If the `name` attribute is specified, the form controller is published onto the current scope under
15594 * this name.
15595 *
15596 * # Alias: {@link ng.directive:ngForm `ngForm`}
15597 *
15598 * In Angular forms can be nested. This means that the outer form is valid when all of the child
15599 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
15600 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
15601 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
15602 * using Angular validation directives in forms that are dynamically generated using the
15603 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
15604 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
15605 * `ngForm` directive and nest these in an outer `form` element.
15606 *
15607 *
15608 * # CSS classes
15609 *  - `ng-valid` is set if the form is valid.
15610 *  - `ng-invalid` is set if the form is invalid.
15611 *  - `ng-pristine` is set if the form is pristine.
15612 *  - `ng-dirty` is set if the form is dirty.
15613 *
15614 *
15615 * # Submitting a form and preventing the default action
15616 *
15617 * Since the role of forms in client-side Angular applications is different than in classical
15618 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
15619 * page reload that sends the data to the server. Instead some javascript logic should be triggered
15620 * to handle the form submission in an application-specific way.
15621 *
15622 * For this reason, Angular prevents the default action (form submission to the server) unless the
15623 * `<form>` element has an `action` attribute specified.
15624 *
15625 * You can use one of the following two ways to specify what javascript method should be called when
15626 * a form is submitted:
15627 *
15628 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
15629 * - {@link ng.directive:ngClick ngClick} directive on the first
15630  *  button or input field of type submit (input[type=submit])
15631 *
15632 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
15633 * or {@link ng.directive:ngClick ngClick} directives.
15634 * This is because of the following form submission rules in the HTML specification:
15635 *
15636 * - If a form has only one input field then hitting enter in this field triggers form submit
15637 * (`ngSubmit`)
15638 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
15639 * doesn't trigger submit
15640 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
15641 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
15642 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
15643 *
15644 * @param {string=} name Name of the form. If specified, the form controller will be published into
15645 *                       related scope, under this name.
15646 *
15647 * @example
15648    <doc:example>
15649      <doc:source>
15650       <script>
15651         function Ctrl($scope) {
15652           $scope.userType = 'guest';
15653         }
15654       </script>
15655       <form name="myForm" ng-controller="Ctrl">
15656         userType: <input name="input" ng-model="userType" required>
15657         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
15658         <tt>userType = {{userType}}</tt><br>
15659         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
15660         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
15661         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
15662         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
15663        </form>
15664      </doc:source>
15665      <doc:protractor>
15666        it('should initialize to model', function() {
15667          var userType = element(by.binding('userType'));
15668          var valid = element(by.binding('myForm.input.$valid'));
15669
15670          expect(userType.getText()).toContain('guest');
15671          expect(valid.getText()).toContain('true');
15672        });
15673
15674        it('should be invalid if empty', function() {
15675          var userType = element(by.binding('userType'));
15676          var valid = element(by.binding('myForm.input.$valid'));
15677          var userInput = element(by.model('userType'));
15678
15679          userInput.clear();
15680          userInput.sendKeys('');
15681
15682          expect(userType.getText()).toEqual('userType =');
15683          expect(valid.getText()).toContain('false');
15684        });
15685      </doc:protractor>
15686    </doc:example>
15687 */
15688var formDirectiveFactory = function(isNgForm) {
15689  return ['$timeout', function($timeout) {
15690    var formDirective = {
15691      name: 'form',
15692      restrict: isNgForm ? 'EAC' : 'E',
15693      controller: FormController,
15694      compile: function() {
15695        return {
15696          pre: function(scope, formElement, attr, controller) {
15697            if (!attr.action) {
15698              // we can't use jq events because if a form is destroyed during submission the default
15699              // action is not prevented. see #1238
15700              //
15701              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
15702              // page reload if the form was destroyed by submission of the form via a click handler
15703              // on a button in the form. Looks like an IE9 specific bug.
15704              var preventDefaultListener = function(event) {
15705                event.preventDefault
15706                  ? event.preventDefault()
15707                  : event.returnValue = false; // IE
15708              };
15709
15710              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
15711
15712              // unregister the preventDefault listener so that we don't not leak memory but in a
15713              // way that will achieve the prevention of the default action.
15714              formElement.on('$destroy', function() {
15715                $timeout(function() {
15716                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
15717                }, 0, false);
15718              });
15719            }
15720
15721            var parentFormCtrl = formElement.parent().controller('form'),
15722                alias = attr.name || attr.ngForm;
15723
15724            if (alias) {
15725              setter(scope, alias, controller, alias);
15726            }
15727            if (parentFormCtrl) {
15728              formElement.on('$destroy', function() {
15729                parentFormCtrl.$removeControl(controller);
15730                if (alias) {
15731                  setter(scope, alias, undefined, alias);
15732                }
15733                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
15734              });
15735            }
15736          }
15737        };
15738      }
15739    };
15740
15741    return formDirective;
15742  }];
15743};
15744
15745var formDirective = formDirectiveFactory();
15746var ngFormDirective = formDirectiveFactory(true);
15747
15748/* global
15749
15750    -VALID_CLASS,
15751    -INVALID_CLASS,
15752    -PRISTINE_CLASS,
15753    -DIRTY_CLASS
15754*/
15755
15756var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
15757var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
15758var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
15759
15760var inputType = {
15761
15762  /**
15763   * @ngdoc inputType
15764   * @name ng.directive:input.text
15765   *
15766   * @description
15767   * Standard HTML text input with angular data binding.
15768   *
15769   * @param {string} ngModel Assignable angular expression to data-bind to.
15770   * @param {string=} name Property name of the form under which the control is published.
15771   * @param {string=} required Adds `required` validation error key if the value is not entered.
15772   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15773   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15774   *    `required` when you want to data-bind to the `required` attribute.
15775   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15776   *    minlength.
15777   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15778   *    maxlength.
15779   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15780   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15781   *    patterns defined as scope expressions.
15782   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15783   *    interaction with the input element.
15784   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
15785   *
15786   * @example
15787      <doc:example>
15788        <doc:source>
15789         <script>
15790           function Ctrl($scope) {
15791             $scope.text = 'guest';
15792             $scope.word = /^\s*\w*\s*$/;
15793           }
15794         </script>
15795         <form name="myForm" ng-controller="Ctrl">
15796           Single word: <input type="text" name="input" ng-model="text"
15797                               ng-pattern="word" required ng-trim="false">
15798           <span class="error" ng-show="myForm.input.$error.required">
15799             Required!</span>
15800           <span class="error" ng-show="myForm.input.$error.pattern">
15801             Single word only!</span>
15802
15803           <tt>text = {{text}}</tt><br/>
15804           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15805           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15806           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15807           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15808          </form>
15809        </doc:source>
15810        <doc:protractor>
15811          var text = element(by.binding('text'));
15812          var valid = element(by.binding('myForm.input.$valid'));
15813          var input = element(by.model('text'));
15814
15815          it('should initialize to model', function() {
15816            expect(text.getText()).toContain('guest');
15817            expect(valid.getText()).toContain('true');
15818          });
15819
15820          it('should be invalid if empty', function() {
15821            input.clear();
15822            input.sendKeys('');
15823
15824            expect(text.getText()).toEqual('text =');
15825            expect(valid.getText()).toContain('false');
15826          });
15827
15828          it('should be invalid if multi word', function() {
15829            input.clear();
15830            input.sendKeys('hello world');
15831
15832            expect(valid.getText()).toContain('false');
15833          });
15834        </doc:protractor>
15835      </doc:example>
15836   */
15837  'text': textInputType,
15838
15839
15840  /**
15841   * @ngdoc inputType
15842   * @name ng.directive:input.number
15843   *
15844   * @description
15845   * Text input with number validation and transformation. Sets the `number` validation
15846   * error if not a valid number.
15847   *
15848   * @param {string} ngModel Assignable angular expression to data-bind to.
15849   * @param {string=} name Property name of the form under which the control is published.
15850   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
15851   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
15852   * @param {string=} required Sets `required` validation error key if the value is not entered.
15853   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15854   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15855   *    `required` when you want to data-bind to the `required` attribute.
15856   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15857   *    minlength.
15858   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15859   *    maxlength.
15860   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15861   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15862   *    patterns defined as scope expressions.
15863   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15864   *    interaction with the input element.
15865   *
15866   * @example
15867      <doc:example>
15868        <doc:source>
15869         <script>
15870           function Ctrl($scope) {
15871             $scope.value = 12;
15872           }
15873         </script>
15874         <form name="myForm" ng-controller="Ctrl">
15875           Number: <input type="number" name="input" ng-model="value"
15876                          min="0" max="99" required>
15877           <span class="error" ng-show="myForm.input.$error.required">
15878             Required!</span>
15879           <span class="error" ng-show="myForm.input.$error.number">
15880             Not valid number!</span>
15881           <tt>value = {{value}}</tt><br/>
15882           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15883           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15884           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15885           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15886          </form>
15887        </doc:source>
15888        <doc:protractor>
15889          var value = element(by.binding('value'));
15890          var valid = element(by.binding('myForm.input.$valid'));
15891          var input = element(by.model('value'));
15892
15893          it('should initialize to model', function() {
15894            expect(value.getText()).toContain('12');
15895            expect(valid.getText()).toContain('true');
15896          });
15897
15898          it('should be invalid if empty', function() {
15899            input.clear();
15900            input.sendKeys('');
15901            expect(value.getText()).toEqual('value =');
15902            expect(valid.getText()).toContain('false');
15903          });
15904
15905          it('should be invalid if over max', function() {
15906            input.clear();
15907            input.sendKeys('123');
15908            expect(value.getText()).toEqual('value =');
15909            expect(valid.getText()).toContain('false');
15910          });
15911        </doc:protractor>
15912      </doc:example>
15913   */
15914  'number': numberInputType,
15915
15916
15917  /**
15918   * @ngdoc inputType
15919   * @name ng.directive:input.url
15920   *
15921   * @description
15922   * Text input with URL validation. Sets the `url` validation error key if the content is not a
15923   * valid URL.
15924   *
15925   * @param {string} ngModel Assignable angular expression to data-bind to.
15926   * @param {string=} name Property name of the form under which the control is published.
15927   * @param {string=} required Sets `required` validation error key if the value is not entered.
15928   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
15929   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
15930   *    `required` when you want to data-bind to the `required` attribute.
15931   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
15932   *    minlength.
15933   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
15934   *    maxlength.
15935   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
15936   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
15937   *    patterns defined as scope expressions.
15938   * @param {string=} ngChange Angular expression to be executed when input changes due to user
15939   *    interaction with the input element.
15940   *
15941   * @example
15942      <doc:example>
15943        <doc:source>
15944         <script>
15945           function Ctrl($scope) {
15946             $scope.text = 'http://google.com';
15947           }
15948         </script>
15949         <form name="myForm" ng-controller="Ctrl">
15950           URL: <input type="url" name="input" ng-model="text" required>
15951           <span class="error" ng-show="myForm.input.$error.required">
15952             Required!</span>
15953           <span class="error" ng-show="myForm.input.$error.url">
15954             Not valid url!</span>
15955           <tt>text = {{text}}</tt><br/>
15956           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
15957           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
15958           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
15959           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
15960           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
15961          </form>
15962        </doc:source>
15963        <doc:protractor>
15964          var text = element(by.binding('text'));
15965          var valid = element(by.binding('myForm.input.$valid'));
15966          var input = element(by.model('text'));
15967
15968          it('should initialize to model', function() {
15969            expect(text.getText()).toContain('http://google.com');
15970            expect(valid.getText()).toContain('true');
15971          });
15972
15973          it('should be invalid if empty', function() {
15974            input.clear();
15975            input.sendKeys('');
15976
15977            expect(text.getText()).toEqual('text =');
15978            expect(valid.getText()).toContain('false');
15979          });
15980
15981          it('should be invalid if not url', function() {
15982            input.clear();
15983            input.sendKeys('box');
15984
15985            expect(valid.getText()).toContain('false');
15986          });
15987        </doc:protractor>
15988      </doc:example>
15989   */
15990  'url': urlInputType,
15991
15992
15993  /**
15994   * @ngdoc inputType
15995   * @name ng.directive:input.email
15996   *
15997   * @description
15998   * Text input with email validation. Sets the `email` validation error key if not a valid email
15999   * address.
16000   *
16001   * @param {string} ngModel Assignable angular expression to data-bind to.
16002   * @param {string=} name Property name of the form under which the control is published.
16003   * @param {string=} required Sets `required` validation error key if the value is not entered.
16004   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16005   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16006   *    `required` when you want to data-bind to the `required` attribute.
16007   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16008   *    minlength.
16009   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16010   *    maxlength.
16011   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16012   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16013   *    patterns defined as scope expressions.
16014   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16015   *    interaction with the input element.
16016   *
16017   * @example
16018      <doc:example>
16019        <doc:source>
16020         <script>
16021           function Ctrl($scope) {
16022             $scope.text = '[email protected]';
16023           }
16024         </script>
16025           <form name="myForm" ng-controller="Ctrl">
16026             Email: <input type="email" name="input" ng-model="text" required>
16027             <span class="error" ng-show="myForm.input.$error.required">
16028               Required!</span>
16029             <span class="error" ng-show="myForm.input.$error.email">
16030               Not valid email!</span>
16031             <tt>text = {{text}}</tt><br/>
16032             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16033             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16034             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16035             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16036             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16037           </form>
16038        </doc:source>
16039        <doc:protractor>
16040          var text = element(by.binding('text'));
16041          var valid = element(by.binding('myForm.input.$valid'));
16042          var input = element(by.model('text'));
16043          
16044          it('should initialize to model', function() {
16045            expect(text.getText()).toContain('[email protected]');
16046            expect(valid.getText()).toContain('true');
16047          });
16048
16049          it('should be invalid if empty', function() {
16050            input.clear();
16051            input.sendKeys('');
16052            expect(text.getText()).toEqual('text =');
16053            expect(valid.getText()).toContain('false');
16054          });
16055
16056          it('should be invalid if not email', function() {
16057            input.clear();
16058            input.sendKeys('xxx');
16059
16060            expect(valid.getText()).toContain('false');
16061          });
16062        </doc:protractor>
16063      </doc:example>
16064   */
16065  'email': emailInputType,
16066
16067
16068  /**
16069   * @ngdoc inputType
16070   * @name ng.directive:input.radio
16071   *
16072   * @description
16073   * HTML radio button.
16074   *
16075   * @param {string} ngModel Assignable angular expression to data-bind to.
16076   * @param {string} value The value to which the expression should be set when selected.
16077   * @param {string=} name Property name of the form under which the control is published.
16078   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16079   *    interaction with the input element.
16080   * @param {string} ngValue Angular expression which sets the value to which the expression should
16081   *    be set when selected.
16082   *
16083   * @example
16084      <doc:example>
16085        <doc:source>
16086         <script>
16087           function Ctrl($scope) {
16088             $scope.color = 'blue';
16089             $scope.specialValue = {
16090               "id": "12345",
16091               "value": "green"
16092             };
16093           }
16094         </script>
16095         <form name="myForm" ng-controller="Ctrl">
16096           <input type="radio" ng-model="color" value="red">  Red <br/>
16097           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16098           <input type="radio" ng-model="color" value="blue"> Blue <br/>
16099           <tt>color = {{color | json}}</tt><br/>
16100          </form>
16101          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16102        </doc:source>
16103        <doc:protractor>
16104          it('should change state', function() {
16105            var color = element(by.binding('color'));
16106
16107            expect(color.getText()).toContain('blue');
16108
16109            element.all(by.model('color')).get(0).click();
16110
16111            expect(color.getText()).toContain('red');
16112          });
16113        </doc:protractor>
16114      </doc:example>
16115   */
16116  'radio': radioInputType,
16117
16118
16119  /**
16120   * @ngdoc inputType
16121   * @name ng.directive:input.checkbox
16122   *
16123   * @description
16124   * HTML checkbox.
16125   *
16126   * @param {string} ngModel Assignable angular expression to data-bind to.
16127   * @param {string=} name Property name of the form under which the control is published.
16128   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16129   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16130   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16131   *    interaction with the input element.
16132   *
16133   * @example
16134      <doc:example>
16135        <doc:source>
16136         <script>
16137           function Ctrl($scope) {
16138             $scope.value1 = true;
16139             $scope.value2 = 'YES'
16140           }
16141         </script>
16142         <form name="myForm" ng-controller="Ctrl">
16143           Value1: <input type="checkbox" ng-model="value1"> <br/>
16144           Value2: <input type="checkbox" ng-model="value2"
16145                          ng-true-value="YES" ng-false-value="NO"> <br/>
16146           <tt>value1 = {{value1}}</tt><br/>
16147           <tt>value2 = {{value2}}</tt><br/>
16148          </form>
16149        </doc:source>
16150        <doc:protractor>
16151          it('should change state', function() {
16152            var value1 = element(by.binding('value1'));
16153            var value2 = element(by.binding('value2'));
16154
16155            expect(value1.getText()).toContain('true');
16156            expect(value2.getText()).toContain('YES');
16157            
16158            element(by.model('value1')).click();
16159            element(by.model('value2')).click();
16160
16161            expect(value1.getText()).toContain('false');
16162            expect(value2.getText()).toContain('NO');
16163          });
16164        </doc:protractor>
16165      </doc:example>
16166   */
16167  'checkbox': checkboxInputType,
16168
16169  'hidden': noop,
16170  'button': noop,
16171  'submit': noop,
16172  'reset': noop,
16173  'file': noop
16174};
16175
16176// A helper function to call $setValidity and return the value / undefined,
16177// a pattern that is repeated a lot in the input validation logic.
16178function validate(ctrl, validatorName, validity, value){
16179  ctrl.$setValidity(validatorName, validity);
16180  return validity ? value : undefined;
16181}
16182
16183function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16184  // In composition mode, users are still inputing intermediate text buffer,
16185  // hold the listener until composition is done.
16186  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16187  if (!$sniffer.android) {
16188    var composing = false;
16189
16190    element.on('compositionstart', function(data) {
16191      composing = true;
16192    });
16193
16194    element.on('compositionend', function() {
16195      composing = false;
16196      listener();
16197    });
16198  }
16199
16200  var listener = function() {
16201    if (composing) return;
16202    var value = element.val();
16203
16204    // By default we will trim the value
16205    // If the attribute ng-trim exists we will avoid trimming
16206    // e.g. <input ng-model="foo" ng-trim="false">
16207    if (toBoolean(attr.ngTrim || 'T')) {
16208      value = trim(value);
16209    }
16210
16211    if (ctrl.$viewValue !== value) {
16212      if (scope.$$phase) {
16213        ctrl.$setViewValue(value);
16214      } else {
16215        scope.$apply(function() {
16216          ctrl.$setViewValue(value);
16217        });
16218      }
16219    }
16220  };
16221
16222  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
16223  // input event on backspace, delete or cut
16224  if ($sniffer.hasEvent('input')) {
16225    element.on('input', listener);
16226  } else {
16227    var timeout;
16228
16229    var deferListener = function() {
16230      if (!timeout) {
16231        timeout = $browser.defer(function() {
16232          listener();
16233          timeout = null;
16234        });
16235      }
16236    };
16237
16238    element.on('keydown', function(event) {
16239      var key = event.keyCode;
16240
16241      // ignore
16242      //    command            modifiers                   arrows
16243      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
16244
16245      deferListener();
16246    });
16247
16248    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
16249    if ($sniffer.hasEvent('paste')) {
16250      element.on('paste cut', deferListener);
16251    }
16252  }
16253
16254  // if user paste into input using mouse on older browser
16255  // or form autocomplete on newer browser, we need "change" event to catch it
16256  element.on('change', listener);
16257
16258  ctrl.$render = function() {
16259    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
16260  };
16261
16262  // pattern validator
16263  var pattern = attr.ngPattern,
16264      patternValidator,
16265      match;
16266
16267  if (pattern) {
16268    var validateRegex = function(regexp, value) {
16269      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
16270    };
16271    match = pattern.match(/^\/(.*)\/([gim]*)$/);
16272    if (match) {
16273      pattern = new RegExp(match[1], match[2]);
16274      patternValidator = function(value) {
16275        return validateRegex(pattern, value);
16276      };
16277    } else {
16278      patternValidator = function(value) {
16279        var patternObj = scope.$eval(pattern);
16280
16281        if (!patternObj || !patternObj.test) {
16282          throw minErr('ngPattern')('noregexp',
16283            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
16284            patternObj, startingTag(element));
16285        }
16286        return validateRegex(patternObj, value);
16287      };
16288    }
16289
16290    ctrl.$formatters.push(patternValidator);
16291    ctrl.$parsers.push(patternValidator);
16292  }
16293
16294  // min length validator
16295  if (attr.ngMinlength) {
16296    var minlength = int(attr.ngMinlength);
16297    var minLengthValidator = function(value) {
16298      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
16299    };
16300
16301    ctrl.$parsers.push(minLengthValidator);
16302    ctrl.$formatters.push(minLengthValidator);
16303  }
16304
16305  // max length validator
16306  if (attr.ngMaxlength) {
16307    var maxlength = int(attr.ngMaxlength);
16308    var maxLengthValidator = function(value) {
16309      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
16310    };
16311
16312    ctrl.$parsers.push(maxLengthValidator);
16313    ctrl.$formatters.push(maxLengthValidator);
16314  }
16315}
16316
16317function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16318  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16319
16320  ctrl.$parsers.push(function(value) {
16321    var empty = ctrl.$isEmpty(value);
16322    if (empty || NUMBER_REGEXP.test(value)) {
16323      ctrl.$setValidity('number', true);
16324      return value === '' ? null : (empty ? value : parseFloat(value));
16325    } else {
16326      ctrl.$setValidity('number', false);
16327      return undefined;
16328    }
16329  });
16330
16331  ctrl.$formatters.push(function(value) {
16332    return ctrl.$isEmpty(value) ? '' : '' + value;
16333  });
16334
16335  if (attr.min) {
16336    var minValidator = function(value) {
16337      var min = parseFloat(attr.min);
16338      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
16339    };
16340
16341    ctrl.$parsers.push(minValidator);
16342    ctrl.$formatters.push(minValidator);
16343  }
16344
16345  if (attr.max) {
16346    var maxValidator = function(value) {
16347      var max = parseFloat(attr.max);
16348      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
16349    };
16350
16351    ctrl.$parsers.push(maxValidator);
16352    ctrl.$formatters.push(maxValidator);
16353  }
16354
16355  ctrl.$formatters.push(function(value) {
16356    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
16357  });
16358}
16359
16360function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16361  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16362
16363  var urlValidator = function(value) {
16364    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
16365  };
16366
16367  ctrl.$formatters.push(urlValidator);
16368  ctrl.$parsers.push(urlValidator);
16369}
16370
16371function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16372  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16373
16374  var emailValidator = function(value) {
16375    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
16376  };
16377
16378  ctrl.$formatters.push(emailValidator);
16379  ctrl.$parsers.push(emailValidator);
16380}
16381
16382function radioInputType(scope, element, attr, ctrl) {
16383  // make the name unique, if not defined
16384  if (isUndefined(attr.name)) {
16385    element.attr('name', nextUid());
16386  }
16387
16388  element.on('click', function() {
16389    if (element[0].checked) {
16390      scope.$apply(function() {
16391        ctrl.$setViewValue(attr.value);
16392      });
16393    }
16394  });
16395
16396  ctrl.$render = function() {
16397    var value = attr.value;
16398    element[0].checked = (value == ctrl.$viewValue);
16399  };
16400
16401  attr.$observe('value', ctrl.$render);
16402}
16403
16404function checkboxInputType(scope, element, attr, ctrl) {
16405  var trueValue = attr.ngTrueValue,
16406      falseValue = attr.ngFalseValue;
16407
16408  if (!isString(trueValue)) trueValue = true;
16409  if (!isString(falseValue)) falseValue = false;
16410
16411  element.on('click', function() {
16412    scope.$apply(function() {
16413      ctrl.$setViewValue(element[0].checked);
16414    });
16415  });
16416
16417  ctrl.$render = function() {
16418    element[0].checked = ctrl.$viewValue;
16419  };
16420
16421  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
16422  ctrl.$isEmpty = function(value) {
16423    return value !== trueValue;
16424  };
16425
16426  ctrl.$formatters.push(function(value) {
16427    return value === trueValue;
16428  });
16429
16430  ctrl.$parsers.push(function(value) {
16431    return value ? trueValue : falseValue;
16432  });
16433}
16434
16435
16436/**
16437 * @ngdoc directive
16438 * @name ng.directive:textarea
16439 * @restrict E
16440 *
16441 * @description
16442 * HTML textarea element control with angular data-binding. The data-binding and validation
16443 * properties of this element are exactly the same as those of the
16444 * {@link ng.directive:input input element}.
16445 *
16446 * @param {string} ngModel Assignable angular expression to data-bind to.
16447 * @param {string=} name Property name of the form under which the control is published.
16448 * @param {string=} required Sets `required` validation error key if the value is not entered.
16449 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16450 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16451 *    `required` when you want to data-bind to the `required` attribute.
16452 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16453 *    minlength.
16454 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16455 *    maxlength.
16456 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16457 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16458 *    patterns defined as scope expressions.
16459 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16460 *    interaction with the input element.
16461 */
16462
16463
16464/**
16465 * @ngdoc directive
16466 * @name ng.directive:input
16467 * @restrict E
16468 *
16469 * @description
16470 * HTML input element control with angular data-binding. Input control follows HTML5 input types
16471 * and polyfills the HTML5 validation behavior for older browsers.
16472 *
16473 * @param {string} ngModel Assignable angular expression to data-bind to.
16474 * @param {string=} name Property name of the form under which the control is published.
16475 * @param {string=} required Sets `required` validation error key if the value is not entered.
16476 * @param {boolean=} ngRequired Sets `required` attribute if set to true
16477 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16478 *    minlength.
16479 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16480 *    maxlength.
16481 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16482 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16483 *    patterns defined as scope expressions.
16484 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16485 *    interaction with the input element.
16486 *
16487 * @example
16488    <doc:example>
16489      <doc:source>
16490       <script>
16491         function Ctrl($scope) {
16492           $scope.user = {name: 'guest', last: 'visitor'};
16493         }
16494       </script>
16495       <div ng-controller="Ctrl">
16496         <form name="myForm">
16497           User name: <input type="text" name="userName" ng-model="user.n
16497ame" required>
16498           <span class="error" ng-show="myForm.userName.$error.required">
16499             Required!</span><br>
16500           Last name: <input type="text" name="lastName" ng-model="user.last"
16501             ng-minlength="3" ng-maxlength="10">
16502           <span class="error" ng-show="myForm.lastName.$error.minlength">
16503             Too short!</span>
16504           <span class="error" ng-show="myForm.lastName.$error.maxlength">
16505             Too long!</span><br>
16506         </form>
16507         <hr>
16508         <tt>user = {{user}}</tt><br/>
16509         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
16510         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
16511         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
16512         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
16513         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16514         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16515         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
16516         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
16517       </div>
16518      </doc:source>
16519      <doc:protractor>
16520        var user = element(by.binding('{{user}}'));
16521        var userNameValid = element(by.binding('myForm.userName.$valid'));
16522        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
16523        var lastNameError = element(by.binding('myForm.lastName.$error'));
16524        var formValid = element(by.binding('myForm.$valid'));
16525        var userNameInput = element(by.model('user.name'));
16526        var userLastInput = element(by.model('user.last'));
16527
16528        it('should initialize to model', function() {
16529          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
16530          expect(userNameValid.getText()).toContain('true');
16531          expect(formValid.getText()).toContain('true');
16532        });
16533
16534        it('should be invalid if empty when required', function() {
16535          userNameInput.clear();
16536          userNameInput.sendKeys('');
16537
16538          expect(user.getText()).toContain('{"last":"visitor"}');
16539          expect(userNameValid.getText()).toContain('false');
16540          expect(formValid.getText()).toContain('false');
16541        });
16542
16543        it('should be valid if empty when min length is set', function() {
16544          userLastInput.clear();
16545          userLastInput.sendKeys('');
16546
16547          expect(user.getText()).toContain('{"name":"guest","last":""}');
16548          expect(lastNameValid.getText()).toContain('true');
16549          expect(formValid.getText()).toContain('true');
16550        });
16551
16552        it('should be invalid if less than required min length', function() {
16553          userLastInput.clear();
16554          userLastInput.sendKeys('xx');
16555
16556          expect(user.getText()).toContain('{"name":"guest"}');
16557          expect(lastNameValid.getText()).toContain('false');
16558          expect(lastNameError.getText()).toContain('minlength');
16559          expect(formValid.getText()).toContain('false');
16560        });
16561
16562        it('should be invalid if longer than max length', function() {
16563          userLastInput.clear();
16564          userLastInput.sendKeys('some ridiculously long name');
16565
16566          expect(user.getText()).toContain('{"name":"guest"}');
16567          expect(lastNameValid.getText()).toContain('false');
16568          expect(lastNameError.getText()).toContain('maxlength');
16569          expect(formValid.getText()).toContain('false');
16570        });
16571      </doc:protractor>
16572    </doc:example>
16573 */
16574var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
16575  return {
16576    restrict: 'E',
16577    require: '?ngModel',
16578    link: function(scope, element, attr, ctrl) {
16579      if (ctrl) {
16580        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
16581                                                            $browser);
16582      }
16583    }
16584  };
16585}];
16586
16587var VALID_CLASS = 'ng-valid',
16588    INVALID_CLASS = 'ng-invalid',
16589    PRISTINE_CLASS = 'ng-pristine',
16590    DIRTY_CLASS = 'ng-dirty';
16591
16592/**
16593 * @ngdoc object
16594 * @name ng.directive:ngModel.NgModelController
16595 *
16596 * @property {string} $viewValue Actual string value in the view.
16597 * @property {*} $modelValue The value in the model, that the control is bound to.
16598 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
16599       the control reads value from the DOM.  Each function is called, in turn, passing the value
16600       through to the next. Used to sanitize / convert the value as well as validation.
16601       For validation, the parsers should update the validity state using
16602       {@link ng.directive:ngModel.NgModelController#methods_$setValidity $setValidity()},
16603       and return `undefined` for invalid values.
16604
16605 *
16606 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
16607       the model value changes. Each function is called, in turn, passing the value through to the
16608       next. Used to format / convert values for display in the control and validation.
16609 *      <pre>
16610 *      function formatter(value) {
16611 *        if (value) {
16612 *          return value.toUpperCase();
16613 *        }
16614 *      }
16615 *      ngModel.$formatters.push(formatter);
16616 *      </pre>
16617 *
16618 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
16619 *     view value has changed. It is called with no arguments, and its return value is ignored.
16620 *     This can be used in place of additional $watches against the model value.
16621 *
16622 * @property {Object} $error An object hash with all errors as keys.
16623 *
16624 * @property {boolean} $pristine True if user has not interacted with the control yet.
16625 * @property {boolean} $dirty True if user has already interacted with the control.
16626 * @property {boolean} $valid True if there is no error.
16627 * @property {boolean} $invalid True if at least one error on the control.
16628 *
16629 * @description
16630 *
16631 * `NgModelController` provides API for the `ng-model` directive. The controller contains
16632 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
16633 * purposefully does not contain any logic which deals with DOM rendering or listening to
16634 * DOM events. Such DOM related logic should be provided by other directives which make use of
16635 * `NgModelController` for data-binding.
16636 *
16637 * ## Custom Control Example
16638 * This example shows how to use `NgModelController` with a custom control to achieve
16639 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
16640 * collaborate together to achieve the desired result.
16641 *
16642 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
16643 * contents be edited in place by the user.  This will not work on older browsers.
16644 *
16645 * <example module="customControl">
16646    <file name="style.css">
16647      [contenteditable] {
16648        border: 1px solid black;
16649        background-color: white;
16650        min-height: 20px;
16651      }
16652
16653      .ng-invalid {
16654        border: 1px solid red;
16655      }
16656
16657    </file>
16658    <file name="script.js">
16659      angular.module('customControl', []).
16660        directive('contenteditable', function() {
16661          return {
16662            restrict: 'A', // only activate on element attribute
16663            require: '?ngModel', // get a hold of NgModelController
16664            link: function(scope, element, attrs, ngModel) {
16665              if(!ngModel) return; // do nothing if no ng-model
16666
16667              // Specify how UI should be updated
16668              ngModel.$render = function() {
16669                element.html(ngModel.$viewValue || '');
16670              };
16671
16672              // Listen for change events to enable binding
16673              element.on('blur keyup change', function() {
16674                scope.$apply(read);
16675              });
16676              read(); // initialize
16677
16678              // Write data to the model
16679              function read() {
16680                var html = element.html();
16681                // When we clear the content editable the browser leaves a <br> behind
16682                // If strip-br attribute is provided then we strip this out
16683                if( attrs.stripBr && html == '<br>' ) {
16684                  html = '';
16685                }
16686                ngModel.$setViewValue(html);
16687              }
16688            }
16689          };
16690        });
16691    </file>
16692    <file name="index.html">
16693      <form name="myForm">
16694       <div contenteditable
16695            name="myWidget" ng-model="userContent"
16696            strip-br="true"
16697            required>Change me!</div>
16698        <span ng-show="myForm.myWidget.$error.required">Required!</span>
16699       <hr>
16700       <textarea ng-model="userContent"></textarea>
16701      </form>
16702    </file>
16703    <file name="protractorTest.js">
16704      it('should data-bind and become invalid', function() {
16705        if (browser.params.browser = 'safari') {
16706          // SafariDriver can't handle contenteditable.
16707          return;
16708        };
16709        var contentEditable = element(by.css('.doc-example-live [contenteditable]'));
16710
16711        expect(contentEditable.getText()).toEqual('Change me!');
16712
16713        // Firefox driver doesn't trigger the proper events on 'clear', so do this hack
16714        contentEditable.click();
16715        contentEditable.sendKeys(protractor.Key.chord(protractor.Key.COMMAND, "a"));
16716        contentEditable.sendKeys(protractor.Key.BACK_SPACE);
16717
16718        expect(contentEditable.getText()).toEqual('');
16719        expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
16720      });
16721    </file>
16722 * </example>
16723 *
16724 *
16725 */
16726var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
16727    function($scope, $exceptionHandler, $attr, $element, $parse) {
16728  this.$viewValue = Number.NaN;
16729  this.$modelValue = Number.NaN;
16730  this.$parsers = [];
16731  this.$formatters = [];
16732  this.$viewChangeListeners = [];
16733  this.$pristine = true;
16734  this.$dirty = false;
16735  this.$valid = true;
16736  this.$invalid = false;
16737  this.$name = $attr.name;
16738
16739  var ngModelGet = $parse($attr.ngModel),
16740      ngModelSet = ngModelGet.assign;
16741
16742  if (!ngModelSet) {
16743    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
16744        $attr.ngModel, startingTag($element));
16745  }
16746
16747  /**
16748   * @ngdoc function
16749   * @name ng.directive:ngModel.NgModelController#$render
16750   * @methodOf ng.directive:ngModel.NgModelController
16751   *
16752   * @description
16753   * Called when the view needs to be updated. It is expected that the user of the ng-model
16754   * directive will implement this method.
16755   */
16756  this.$render = noop;
16757
16758  /**
16759   * @ngdoc function
16760   * @name { ng.directive:ngModel.NgModelController#$isEmpty
16761   * @methodOf ng.directive:ngModel.NgModelController
16762   *
16763   * @description
16764   * This is called when we need to determine if the value of the input is empty.
16765   *
16766   * For instance, the required directive does this to work out if the input has data or not.
16767   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
16768   *
16769   * You can override this for input directives whose concept of being empty is different to the
16770   * default. The `checkboxInputType` directive does this because in 
16770its case a value of `false`
16771   * implies empty.
16772   * 
16773   * @param {*} value Reference to check.
16774   * @returns {boolean} True if `value` is empty.
16775   */
16776  this.$isEmpty = function(value) {
16777    return isUndefined(value) || value === '' || value === null || value !== value;
16778  };
16779
16780  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
16781      invalidCount = 0, // used to easily determine if we are valid
16782      $error = this.$error = {}; // keep invalid keys here
16783
16784
16785  // Setup initial state of the control
16786  $element.addClass(PRISTINE_CLASS);
16787  toggleValidCss(true);
16788
16789  // convenience method for easy toggling of classes
16790  function toggleValidCss(isValid, validationErrorKey) {
16791    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16792    $element.
16793      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
16794      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
16795  }
16796
16797  /**
16798   * @ngdoc function
16799   * @name ng.directive:ngModel.NgModelController#$setValidity
16800   * @methodOf ng.directive:ngModel.NgModelController
16801   *
16802   * @description
16803   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
16804   * does not notify form if given validator is already marked as invalid).
16805   *
16806   * This method should be called by validators - i.e. the parser or formatter functions.
16807   *
16808   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
16809   *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
16810   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
16811   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
16812   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
16813   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
16814   */
16815  this.$setValidity = function(validationErrorKey, isValid) {
16816    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
16817    // jshint -W018
16818    if ($error[validationErrorKey] === !isValid) return;
16819    // jshint +W018
16820
16821    if (isValid) {
16822      if ($error[validationErrorKey]) invalidCount--;
16823      if (!invalidCount) {
16824        toggleValidCss(true);
16825        this.$valid = true;
16826        this.$invalid = false;
16827      }
16828    } else {
16829      toggleValidCss(false);
16830      this.$invalid = true;
16831      this.$valid = false;
16832      invalidCount++;
16833    }
16834
16835    $error[validationErrorKey] = !isValid;
16836    toggleValidCss(isValid, validationErrorKey);
16837
16838    parentForm.$setValidity(validationErrorKey, isValid, this);
16839  };
16840
16841  /**
16842   * @ngdoc function
16843   * @name ng.directive:ngModel.NgModelController#$setPristine
16844   * @methodOf ng.directive:ngModel.NgModelController
16845   *
16846   * @description
16847   * Sets the control to its pristine state.
16848   *
16849   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
16850   * state (ng-pristine class).
16851   */
16852  this.$setPristine = function () {
16853    this.$dirty = false;
16854    this.$pristine = true;
16855    $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
16856  };
16857
16858  /**
16859   * @ngdoc function
16860   * @name ng.directive:ngModel.NgModelController#$setViewValue
16861   * @methodOf ng.directive:ngModel.NgModelController
16862   *
16863   * @description
16864   * Update the view value.
16865   *
16866   * This method should be called when the view value changes, typically from within a DOM event handler.
16867   * For example {@link ng.directive:input input} and
16868   * {@link ng.directive:select select} directives call it.
16869   *
16870   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
16871   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
16872   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
16873   *
16874   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
16875   *
16876   * Note that calling this function does not trigger a `$digest`.
16877   *
16878   * @param {string} value Value from the view.
16879   */
16880  this.$setViewValue = function(value) {
16881    this.$viewValue = value;
16882
16883    // change to dirty
16884    if (this.$pristine) {
16885      this.$dirty = true;
16886      this.$pristine = false;
16887      $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
16888      parentForm.$setDirty();
16889    }
16890
16891    forEach(this.$parsers, function(fn) {
16892      value = fn(value);
16893    });
16894
16895    if (this.$modelValue !== value) {
16896      this.$modelValue = value;
16897      ngModelSet($scope, value);
16898      forEach(this.$viewChangeListeners, function(listener) {
16899        try {
16900          listener();
16901        } catch(e) {
16902          $exceptionHandler(e);
16903        }
16904      });
16905    }
16906  };
16907
16908  // model -> value
16909  var ctrl = this;
16910
16911  $scope.$watch(function ngModelWatch() {
16912    var value = ngModelGet($scope);
16913
16914    // if scope model value and ngModel value are out of sync
16915    if (ctrl.$modelValue !== value) {
16916
16917      var formatters = ctrl.$formatters,
16918          idx = formatters.length;
16919
16920      ctrl.$modelValue = value;
16921      while(idx--) {
16922        value = formatters[idx](value);
16923      }
16924
16925      if (ctrl.$viewValue !== value) {
16926        ctrl.$viewValue = value;
16927        ctrl.$render();
16928      }
16929    }
16930
16931    return value;
16932  });
16933}];
16934
16935
16936/**
16937 * @ngdoc directive
16938 * @name ng.directive:ngModel
16939 *
16940 * @element input
16941 *
16942 * @description
16943 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
16944 * property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController},
16945 * which is created and exposed by this directive.
16946 *
16947 * `ngModel` is responsible for:
16948 *
16949 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
16950 *   require.
16951 * - Providing validation behavior (i.e. required, number, email, url).
16952 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
16953 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`).
16954 * - Registering the control with its parent {@link ng.directive:form form}.
16955 *
16956 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
16957 * current scope. If the property doesn't already exist on this scope, it will be created
16958 * implicitly and added to the scope.
16959 *
16960 * For best practices on using `ngModel`, see:
16961 *
16962 *  - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes}
16963 *
16964 * For basic examples, how to use `ngModel`, see:
16965 *
16966 *  - {@link ng.directive:input input}
16967 *    - {@link ng.directive:input.text text}
16968 *    - {@link ng.directive:input.checkbox checkbox}
16969 *    - {@link ng.directive:input.radio radio}
16970 *    - {@link ng.directive:input.number number}
16971 *    - {@link ng.directive:input.email email}
16972 *    - {@link ng.directive:input.url url}
16973 *  - {@link ng.directive:select select}
16974 *  - {@link ng.directive:textarea textarea}
16975 *
16976 */
16977var ngModelDirective = function() {
16978  return {
16979    require: ['ngModel', '^?form'],
16980    controller: NgModelController,
16981    link: function(scope, element, attr, ctrls) {
16982      // notify others, especially parent forms
16983
16984      var modelCtrl = ctrls[0],
16985          formCtrl = ctrls[1] || nullFormCtrl;
16986
16987      formCtrl.$addControl(modelCtrl);
16988
16989      scope.$on('$destroy', function() {
16990        formCtrl.$removeControl(modelCtrl);
16991      });
16992    }
16993  };
16994};
16995
16996
16997/**
16998 * @ngdoc directive
16999 * @name ng.directive:ngChange
17000 *
17001 * @description
17002 * Evaluate the given expression when the user changes the input.
17003 * The expression is evaluated immediately, unlike the JavaScript onchange event
17004 * which only triggers at the end of a change (usually, when the user leaves the
17005 * form element or presses the return key).
17006 * The expression is not evaluated when the value change is coming from the model.
17007 *
17008 * Note, this directive requires `ngModel` to be present.
17009 *
17010 * @element input
17011 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17012 * in input value.
17013 *
17014 * @example
17015 * <doc:example>
17016 *   <doc:source>
17017 *     <script>
17018 *       function Controller($scope) {
17019 *         $scope.counter = 0;
17020 *         $scope.change = function() {
17021 *           $scope.counter++;
17022 *         };
17023 *       }
17024 *     </script>
17025 *     <div ng-controller="Controller">
17026 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17027 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17028 *       <label for="ng-change-example2">Confirmed</label><br />
17029 *       <tt>debug = {{confirmed}}</tt><br/>
17030 *       <tt>counter = {{counter}}</tt><br/>
17031 *     </div>
17032 *   </doc:source>
17033 *   <doc:protractor>
17034 *     var counter = element(by.binding('counter'));
17035 *     var debug = element(by.binding('confirmed'));
17036 *
17037 *     it('should evaluate the expression if changing from view', function() {
17038 *       expect(counter.getText()).toContain('0');
17039 *
17040 *       element(by.id('ng-change-example1')).click();
17041 *
17042 *       expect(counter.getText()).toContain('1');
17043 *       expect(debug.getText()).toContain('true');
17044 *     });
17045 *
17046 *     it('should not evaluate the expression if changing from model', function() {
17047 *       element(by.id('ng-change-example2')).click();
17048
17049 *       expect(counter.getText()).toContain('0');
17050 *       expect(debug.getText()).toContain('true');
17051 *     });
17052 *   </doc:protractor>
17053 * </doc:example>
17054 */
17055var ngChangeDirective = valueFn({
17056  require: 'ngModel',
17057  link: function(scope, element, attr, ctrl) {
17058    ctrl.$viewChangeListeners.push(function() {
17059      scope.$eval(attr.ngChange);
17060    });
17061  }
17062});
17063
17064
17065var requiredDirective = function() {
17066  return {
17067    require: '?ngModel',
17068    link: function(scope, elm, attr, ctrl) {
17069      if (!ctrl) return;
17070      attr.required = true; // force truthy in case we are on non input element
17071
17072      var validator = function(value) {
17073        if (attr.required && ctrl.$isEmpty(value)) {
17074          ctrl.$setValidity('required', false);
17075          return;
17076        } else {
17077          ctrl.$setValidity('required', true);
17078          return value;
17079        }
17080      };
17081
17082      ctrl.$formatters.push(validator);
17083      ctrl.$parsers.unshift(validator);
17084
17085      attr.$observe('required', function() {
17086        validator(ctrl.$viewValue);
17087      });
17088    }
17089  };
17090};
17091
17092
17093/**
17094 * @ngdoc directive
17095 * @name ng.directive:ngList
17096 *
17097 * @description
17098 * Text input that converts between a delimited string and an array of strings. The delimiter
17099 * can be a fixed string (by default a comma) or a regular expression.
17100 *
17101 * @element input
17102 * @param {string=} ngList optional delimiter that should be used to split the value. If
17103 *   specified in form `/something/` then the value will be converted into a regular expression.
17104 *
17105 * @example
17106    <doc:example>
17107      <doc:source>
17108       <script>
17109         function Ctrl($scope) {
17110           $scope.names = ['igor', 'misko', 'vojta'];
17111         }
17112       </script>
17113       <form name="myForm" ng-controller="Ctrl">
17114         List: <input name="namesInput" ng-model="names" ng-list required>
17115         <span class="error" ng-show="myForm.namesInput.$error.required">
17116           Required!</span>
17117         <br>
17118         <tt>names = {{names}}</tt><br/>
17119         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
17120         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
17121         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
17122         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
17123        </form>
17124      </doc:source>
17125      <doc:protractor>
17126        var listInput = element(by.model('names'));
17127        var names = element(by.binding('{{names}}'));
17128        var valid = element(by.binding('myForm.namesInput.$valid'));
17129        var error = element(by.css('span.error'));
17130
17131        it('should initialize to model', function() {
17132          expect(names.getText()).toContain('["igor","misko","vojta"]');
17133          expect(valid.getText()).toContain('true');
17134          expect(error.getCssValue('display')).toBe('none');
17135        });
17136
17137        it('should be invalid if empty', function() {
17138          listInput.clear();
17139          listInput.sendKeys('');
17140
17141          expect(names.getText()).toContain('');
17142          expect(valid.getText()).toContain('false');
17143          expect(error.getCssValue('display')).not.toBe('none');        });
17144      </doc:protractor>
17145    </doc:example>
17146 */
17147var ngListDirective = function() {
17148  return {
17149    require: 'ngModel',
17150    link: function(scope, element, attr, ctrl) {
17151      var match = /\/(.*)\//.exec(attr.ngList),
17152          separator = match && new RegExp(match[1]) || attr.ngList || ',';
17153
17154      var parse = function(viewValue) {
17155        // If the viewValue is invalid (say required but empty) it will be `undefined`
17156        if (isUndefined(viewValue)) return;
17157
17158        var list = [];
17159
17160        if (viewValue) {
17161          forEach(viewValue.split(separator), function(value) {
17162            if (value) list.push(trim(value));
17163          });
17164        }
17165
17166        return list;
17167      };
17168
17169      ctrl.$parsers.push(parse);
17170      ctrl.$formatters.push(function(value) {
17171        if (isArray(value)) {
17172          return value.join(', ');
17173        }
17174
17175        return undefined;
17176      });
17177
17178      // Override the standard $isEmpty because an empty array means the input is empty.
17179      ctrl.$isEmpty = function(value) {
17180        return !value || !value.length;
17181      };
17182    }
17183  };
17184};
17185
17186
17187var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
17188/**
17189 * @ngdoc directive
17190 * @name ng.directive:ngValue
17191 *
17192 * @description
17193 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
17194 * that when the element is selected, the `ngModel` of that element is set to the
17195 * bound value.
17196 *
17197 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
17198 * shown below.
17199 *
17200 * @element input
17201 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
17202 *   of the `input` element
17203 *
17204 * @example
17205    <doc:example>
17206      <doc:source>
17207       <script>
17208          function Ctrl($scope) {
17209            $scope.names = ['pizza', 'unicorns', 'robots'];
17210            $scope.my = { favorite: 'unicorns' };
17211          }
17212       </script>
17213        <form ng-controller="Ctrl">
17214          <h2>Which is your favorite?</h2>
17215            <label ng-repeat="name in names" for="{{name}}">
17216              {{name}}
17217              <input type="radio"
17218                     ng-model="my.favorite"
17219                     ng-value="name"
17220                     id="{{name}}"
17221                     name="favorite">
17222            </label>
17223          <div>You chose {{my.favorite}}</div>
17224        </form>
17225      </doc:source>
17226      <doc:protractor>
17227        var favorite = element(by.binding('my.favorite'));
17228
17229        it('should initialize to model', function() {
17230          expect(favorite.getText()).toContain('unicorns');
17231        });
17232        it('should bind the values to the inputs', function() {
17233          element.all(by.model('my.favorite')).get(0).click();
17234          expect(favorite.getText()).toContain('pizza');
17235        });
17236      </doc:protractor>
17237    </doc:example>
17238 */
17239var ngValueDirective = function() {
17240  return {
17241    priority: 100,
17242    compile: function(tpl, tplAttr) {
17243      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
17244        return function ngValueConstantLink(scope, elm, attr) {
17245          attr.$set('value', scope.$eval(attr.ngValue));
17246        };
17247      } else {
17248        return function ngValueLink(scope, elm, attr) {
17249          scope.$watch(attr.ngValue, function valueWatchAction(value) {
17250            attr.$set('value', value);
17251          });
17252        };
17253      }
17254    }
17255  };
17256};
17257
17258/**
17259 * @ngdoc directive
17260 * @name ng.directive:ngBind
17261 * @restrict AC
17262 *
17263 * @description
17264 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
17265 * with the value of a given expression, and to update the text content when the value of that
17266 * expression changes.
17267 *
17268 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
17269 * `{{ expression }}` which is similar but less verbose.
17270 *
17271 * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
17272 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
17273 * element attribute, it makes the bindings invisible to the user while the page is loading.
17274 *
17275 * An alternative solution to this problem would be using the
17276 * {@link ng.directive:ngCloak ngCloak} directive.
17277 *
17278 *
17279 * @element ANY
17280 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
17281 *
17282 * @example
17283 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
17284   <doc:example>
17285     <doc:source>
17286       <script>
17287         function Ctrl($scope) {
17288           $scope.name = 'Whirled';
17289         }
17290       </script>
17291       <div ng-controller="Ctrl">
17292         Enter name: <input type="text" ng-model="name"><br>
17293         Hello <span ng-bind="name"></span>!
17294       </div>
17295     </doc:source>
17296     <doc:protractor>
17297       it('should check ng-bind', function() {
17298         var exampleContainer = $('.doc-example-live');
17299         var nameInput = element(by.model('name'));
17300
17301         expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('Whirled');
17302         nameInput.clear();
17303         nameInput.sendKeys('world');
17304         expect(exampleContainer.findElement(by.binding('name')).getText()).toBe('world');
17305       });
17306     </doc:protractor>
17307   </doc:example>
17308 */
17309var ngBindDirective = ngDirective(function(scope, element, attr) {
17310  element.addClass('ng-binding').data('$binding', attr.ngBind);
17311  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
17312    // We are purposefully using == here rather than === because we want to
17313    // catch when value is "null or undefined"
17314    // jshint -W041
17315    element.text(value == undefined ? '' : value);
17316  });
17317});
17318
17319
17320/**
17321 * @ngdoc directive
17322 * @name ng.directive:ngBindTemplate
17323 *
17324 * @description
17325 * The `ngBindTemplate` directive specifies that the element
17326 * text content should be replaced with the interpolation of the template
17327 * in the `ngBindTemplate` attribute.
17328 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
17329 * expressions. This directive is needed since some HTML elements
17330 * (such as TITLE and OPTION) cannot contain SPAN elements.
17331 *
17332 * @element ANY
17333 * @param {string} ngBindTemplate template of form
17334 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
17335 *
17336 * @example
17337 * Try it here: enter text in text box and watch the greeting change.
17338   <doc:example>
17339     <doc:source>
17340       <script>
17341         function Ctrl($scope) {
17342           $scope.salutation = 'Hello';
17343           $scope.name = 'World';
17344         }
17345       </script>
17346       <div ng-controller="Ctrl">
17347        Salutation: <input type="text" ng-model="salutation"><br>
17348        Name: <input type="text" ng-model="name"><br>
17349        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
17350       </div>
17351     </doc:source>
17352     <doc:protractor>
17353       it('should check ng-bind', function() {
17354         var salutationElem = element(by.binding('salutation'));
17355         var salutationInput = element(by.model('salutation'));
17356         var nameInput = element(by.model('name'));
17357
17358         expect(salutationElem.getText()).toBe('Hello World!');
17359
17360         salutationInput.clear();
17361         salutationInput.sendKeys('Greetings');
17362         nameInput.clear();
17363         nameInput.sendKeys('user');
17364
17365         expect(salutationElem.getText()).toBe('Greetings user!');
17366       });
17367     </doc:protractor>
17368   </doc:example>
17369 */
17370var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
17371  return function(scope, element, attr) {
17372    // TODO: move this to scenario runner
17373    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
17374    element.addClass('ng-binding').data('$binding', interpolateFn);
17375    attr.$observe('ngBindTemplate', function(value) {
17376      element.text(value);
17377    });
17378  };
17379}];
17380
17381
17382/**
17383 * @ngdoc directive
17384 * @name ng.directive:ngBindHtml
17385 *
17386 * @description
17387 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
17388 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
17389 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
17390 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
17391 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
17392 * an explicitly trusted value via {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}.  See the example
17393 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
17394 *
17395 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
17396 * will have an exception (instead of an exploit.)
17397 *
17398 * @element ANY
17399 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
17400 *
17401 * @example
17402   Try it here: enter text in text box and watch the greeting change.
17403 
17404   <example module="ngBindHtmlExample" deps="angular-sanitize.js">
17405     <file name="index.html">
17406       <div ng-controller="ngBindHtmlCtrl">
17407        <p ng-bind-html="myHTML"></p>
17408       </div>
17409     </file>
17410     
17411     <file name="script.js">
17412       angular.module('ngBindHtmlExample', ['ngSanitize'])
17413
17414       .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
17415         $scope.myHTML =
17416            'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
17417       }]);
17418     </file>
17419
17420     <file name="protractorTest.js">
17421       it('should check ng-bind-html', function() {
17422         expect(element(by.binding('myHTML')).getText()).toBe(
17423             'I am an HTMLstring with links! and other stuff');
17424       });
17425     </file>
17426   </example>
17427 */
17428var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
17429  return function(scope, element, attr) {
17430    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
17431
17432    var parsed = $parse(attr.ngBindHtml);
17433    function getStringValue() { return (parsed(scope) || '').toString(); }
17434
17435    scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
17436      element.html($sce.getTrustedHtml(parsed(scope)) || '');
17437    });
17438  };
17439}];
17440
17441function classDirective(name, selector) {
17442  name = 'ngClass' + name;
17443  return function() {
17444    return {
17445      restrict: 'AC',
17446      link: function(scope, element, attr) {
17447        var oldVal;
17448
17449        scope.$watch(attr[name], ngClassWatchAction, true);
17450
17451        attr.$observe('class', function(value) {
17452          ngClassWatchAction(scope.$eval(attr[name]));
17453        });
17454
17455
17456        if (name !== 'ngClass') {
17457          scope.$watch('$index', function($index, old$index) {
17458            // jshint bitwise: false
17459            var mod = $index & 1;
17460            if (mod !== old$index & 1) {
17461              var classes = flattenClasses(scope.$eval(attr[name]));
17462              mod === selector ?
17463                attr.$addClass(classes) :
17464                attr.$removeClass(classes);
17465            }
17466          });
17467        }
17468
17469
17470        function ngClassWatchAction(newVal) {
17471          if (selector === true || scope.$index % 2 === selector) {
17472            var newClasses = flattenClasses(newVal || '');
17473            if(!oldVal) {
17474              attr.$addClass(newClasses);
17475            } else if(!equals(newVal,oldVal)) {
17476              attr.$updateClass(newClasses, flattenClasses(oldVal));
17477            }
17478          }
17479          oldVal = copy(newVal);
17480        }
17481
17482
17483        function flattenClasses(classVal) {
17484          if(isArray(classVal)) {
17485            return classVal.join(' ');
17486          } else if (isObject(classVal)) {
17487            var classes = [], i = 0;
17488            forEach(classVal, function(v, k) {
17489              if (v) {
17490                classes.push(k);
17491              }
17492            });
17493            return classes.join(' ');
17494          }
17495
17496          return classVal;
17497        }
17498      }
17499    };
17500  };
17501}
17502
17503/**
17504 * @ngdoc directive
17505 * @name ng.directive:ngClass
17506 * @restrict AC
17507 *
17508 * @description
17509 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
17510 * an expression that represents all classes to be added.
17511 *
17512 * The directive won't add duplicate classes if a particular class was already set.
17513 *
17514 * When the expression changes, the previously added classes are removed and only then the
17515 * new classes are added.
17516 *
17517 * @animations
17518 * add - happens just before the class is applied to the element
17519 * remove - happens just before the class is removed from the element
17520 *
17521 * @element ANY
17522 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
17523 *   of the evaluation can be a string representing space delimited class
17524 *   names, an array, or a map of class names to boolean values. In the case of a map, the
17525 *   names of the properties whose values are truthy will be added as css classes to the
17526 *   element.
17527 *
17528 * @example Example that demonstrates basic bindings via ngClass directive.
17529   <example>
17530     <file name="index.html">
17531       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
17532       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
17533       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
17534       <input type="checkbox" ng-model="error"> error (apply "red" class)
17535       <hr>
17536       <p ng-class="style">Using String Syntax</p>
17537       <input type="text" ng-model="style" placeholder="Type: bold strike red">
17538       <hr>
17539       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
17540       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
17541       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
17542       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
17543     </file>
17544     <file name="style.css">
17545       .strike {
17546         text-decoration: line-through;
17547       }
17548       .bold {
17549           font-weight: bold;
17550       }
17551       .red {
17552           color: red;
17553       }
17554     </file>
17555     <file name="protractorTest.js">
17556       var ps = element.all(by.css('.doc-example-live p'));
17557
17558       it('should let you toggle the class', function() {
17559
17560         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
17561         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
17562
17563         element(by.model('important')).click();
17564         expect(ps.first().getAttribute('class')).toMatch(/bold/);
17565
17566         element(by.model('error')).click();
17567         expect(ps.first().getAttribute('class')).toMatch(/red/);
17568       });
17569
17570       it('should let you toggle string example', function() {
17571         expect(ps.get(1).getAttribute('class')).toBe('');
17572         element(by.model('style')).clear();
17573         element(by.model('style')).sendKeys('red');
17574         expect(ps.get(1).getAttribute('class')).toBe('red');
17575       });
17576
17577       it('array example should have 3 classes', function() {
17578         expect(ps.last().getAttribute('class')).toBe('');
17579         element(by.model('style1')).sendKeys('bold');
17580         element(by.model('style2')).sendKeys('strike');
17581         element(by.model('style3')).sendKeys('red');
17582         expect(ps.last().getAttribute('class')).toBe('bold strike red');
17583       });
17584     </file>
17585   </example>
17586
17587   ## Animations
17588
17589   The example below demonstrates how to perform animations using ngClass.
17590
17591   <example animations="true">
17592     <file name="index.html">
17593      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
17594      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
17595      <br>
17596      <span class="base-class" ng-class="myVar">Sample Text</span>
17597     </file>
17598     <file name="style.css">
17599       .base-class {
17600         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17601         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17602       }
17603
17604       .base-class.my-class {
17605         color: red;
17606         font-size:3em;
17607       }
17608     </file>
17609     <file name="protractorTest.js">
17610       it('should check ng-class', function() {
17611         expect(element(by.css('.base-class')).getAttribute('class')).not.
17612           toMatch(/my-class/);
17613
17614         element(by.id('setbtn')).click();
17615
17616         expect(element(by.css('.base-class')).getAttribute('class')).
17617           toMatch(/my-class/);
17618
17619         element(by.id('clearbtn')).click();
17620
17621         expect(element(by.css('.base-class')).getAttribute('class')).not.
17622           toMatch(/my-class/);
17623       });
17624     </file>
17625   </example>
17626
17627
17628   ## ngClass and pre-existing CSS3 Transitions/Animations
17629   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
17630   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
17631   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
17632   to view the step by step details of {@link ngAnimate.$animate#methods_addclass $animate.addClass} and
17633   {@link ngAnimate.$animate#methods_removeclass $animate.removeClass}.
17634 */
17635var ngClassDirective = classDirective('', true);
17636
17637/**
17638 * @ngdoc directive
17639 * @name ng.directive:ngClassOdd
17640 * @restrict AC
17641 *
17642 * @description
17643 * The `ngClassOdd` and `ngClassEven` directives work exactly as
17644 * {@link ng.directive:ngClass ngClass}, except they work in
17645 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
17646 *
17647 * This directive can be applied only within the scope of an
17648 * {@link ng.directive:ngRepeat ngRepeat}.
17649 *
17650 * @element ANY
17651 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
17652 *   of the evaluation can be a string representing space delimited class names or an array.
17653 *
17654 * @example
17655   <example>
17656     <file name="index.html">
17657        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
17658          <li ng-repeat="name in names">
17659           <span ng-class-odd="'odd'" ng-class-even="'even'">
17660             {{name}}
17661           </span>
17662          </li>
17663        </ol>
17664     </file>
17665     <file name="style.css">
17666       .odd {
17667         color: red;
17668       }
17669       .even {
17670         color: blue;
17671       }
17672     </file>
17673     <file name="protractorTest.js">
17674       it('should check ng-class-odd and ng-class-even', function() {
17675         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
17676           toMatch(/odd/);
17677         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
17678           toMatch(/even/);
17679       });
17680     </file>
17681   </example>
17682 */
17683var ngClassOddDirective = classDirective('Odd', 0);
17684
17685/**
17686 * @ngdoc directive
17687 * @name ng.directive:ngClassEven
17688 * @restrict AC
17689 *
17690 * @description
17691 * The `ngClassOdd` and `ngClassEven` directives work exactly as
17692 * {@link ng.directive:ngClass ngClass}, except they work in
17693 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
17694 *
17695 * This directive can be applied only within the scope of an
17696 * {@link ng.directive:ngRepeat ngRepeat}.
17697 *
17698 * @element ANY
17699 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
17700 *   result of the evaluation can be a string representing space delimited class names or an array.
17701 *
17702 * @example
17703   <example>
17704     <file name="index.html">
17705        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
17706          <li ng-repeat="name in names">
17707           <span ng-class-odd="'odd'" ng-class-even="'even'">
17708             {{name}} &nbsp; &nbsp; &nbsp;
17709           </span>
17710          </li>
17711        </ol>
17712     </file>
17713     <file name="style.css">
17714       .odd {
17715         color: red;
17716       }
17717       .even {
17718         color: blue;
17719       }
17720     </file>
17721     <file name="protractorTest.js">
17722       it('should check ng-class-odd and ng-class-even', function() {
17723         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
17724           toMatch(/odd/);
17725         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
17726           toMatch(/even/);
17727       });
17728     </file>
17729   </example>
17730 */
17731var ngClassEvenDirective = classDirective('Even', 1);
17732
17733/**
17734 * @ngdoc directive
17735 * @name ng.directive:ngCloak
17736 * @restrict AC
17737 *
17738 * @description
17739 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
17740 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
17741 * directive to avoid the undesirable flicker effect caused by the html template display.
17742 *
17743 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
17744 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
17745 * of the browser view.
17746 *
17747 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
17748 * `angular.min.js`.
17749 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
17750 *
17751 * <pre>
17752 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
17753 *   display: none !important;
17754 * }
17755 * </pre>
17756 *
17757 * When this css rule is loaded by the browser, all html elements (including their children) that
17758 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
17759 * during the compilation of the template it deletes the `ngCloak` element attribute, making
17760 * the compiled element visible.
17761 *
17762 * For the best result, the `angular.js` script must be loaded in the head section of the html
17763 * document; alternatively, the css rule above must be included in the external stylesheet of the
17764 * application.
17765 *
17766 * Legacy browsers, like IE7, do not provide attribute selector support (a
17766dded in CSS 2.1) so they
17767 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
17768 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
17769 *
17770 * @element ANY
17771 *
17772 * @example
17773   <doc:example>
17774     <doc:source>
17775        <div id="template1" ng-cloak>{{ 'hello' }}</div>
17776        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
17777     </doc:source>
17778     <doc:protractor>
17779       it('should remove the template directive and css class', function() {
17780         expect($('.doc-example-live #template1').getAttribute('ng-cloak')).
17781           toBeNull();
17782         expect($('.doc-example-live #template2').getAttribute('ng-cloak')).
17783           toBeNull();
17784       });
17785     </doc:protractor>
17786   </doc:example>
17787 *
17788 */
17789var ngCloakDirective = ngDirective({
17790  compile: function(element, attr) {
17791    attr.$set('ngCloak', undefined);
17792    element.removeClass('ng-cloak');
17793  }
17794});
17795
17796/**
17797 * @ngdoc directive
17798 * @name ng.directive:ngController
17799 *
17800 * @description
17801 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
17802 * supports the principles behind the Model-View-Controller design pattern.
17803 *
17804 * MVC components in angular:
17805 *
17806 * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
17807 *   are accessed through bindings.
17808 * * View — The template (HTML with data bindings) that is rendered into the View.
17809 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
17810 *   logic behind the application to decorate the scope with functions and values
17811 *
17812 * Note that you can also attach controllers to the DOM by declaring it in a route definition
17813 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
17814 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
17815 * and executed twice.
17816 *
17817 * @element ANY
17818 * @scope
17819 * @param {expression} ngController Name of a globally accessible constructor function or an
17820 *     {@link guide/expression expression} that on the current scope evaluates to a
17821 *     constructor function. The controller instance can be published into a scope property
17822 *     by specifying `as propertyName`.
17823 *
17824 * @example
17825 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
17826 * greeting are methods declared on the controller (see source tab). These methods can
17827 * easily be called from the angular markup. Notice that the scope becomes the `this` for the
17828 * controller's instance. This allows for easy access to the view data from the controller. Also
17829 * notice that any changes to the data are automatically reflected in the View without the need
17830 * for a manual update. The example is shown in two different declaration styles you may use
17831 * according to preference.
17832   <doc:example>
17833     <doc:source>
17834      <script>
17835        function SettingsController1() {
17836          this.name = "John Smith";
17837          this.contacts = [
17838            {type: 'phone', value: '408 555 1212'},
17839            {type: 'email', value: '[email protected]'} ];
17840          };
17841
17842        SettingsController1.prototype.greet = function() {
17843          alert(this.name);
17844        };
17845
17846        SettingsController1.prototype.addContact = function() {
17847          this.contacts.push({type: 'email', value: '[email protected]'});
17848        };
17849
17850        SettingsController1.prototype.removeContact = function(contactToRemove) {
17851         var index = this.contacts.indexOf(contactToRemove);
17852          this.contacts.splice(index, 1);
17853        };
17854
17855        SettingsController1.prototype.clearContact = function(contact) {
17856          contact.type = 'phone';
17857          contact.value = '';
17858        };
17859      </script>
17860      <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
17861        Name: <input type="text" ng-model="settings.name"/>
17862        [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
17863        Contact:
17864        <ul>
17865          <li ng-repeat="contact in settings.contacts">
17866            <select ng-model="contact.type">
17867               <option>phone</option>
17868               <option>email</option>
17869            </select>
17870            <input type="text" ng-model="contact.value"/>
17871            [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
17872            | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
17873          </li>
17874          <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
17875       </ul>
17876      </div>
17877     </doc:source>
17878     <doc:protractor>
17879       it('should check controller as', function() {
17880         var container = element(by.id('ctrl-as-exmpl'));
17881
17882         expect(container.findElement(by.model('settings.name'))
17883             .getAttribute('value')).toBe('John Smith');
17884
17885         var firstRepeat =
17886             container.findElement(by.repeater('contact in settings.contacts').row(0));
17887         var secondRepeat =
17888             container.findElement(by.repeater('contact in settings.contacts').row(1));
17889
17890         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17891             .toBe('408 555 1212');
17892         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17893             .toBe('[email protected]');
17894
17895         firstRepeat.findElement(by.linkText('clear')).click()
17896
17897         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17898             .toBe('');
17899
17900         container.findElement(by.linkText('add')).click();
17901
17902         expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
17903             .findElement(by.model('contact.value'))
17904             .getAttribute('value'))
17905             .toBe('[email protected]');
17906       });
17907     </doc:protractor>
17908   </doc:example>
17909    <doc:example>
17910     <doc:source>
17911      <script>
17912        function SettingsController2($scope) {
17913          $scope.name = "John Smith";
17914          $scope.contacts = [
17915            {type:'phone', value:'408 555 1212'},
17916            {type:'email', value:'[email protected]'} ];
17917
17918          $scope.greet = function() {
17919           alert(this.name);
17920          };
17921
17922          $scope.addContact = function() {
17923           this.contacts.push({type:'email', value:'[email protected]'});
17924          };
17925
17926          $scope.removeContact = function(contactToRemove) {
17927           var index = this.contacts.indexOf(contactToRemove);
17928           this.contacts.splice(index, 1);
17929          };
17930
17931          $scope.clearContact = function(contact) {
17932           contact.type = 'phone';
17933           contact.value = '';
17934          };
17935        }
17936      </script>
17937      <div id="ctrl-exmpl" ng-controller="SettingsController2">
17938        Name: <input type="text" ng-model="name"/>
17939        [ <a href="" ng-click="greet()">greet</a> ]<br/>
17940        Contact:
17941        <ul>
17942          <li ng-repeat="contact in contacts">
17943            <select ng-model="contact.type">
17944               <option>phone</option>
17945               <option>email</option>
17946            </select>
17947            <input type="text" ng-model="contact.value"/>
17948            [ <a href="" ng-click="clearContact(contact)">clear</a>
17949            | <a href="" ng-click="removeContact(contact)">X</a> ]
17950          </li>
17951          <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
17952       </ul>
17953      </div>
17954     </doc:source>
17955     <doc:protractor>
17956       it('should check controller', function() {
17957         var container = element(by.id('ctrl-exmpl'));
17958
17959         expect(container.findElement(by.model('name'))
17960             .getAttribute('value')).toBe('John Smith');
17961
17962         var firstRepeat =
17963             container.findElement(by.repeater('contact in contacts').row(0));
17964         var secondRepeat =
17965             container.findElement(by.repeater('contact in contacts').row(1));
17966
17967         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17968             .toBe('408 555 1212');
17969         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17970             .toBe('[email protected]');
17971
17972         firstRepeat.findElement(by.linkText('clear')).click()
17973
17974         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
17975             .toBe('');
17976
17977         container.findElement(by.linkText('add')).click();
17978
17979         expect(container.findElement(by.repeater('contact in contacts').row(2))
17980             .findElement(by.model('contact.value'))
17981             .getAttribute('value'))
17982             .toBe('[email protected]');
17983       });
17984     </doc:protractor>
17985   </doc:example>
17986
17987 */
17988var ngControllerDirective = [function() {
17989  return {
17990    scope: true,
17991    controller: '@',
17992    priority: 500
17993  };
17994}];
17995
17996/**
17997 * @ngdoc directive
17998 * @name ng.directive:ngCsp
17999 *
18000 * @element html
18001 * @description
18002 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
18003 *
18004 * This is necessary when developing things like Google Chrome Extensions.
18005 *
18006 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
18007 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
18008 * any of these restrictions.
18009 *
18010 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
18011 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
18012 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
18013 * be raised.
18014 *
18015 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
18016 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
18017 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
18018 *
18019 * In order to use this feature put the `ngCsp` directive on the root element of the application.
18020 *
18021 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
18022 *
18023 * @example
18024 * This example shows how to apply the `ngCsp` directive to the `html` tag.
18025   <pre>
18026     <!doctype html>
18027     <html ng-app ng-csp>
18028     ...
18029     ...
18030     </html>
18031   </pre>
18032 */
18033
18034// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
18035// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
18036// anywhere in the current doc
18037
18038/**
18039 * @ngdoc directive
18040 * @name ng.directive:ngClick
18041 *
18042 * @description
18043 * The ngClick directive allows you to specify custom behavior when
18044 * an element is clicked.
18045 *
18046 * @element ANY
18047 * @priority 0
18048 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
18049 * click. (Event object is available as `$event`)
18050 *
18051 * @example
18052   <doc:example>
18053     <doc:source>
18054      <button ng-click="count = count + 1" ng-init="count=0">
18055        Increment
18056      </button>
18057      count: {{count}}
18058     </doc:source>
18059     <doc:protractor>
18060       it('should check ng-click', function() {
18061         expect(element(by.binding('count')).getText()).toMatch('0');
18062         element(by.css('.doc-example-live button')).click();
18063         expect(element(by.binding('count')).getText()).toMatch('1');
18064       });
18065     </doc:protractor>
18066   </doc:example>
18067 */
18068/*
18069 * A directive that allows creation of custom onclick handlers that are defined as angular
18070 * expressions and are compiled and executed within the current scope.
18071 *
18072 * Events that are handled via these handler are always configured not to propagate further.
18073 */
18074var ngEventDirectives = {};
18075forEach(
18076  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
18077  function(name) {
18078    var directiveName = directiveNormalize('ng-' + name);
18079    ngEventDirectives[directiveName] = ['$parse', function($parse) {
18080      return {
18081        compile: function($element, attr) {
18082          var fn = $parse(attr[directiveName]);
18083          return function(scope, element, attr) {
18084            element.on(lowercase(name), function(event) {
18085              scope.$apply(function() {
18086                fn(scope, {$event:event});
18087              });
18088            });
18089          };
18090        }
18091      };
18092    }];
18093  }
18094);
18095
18096/**
18097 * @ngdoc directive
18098 * @name ng.directive:ngDblclick
18099 *
18100 * @description
18101 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
18102 *
18103 * @element ANY
18104 * @priority 0
18105 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
18106 * a dblclick. (The Event object is available as `$event`)
18107 *
18108 * @example
18109   <doc:example>
18110     <doc:source>
18111      <button ng-dblclick="count = count + 1" ng-init="count=0">
18112        Increment (on double click)
18113      </button>
18114      count: {{count}}
18115     </doc:source>
18116   </doc:example>
18117 */
18118
18119
18120/**
18121 * @ngdoc directive
18122 * @name ng.directive:ngMousedown
18123 *
18124 * @description
18125 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
18126 *
18127 * @element ANY
18128 * @priority 0
18129 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
18130 * mousedown. (Event object is available as `$event`)
18131 *
18132 * @example
18133   <doc:example>
18134     <doc:source>
18135      <button ng-mousedown="count = count + 1" ng-init="count=0">
18136        Increment (on mouse down)
18137      </button>
18138      count: {{count}}
18139     </doc:source>
18140   </doc:example>
18141 */
18142
18143
18144/**
18145 * @ngdoc directive
18146 * @name ng.directive:ngMouseup
18147 *
18148 * @description
18149 * Specify custom behavior on mouseup event.
18150 *
18151 * @element ANY
18152 * @priority 0
18153 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
18154 * mouseup. (Event object is available as `$event`)
18155 *
18156 * @example
18157   <doc:example>
18158     <doc:source>
18159      <button ng-mouseup="count = count + 1" ng-init="count=0">
18160        Increment (on mouse up)
18161      </button>
18162      count: {{count}}
18163     </doc:source>
18164   </doc:example>
18165 */
18166
18167/**
18168 * @ngdoc directive
18169 * @name ng.directive:ngMouseover
18170 *
18171 * @description
18172 * Specify custom behavior on mouseover event.
18173 *
18174 * @element ANY
18175 * @priority 0
18176 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
18177 * mouseover. (Event object is available as `$event`)
18178 *
18179 * @example
18180   <doc:example>
18181     <doc:source>
18182      <button ng-mouseover="count = count + 1" ng-init="count=0">
18183        Increment (when mouse is over)
18184      </button>
18185      count: {{count}}
18186     </doc:source>
18187   </doc:example>
18188 */
18189
18190
18191/**
18192 * @ngdoc directive
18193 * @name ng.directive:ngMouseenter
18194 *
18195 * @description
18196 * Specify custom behavior on mouseenter event.
18197 *
18198 * @element ANY
18199 * @priority 0
18200 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
18201 * mouseenter. (Event object is available as `$event`)
18202 *
18203 * @example
18204   <doc:example>
18205     <doc:source>
18206      <button ng-mouseenter="count = count + 1" ng-init="count=0">
18207        Increment (when mouse enters)
18208      </button>
18209      count: {{count}}
18210     </doc:source>
18211   </doc:example>
18212 */
18213
18214
18215/**
18216 * @ngdoc directive
18217 * @name ng.directive:ngMouseleave
18218 *
18219 * @description
18220 * Specify custom behavior on mouseleave event.
18221 *
18222 * @element ANY
18223 * @priority 0
18224 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
18225 * mouseleave. (Event object is available as `$event`)
18226 *
18227 * @example
18228   <doc:example>
18229     <doc:source>
18230      <button ng-mouseleave="count = count + 1" ng-init="count=0">
18231        Increment (when mouse leaves)
18232      </button>
18233      count: {{count}}
18234     </doc:source>
18235   </doc:example>
18236 */
18237
18238
18239/**
18240 * @ngdoc directive
18241 * @name ng.directive:ngMousemove
18242 *
18243 * @description
18244 * Specify custom behavior on mousemove event.
18245 *
18246 * @element ANY
18247 * @priority 0
18248 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
18249 * mousemove. (Event object is available as `$event`)
18250 *
18251 * @example
18252   <doc:example>
18253     <doc:source>
18254      <button ng-mousemove="count = count + 1" ng-init="count=0">
18255        Increment (when mouse moves)
18256      </button>
18257      count: {{count}}
18258     </doc:source>
18259   </doc:example>
18260 */
18261
18262
18263/**
18264 * @ngdoc directive
18265 * @name ng.directive:ngKeydown
18266 *
18267 * @description
18268 * Specify custom behavior on keydown event.
18269 *
18270 * @element ANY
18271 * @priority 0
18272 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
18273 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18274 *
18275 * @example
18276   <doc:example>
18277     <doc:source>
18278      <input ng-keydown="count = count + 1" ng-init="count=0">
18279      key down count: {{count}}
18280     </doc:source>
18281   </doc:example>
18282 */
18283
18284
18285/**
18286 * @ngdoc directive
18287 * @name ng.directive:ngKeyup
18288 *
18289 * @description
18290 * Specify custom behavior on keyup event.
18291 *
18292 * @element ANY
18293 * @priority 0
18294 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
18295 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18296 *
18297 * @example
18298   <doc:example>
18299     <doc:source>
18300      <input ng-keyup="count = count + 1" ng-init="count=0">
18301      key up count: {{count}}
18302     </doc:source>
18303   </doc:example>
18304 */
18305
18306
18307/**
18308 * @ngdoc directive
18309 * @name ng.directive:ngKeypress
18310 *
18311 * @description
18312 * Specify custom behavior on keypress event.
18313 *
18314 * @element ANY
18315 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
18316 * keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18317 *
18318 * @example
18319   <doc:example>
18320     <doc:source>
18321      <input ng-keypress="count = count + 1" ng-init="count=0">
18322      key press count: {{count}}
18323     </doc:source>
18324   </doc:example>
18325 */
18326
18327
18328/**
18329 * @ngdoc directive
18330 * @name ng.directive:ngSubmit
18331 *
18332 * @description
18333 * Enables binding angular expressions to onsubmit events.
18334 *
18335 * Additionally it prevents the default action (which for form means 
18335sending the request to the
18336 * server and reloading the current page), but only if the form does not contain `action`,
18337 * `data-action`, or `x-action` attributes.
18338 *
18339 * @element form
18340 * @priority 0
18341 * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
18342 *
18343 * @example
18344   <doc:example>
18345     <doc:source>
18346      <script>
18347        function Ctrl($scope) {
18348          $scope.list = [];
18349          $scope.text = 'hello';
18350          $scope.submit = function() {
18351            if (this.text) {
18352              this.list.push(this.text);
18353              this.text = '';
18354            }
18355          };
18356        }
18357      </script>
18358      <form ng-submit="submit()" ng-controller="Ctrl">
18359        Enter text and hit enter:
18360        <input type="text" ng-model="text" name="text" />
18361        <input type="submit" id="submit" value="Submit" />
18362        <pre>list={{list}}</pre>
18363      </form>
18364     </doc:source>
18365     <doc:protractor>
18366       it('should check ng-submit', function() {
18367         expect(element(by.binding('list')).getText()).toBe('list=[]');
18368         element(by.css('.doc-example-live #submit')).click();
18369         expect(element(by.binding('list')).getText()).toContain('hello');
18370         expect(element(by.input('text')).getAttribute('value')).toBe('');
18371       });
18372       it('should ignore empty strings', function() {
18373         expect(element(by.binding('list')).getText()).toBe('list=[]');
18374         element(by.css('.doc-example-live #submit')).click();
18375         element(by.css('.doc-example-live #submit')).click();
18376         expect(element(by.binding('list')).getText()).toContain('hello');
18377        });
18378     </doc:protractor>
18379   </doc:example>
18380 */
18381
18382/**
18383 * @ngdoc directive
18384 * @name ng.directive:ngFocus
18385 *
18386 * @description
18387 * Specify custom behavior on focus event.
18388 *
18389 * @element window, input, select, textarea, a
18390 * @priority 0
18391 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
18392 * focus. (Event object is available as `$event`)
18393 *
18394 * @example
18395 * See {@link ng.directive:ngClick ngClick}
18396 */
18397
18398/**
18399 * @ngdoc directive
18400 * @name ng.directive:ngBlur
18401 *
18402 * @description
18403 * Specify custom behavior on blur event.
18404 *
18405 * @element window, input, select, textarea, a
18406 * @priority 0
18407 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
18408 * blur. (Event object is available as `$event`)
18409 *
18410 * @example
18411 * See {@link ng.directive:ngClick ngClick}
18412 */
18413
18414/**
18415 * @ngdoc directive
18416 * @name ng.directive:ngCopy
18417 *
18418 * @description
18419 * Specify custom behavior on copy event.
18420 *
18421 * @element window, input, select, textarea, a
18422 * @priority 0
18423 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
18424 * copy. (Event object is available as `$event`)
18425 *
18426 * @example
18427   <doc:example>
18428     <doc:source>
18429      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
18430      copied: {{copied}}
18431     </doc:source>
18432   </doc:example>
18433 */
18434
18435/**
18436 * @ngdoc directive
18437 * @name ng.directive:ngCut
18438 *
18439 * @description
18440 * Specify custom behavior on cut event.
18441 *
18442 * @element window, input, select, textarea, a
18443 * @priority 0
18444 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
18445 * cut. (Event object is available as `$event`)
18446 *
18447 * @example
18448   <doc:example>
18449     <doc:source>
18450      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
18451      cut: {{cut}}
18452     </doc:source>
18453   </doc:example>
18454 */
18455
18456/**
18457 * @ngdoc directive
18458 * @name ng.directive:ngPaste
18459 *
18460 * @description
18461 * Specify custom behavior on paste event.
18462 *
18463 * @element window, input, select, textarea, a
18464 * @priority 0
18465 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
18466 * paste. (Event object is available as `$event`)
18467 *
18468 * @example
18469   <doc:example>
18470     <doc:source>
18471      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
18472      pasted: {{paste}}
18473     </doc:source>
18474   </doc:example>
18475 */
18476
18477/**
18478 * @ngdoc directive
18479 * @name ng.directive:ngIf
18480 * @restrict A
18481 *
18482 * @description
18483 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
18484 * {expression}. If the expression assigned to `ngIf` evaluates to a false
18485 * value then the element is removed from the DOM, otherwise a clone of the
18486 * element is reinserted into the DOM.
18487 *
18488 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
18489 * element in the DOM rather than changing its visibility via the `display` css property.  A common
18490 * case when this difference is significant is when using css selectors that rely on an element's
18491 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
18491s.
18492 *
18493 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
18494 * is created when the element is restored.  The scope created within `ngIf` inherits from
18495 * its parent scope using
18496 * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
18497 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
18498 * a javascript primitive defined in the parent scope. In this case any modifications made to the
18499 * variable within the child scope will override (hide) the value in the parent scope.
18500 *
18501 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
18502 * is if an element's class attribute is directly modified after it's compiled, using something like
18503 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
18504 * the added class will be lost because the original compiled state is used to regenerate the element.
18505 *
18506 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
18507 * and `leave` effects.
18508 *
18509 * @animations
18510 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
18511 * leave - happens just before the ngIf contents are removed from the DOM
18512 *
18513 * @element ANY
18514 * @scope
18515 * @priority 600
18516 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
18517 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
18518 *     element is added to the DOM tree.
18519 *
18520 * @example
18521  <example animations="true">
18522    <file name="index.html">
18523      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
18524      Show when checked:
18525      <span ng-if="checked" class="animate-if">
18526        I'm removed when the checkbox is unchecked.
18527      </span>
18528    </file>
18529    <file name="animations.css">
18530      .animate-if {
18531        background:white;
18532        border:1px solid black;
18533        padding:10px;
18534      }
18535
18536      .animate-if.ng-enter, .animate-if.ng-leave {
18537        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18538        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18539      }
18540
18541      .animate-if.ng-enter,
18542      .animate-if.ng-leave.ng-leave-active {
18543        opacity:0;
18544      }
18545
18546      .animate-if.ng-leave,
18547      .animate-if.ng-enter.ng-enter-active {
18548        opacity:1;
18549      }
18550    </file>
18551  </example>
18552 */
18553var ngIfDirective = ['$animate', function($animate) {
18554  return {
18555    transclude: 'element',
18556    priority: 600,
18557    terminal: true,
18558    restrict: 'A',
18559    $$tlb: true,
18560    link: function ($scope, $element, $attr, ctrl, $transclude) {
18561        var block, childScope;
18562        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
18563
18564          if (toBoolean(value)) {
18565            if (!childScope) {
18566              childScope = $scope.$new();
18567              $transclude(childScope, function (clone) {
18568                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
18569                // Note: We only need the first/last node of the cloned nodes.
18570                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
18571                // by a directive with templateUrl when it's template arrives.
18572                block = {
18573                  clone: clone
18574                };
18575                $animate.enter(clone, $element.parent(), $element);
18576              });
18577            }
18578          } else {
18579
18580            if (childScope) {
18581              childScope.$destroy();
18582              childScope = null;
18583            }
18584
18585            if (block) {
18586              $animate.leave(getBlockElements(block.clone));
18587              block = null;
18588            }
18589          }
18590        });
18591    }
18592  };
18593}];
18594
18595/**
18596 * @ngdoc directive
18597 * @name ng.directive:ngInclude
18598 * @restrict ECA
18599 *
18600 * @description
18601 * Fetches, compiles and includes an external HTML fragment.
18602 *
18603 * By default, the template URL is restricted to the same domain and protocol as the
18604 * application document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
18605 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
18606 * you may either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist them} or
18607 * {@link ng.$sce#methods_trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
18608 * ng.$sce Strict Contextual Escaping}.
18609 *
18610 * In addition, the browser's
18611 * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
18612 * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
18613 * (CORS)} policy may further restrict whether the template is successfully loaded.
18614 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
18615 * access on some browsers.
18616 *
18617 * @animations
18618 * enter - animation is used to bring new content into the browser.
18619 * leave - animation is used to animate existing content away.
18620 *
18621 * The enter and leave animation occur concurrently.
18622 *
18623 * @scope
18624 * @priority 400
18625 *
18626 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
18627 *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
18628 * @param {string=} onload Expression to evaluate when a new partial is loaded.
18629 *
18630 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
18631 *                  $anchorScroll} to scroll the viewport after the content is loaded.
18632 *
18633 *                  - If the attribute is not set, disable scrolling.
18634 *                  - If the attribute is set without value, enable scrolling.
18635 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
18636 *
18637 * @example
18638  <example animations="true">
18639    <file name="index.html">
18640     <div ng-controller="Ctrl">
18641       <select ng-model="template" ng-options="t.name for t in templates">
18642        <option value="">(blank)</option>
18643       </select>
18644       url of the template: <tt>{{template.url}}</tt>
18645       <hr/>
18646       <div class="slide-animate-container">
18647         <div class="slide-animate" ng-include="template.url"></div>
18648       </div>
18649     </div>
18650    </file>
18651    <file name="script.js">
18652      function Ctrl($scope) {
18653        $scope.templates =
18654          [ { name: 'template1.html', url: 'template1.html'}
18655          , { name: 'template2.html', url: 'template2.html'} ];
18656        $scope.template = $scope.templates[0];
18657      }
18658     </file>
18659    <file name="template1.html">
18660      Content of template1.html
18661    </file>
18662    <file name="template2.html">
18663      Content of template2.html
18664    </file>
18665    <file name="animations.css">
18666      .slide-animate-container {
18667        position:relative;
18668        background:white;
18669        border:1px solid black;
18670        height:40px;
18671        overflow:hidden;
18672      }
18673
18674      .slide-animate {
18675        padding:10px;
18676      }
18677
18678      .slide-animate.ng-enter, .slide-animate.ng-leave {
18679        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18680        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18681
18682        position:absolute;
18683        top:0;
18684        left:0;
18685        right:0;
18686        bottom:0;
18687        display:block;
18688        padding:10px;
18689      }
18690
18691      .slide-animate.ng-enter {
18692        top:-50px;
18693      }
18694      .slide-animate.ng-enter.ng-enter-active {
18695        top:0;
18696      }
18697
18698      .slide-animate.ng-leave {
18699        top:0;
18700      }
18701      .slide-animate.ng-leave.ng-leave-active {
18702        top:50px;
18703      }
18704    </file>
18705    <file name="protractorTest.js">
18706      var templateSelect = element(by.model('template'));
18707      var includeElem = element(by.css('.doc-example-live [ng-include]'));
18708
18709      it('should load template1.html', function() {
18710        expect(includeElem.getText()).toMatch(/Content of template1.html/);
18711      });
18712
18713      it('should load template2.html', function() {
18714        if (browser.params.browser == 'firefox') {
18715          // Firefox can't handle using selects
18716          // See https://github.com/angular/protractor/issues/480
18717          return;
18718        }
18719        templateSelect.click();
18720        templateSelect.element.all(by.css('option')).get(2).click();
18721        expect(includeElem.getText()).toMatch(/Content of template2.html/);
18722      });
18723
18724      it('should change to blank', function() {
18725        if (browser.params.browser == 'firefox') {
18726          // Firefox can't handle using selects
18727          return;
18728        }
18729        templateSelect.click();
18730        templateSelect.element.all(by.css('option')).get(0).click();
18731        expect(includeElem.isPresent()).toBe(false);
18732      });
18733    </file>
18734  </example>
18735 */
18736
18737
18738/**
18739 * @ngdoc event
18740 * @name ng.directive:ngInclude#$includeContentRequested
18741 * @eventOf ng.directive:ngInclude
18742 * @eventType emit on the scope ngInclude was declared in
18743 * @description
18744 * Emitted every time the ngInclude content is requested.
18745 */
18746
18747
18748/**
18749 * @ngdoc event
18750 * @name ng.directive:ngInclude#$includeContentLoaded
18751 * @eventOf ng.directive:ngInclude
18752 * @eventType emit on the current ngInclude scope
18753 * @description
18754 * Emitted every time the ngInclude content is reloaded.
18755 */
18756var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
18757                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
18758  return {
18759    restrict: 'ECA',
18760    priority: 400,
18761    terminal: true,
18762    transclude: 'element',
18763    controller: angular.noop,
18764    compile: function(element, attr) {
18765      var srcExp = attr.ngInclude || attr.src,
18766          onloadExp = attr.onload || '',
18767          autoScrollExp = attr.autoscroll;
18768
18769      return function(scope, $element, $attr, ctrl, $transclude) {
18770        var changeCounter = 0,
18771            currentScope,
18772            currentElement;
18773
18774        var cleanupLastIncludeContent = function() {
18775          if (currentScope) {
18776            currentScope.$destroy();
18777            currentScope = null;
18778          }
18779          if(currentElement) {
18780            $animate.leave(currentElement);
18781            currentElement = null;
18782          }
18783        };
18784
18785        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
18786          var afterAnimation = function() {
18787            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
18788              $anchorScroll();
18789            }
18790          };
18791          var thisChangeId = ++changeCounter;
18792
18793          if (src) {
18794            $http.get(src, {cache: $templateCache}).success(function(response) {
18795              if (thisChangeId !== changeCounter) return;
18796              var newScope = scope.$new();
18797              ctrl.template = response;
18798
18799              // Note: This will also link all children of ng-include that were contained in the original
18800              // html. If that content contains controllers, ... they could pollute/change the scope.
18801              // However, using ng-include on an element with additional content does not make sense...
18802              // Note: We can't remove them in the cloneAttchFn of $transclude as that
18803              // function is called before linking the content, which would apply child
18804              // directives to non existing elements.
18805              var clone = $transclude(newScope, function(clone) {
18806                cleanupLastIncludeContent();
18807                $animate.enter(clone, null, $element, afterAnimation);
18808              });
18809
18810              currentScope = newScope;
18811              currentElement = clone;
18812
18813              currentScope.$emit('$includeContentLoaded');
18814              scope.$eval(onloadExp);
18815            }).error(function() {
18816              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
18817            });
18818            scope.$emit('$includeContentRequested');
18819          } else {
18820            cleanupLastIncludeContent();
18821            ctrl.template = null;
18822          }
18823        });
18824      };
18825    }
18826  };
18827}];
18828
18829// This directive is called during the $transclude call of the first `ngInclude` directive.
18830// It will replace and compile the content of the element with the loaded template.
18831// We need this directive so that the element content is already filled when
18832// the link function of another directive on the same element as ngInclude
18833// is called.
18834var ngIncludeFillContentDirective = ['$compile',
18835  function($compile) {
18836    return {
18837      restrict: 'ECA',
18838      priority: -400,
18839      require: 'ngInclude',
18840      link: function(scope, $element, $attr, ctrl) {
18841        $element.html(ctrl.template);
18842        $compile($element.contents())(scope);
18843      }
18844    };
18845  }];
18846
18847/**
18848 * @ngdoc directive
18849 * @name ng.directive:ngInit
18850 * @restrict AC
18851 *
18852 * @description
18853 * The `ngInit` directive allows you to evaluate an expression in the
18854 * current scope.
18855 *
18856 * <div class="alert alert-error">
18857 * The only appropriate use of `ngInit` is for aliasing special properties of
18858 * {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
18859 * should use {@link guide/controller controllers} rather than `ngInit`
18860 * to initialize values on a scope.
18861 * </div>
18862 * <div class="alert alert-warning">
18863 * **Note**: If you have assignment in `ngInit` along with {@link api/ng.$filter `$filter`}, make
18864 * sure you have parenthesis for correct precedence:
18865 * <pre class="prettyprint">
18866 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
18867 * </pre>
18868 * </div>
18869 *
18870 * @priority 450
18871 *
18872 * @element ANY
18873 * @param {expression} ngInit {@link guide/expression Expression} to eval.
18874 *
18875 * @example
18876   <doc:example>
18877     <doc:source>
18878   <script>
18879     function Ctrl($scope) {
18880       $scope.list = [['a', 'b'], ['c', 'd']];
18881     }
18882   </script>
18883   <div ng-controller="Ctrl">
18884     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
18885       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
18886          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
18887       </div>
18888     </div>
18889   </div>
18890     </doc:source>
18891     <doc:protractor>
18892       it('should alias index positions', function() {
18893         var elements = element.all(by.css('.example-init'));
18894         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
18895         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
18896         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
18897         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
18898       });
18899     </doc:protractor>
18900   </doc:example>
18901 */
18902var ngInitDirective = ngDirective({
18903  priority: 450,
18904  compile: function() {
18905    return {
18906      pre: function(scope, element, attrs) {
18907        scope.$eval(attrs.ngInit);
18908      }
18909    };
18910  }
18911});
18912
18913/**
18914 * @ngdoc directive
18915 * @name ng.directive:ngNonBindable
18916 * @restrict AC
18917 * @priority 1000
18918 *
18919 * @description
18920 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
18921 * DOM element. This is useful if the element contains what appears to be Angular directives and
18922 * bindings but which should be ignored by Angular. This could be the case if you have a site that
18923 * displays snippets of code, for instance.
18924 *
18925 * @element ANY
18926 *
18927 * @example
18928 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
18929 * but the one wrapped in `ngNonBindable` is left alone.
18930 *
18931 * @example
18932    <doc:example>
18933      <doc:source>
18934        <div>Normal: {{1 + 2}}</div>
18935        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
18936      </doc:source>
18937      <doc:protractor>
18938       it('should check ng-non-bindable', function() {
18939         expect(element(by.binding('1 + 2')).getText()).toContain('3');
18940         expect(element.all(by.css('.doc-example-live div')).last().getText()).toMatch(/1 \+ 2/);
18941       });
18942      </doc:protractor>
18943    </doc:example>
18944 */
18945var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
18946
18947/**
18948 * @ngdoc directive
18949 * @name ng.directive:ngPluralize
18950 * @restrict EA
18951 *
18952 * @description
18953 * # Overview
18954 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
18955 * These rules are bundled with angular.js, but can be overridden
18956 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
18957 * by specifying the mappings between
18958 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18959 * plural categories} and the strings to be displayed.
18960 *
18961 * # Plural categories and explicit number rules
18962 * There are two
18963 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
18964 * plural categories} in Angular's default en-US locale: "one" and "other".
18965 *
18966 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
18967 * any number that is not 1), an explicit number rule can only match one number. For example, the
18968 * explicit number rule for "3" matches the number 3. There are examples of plural categories
18969 * and explicit number rules throughout the rest of this documentation.
18970 *
18971 * # Configuring ngPluralize
18972 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
18973 * You can also provide an optional attribute, `offset`.
18974 *
18975 * The value of the `count` attribute can be either a string or an {@link guide/expression
18976 * Angular expression}; these are evaluated on the current scope for its bound value.
18977 *
18978 * The `when` attribute specifies the mappings between plural categories and the actual
18979 * string to be displayed. The value of the attribute should be a JSON object.
18980 *
18981 * The following example shows how to configure ngPluralize:
18982 *
18983 * <pre>
18984 * <ng-pluralize count="personCount"
18985                 when="{'0': 'Nobody is viewing.',
18986 *                      'one': '1 person is viewing.',
18987 *                      'other': '{} people are viewing.'}">
18988 * </ng-pluralize>
18989 *</pre>
18990 *
18991 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
18992 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
18993 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
18994 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
18995 * show "a dozen people are viewing".
18996 *
18997 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
18998 * into pluralized strings. In the previous example, Angular will replace `{}` with
18999 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
19000 * for <span ng-non-bindable>{{numberExpression}}</span>.
19001 *
19002 * # Configuring ngPluralize with offset
19003 * The `offset` attribute allows further customization of pluralized text, which can result in
19004 * a better user experience. For example, instead of the message "4 people are viewing this document",
19005 * you might display "John, Kate and 2 others are viewing this document".
19006 * The offset attribute allows you to offset a number by any desired value.
19007 * Let's take a look at an example:
19008 *
19009 * <pre>
19010 * <ng-pluralize count="personCount" offset=2
19011 *               when="{'0': 'Nobody is viewing.',
19012 *                      '1': '{{person1}} is viewing.',
19013 *                      '2': '{{person1}} and {{person2}} are viewing.',
19014 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
19015 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19016 * </ng-pluralize>
19017 * </pre>
19018 *
19019 * Notice that we are still using two plural categories(one, other), but we added
19020 * three explicit number rules 0, 1 and 2.
19021 * When one person, perhaps John, views the document, "John is viewing" will be shown.
19022 * When three people view the document, no explicit number rule is found, so
19023 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
19024 * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
19025 * is shown.
19026 *
19027 * Note that when you specify offsets, you must provide explicit number rules for
19028 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
19029 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
19030 * plural categories "one" and "other".
19031 *
19032 * @param {string|expression} count The variable to be bounded to.
19033 * @param {string} when The mapping between plural category to its corresponding strings.
19034 * @param {number=} offset Offset to deduct from the total number.
19035 *
19036 * @example
19037    <doc:example>
19038      <doc:source>
19039        <script>
19040          function Ctrl($scope) {
19041            $scope.person1 = 'Igor';
19042            $scope.person2 = 'Misko';
19043            $scope.personCount = 1;
19044          }
19045        </script>
19046        <div ng-controller="Ctrl">
19047          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
19048          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
19049          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
19050
19051          <!--- Example with simple pluralization rules for en locale --->
19052          Without Offset:
19053          <ng-pluralize count="personCount"
19054                        when="{'0': 'Nobody is viewing.',
19055                               'one': '1 person is viewing.',
19056                               'other': '{} people are viewing.'}">
19057          </ng-pluralize><br>
19058
19059          <!--- Example with offset --->
19060          With Offset(2):
19061          <ng-pluralize count="personCount" offset=2
19062                        when="{'0': 'Nobody is viewing.',
19063                               '1': '{{person1}} is viewing.',
19064                               '2': '{{person1}} and {{person2}} are viewing.',
19065                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
19066                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19067          </ng-pluralize>
19068        </div>
19069      </doc:source>
19070      <doc:protractor>
19071        it('should show correct pluralized string', function() {
19072          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
19073          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19074          var countInput = element(by.model('personCount'));
19075
19076          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
19077          expect(withOffset.getText()).toEqual('Igor is viewing.');
19078
19079          countInput.clear();
19080          countInput.sendKeys('0');
19081
19082          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
19083          expect(withOffset.getText()).toEqual('Nobody is viewing.');
19084
19085          countInput.clear();
19086          countInput.sendKeys('2');
19087
19088          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
19089          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
19090
19091          countInput.clear();
19092          countInput.sendKeys('3');
19093
19094          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
19095          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
19096
19097          countInput.clear();
19098          countInput.sendKeys('4');
19099
19100          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
19101          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
19102        });
19103        it('should show data-bound names', function() {
19104          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19105          var personCount = element(by.model('personCount'));
19106          var person1 = element(by.model('person1'));
19107          var person2 = element(by.model('person2'));
19108          personCount.clear();
19109          personCount.sendKeys('4');
19110          person1.clear();
19111          person1.sendKeys('Di');
19112          person2.clear();
19113          person2.sendKeys('Vojta');
19114          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
19115        });
19116      </doc:protractor>
19117    </doc:example>
19118 */
19119var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
19120  var BRACE = /{}/g;
19121  return {
19122    restrict: 'EA',
19123    link: function(scope, element, attr) {
19124      var numberExp = attr.count,
19125          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
19126          offset = attr.offset || 0,
19127          whens = scope.$eval(whenExp) || {},
19128          whensExpFns = {},
19129          startSymbol = $interpolate.startSymbol(),
19130          endSymbol = $interpolate.endSymbol(),
19131          isWhen = /^when(Minus)?(.+)$/;
19132
19133      forEach(attr, function(expression, attributeName) {
19134        if (isWhen.test(attributeName)) {
19135          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
19136            element.attr(attr.$attr[attributeName]);
19137        }
19138      });
19139      forEach(whens, function(expression, key) {
19140        whensExpFns[key] =
19141          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
19142            offset + endSymbol));
19143      });
19144
19145      scope.$watch(function ngPluralizeWatch() {
19146        var value = parseFloat(scope.$eval(numberExp));
19147
19148        if (!isNaN(value)) {
19149          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
19150          //check it against pluralization rules in $locale service
19151          if (!(value in whens)) value = $locale.pluralCat(value - offset);
19152           return whensExpFns[value](scope, element, true);
19153        } else {
19154          return '';
19155        }
19156      }, function ngPluralizeWatchAction(newVal) {
19157        element.text(newVal);
19158      });
19159    }
19160  };
19161}];
19162
19163/**
19164 * @ngdoc directive
19165 * @name ng.directive:ngRepeat
19166 *
19167 * @description
19168 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
19169 * instance gets its own scope, where the given loop variable is set to the current collection item,
19170 * and `$index` is set to the item index or key.
19171 *
19172 * Special properties are exposed on the local scope of each template instance, including:
19173 *
19174 * | Variable  | Type            | Details                                                                     |
19175 * |-----------|-----------------|-----------------------------------------------------------------------------|
19176 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
19177 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
19178 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
19179 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
19180 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
19181 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
19182 *
19183 * Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
19184 * This may be useful when, for instance, nesting ngRepeats.
19185 *
19186 * # Special repeat start and end points
19187 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
19188 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
19189 * 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)
19190 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
19191 *
19192 * The example below makes use of this feature:
19193 * <pre>
19194 *   <header ng-repeat-start="item in items">
19195 *     Header {{ item }}
19196 *   </header>
19197 *   <div class="body">
19198 *     Body {{ item }}
19199 *   </div>
19200 *   <footer ng-repeat-end>
19201 *     Footer {{ item }}
19202 *   </footer>
19203 * </pre>
19204 *
19205 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
19206 * <pre>
19207 *   <header>
19208 *     Header A
19209 *   </header>
19210 *   <div class="body">
19211 *     Body A
19212 *   </div>
19213 *   <footer>
19214 *     Footer A
19215 *   </footer>
19216 *   <header>
19217 *     Header B
19218 *   </header>
19219 *   <div class="body">
19220 *     Body B
19221 *   </div>
19222 *   <footer>
19223 *     Footer B
19224 *   </footer>
19225 * </pre>
19226 *
19227 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
19228 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
19229 *
19230 * @animations
19231 * enter - when a new item is added to the list or when an item is revealed after a filter
19232 * leave - when an item is removed from the list or when an item is filtered out
19233 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
19234 *
19235 * @element ANY
19236 * @scope
19237 * @priority 1000
19238 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
19239 *   formats are currently supported:
19240 *
19241 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
19242 *     is a scope expression giving the collection to enumerate.
19243 *
19244 *     For example: `album in artist.albums`.
19245 *
19246 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
19247 *     and `expression` is the scope expression giving the collection to enumerate.
19248 *
19249 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
19250 *
19251 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
19252 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
19253 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
19254 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
19255 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
19256 *     before specifying a tracking expression.
19257 *
19258 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
19259 *     will be associated by item identity in the array.
19260 *
19261 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
19262 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
19263 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
19264 *     element in the same way in the DOM.
19265 *
19266 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
19267 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
19268 *     property is same.
19269 *
19270 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
19271 *     to items in conjunction with a tracking expression.
19272 *
19273 * @example
19274 * This example initializes the scope to a list of names and
19275 * then uses `ngRepeat` to display every person:
19276  <example animations="true">
19277    <file name="index.html">
19278      <div ng-init="friends = [
19279        {name:'John', age:25, gender:'boy'},
19280        {name:'Jessie', age:30, gender:'girl'},
19281        {name:'Johanna', age:28, gender:'girl'},
19282        {name:'Joy', age:15, gender:'girl'},
19283        {name:'Mary', age:28, gender:'girl'},
19284        {name:'Peter', age:95, gender:'boy'},
19285        {name:'Sebastian', age:50, gender:'boy'},
19286        {name:'Erika', age:27, gender:'girl'},
19287        {name:'Patrick', age:40, gender:'boy'},
19288        {name:'Samantha', age:60, gender:'girl'}
19289      ]">
19290        I have {{friends.length}} friends. They are:
19291        <input type="search" ng-model="q" placeholder="filter friends..." />
19292        <ul class="example-animate-container">
19293          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
19294            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
19295          </li>
19296        </ul>
19297      </div>
19298    </file>
19299    <file name="animations.css">
19300      .example-animate-container {
19301        background:white;
19302        border:1px solid black;
19303        list-style:none;
19304        margin:0;
19305        padding:0 10px;
19306      }
19307
19308      .animate-repeat {
19309        line-height:40px;
19310        list-style:none;
19311        box-sizing:border-box;
19312      }
19313
19314      .animate-repeat.ng-move,
19315      .animate-repeat.ng-enter,
19316      .animate-repeat.ng-leave {
19317        -webkit-transition:all linear 0.5s;
19318        transition:all linear 0.5s;
19319      }
19320
19321      .animate-repeat.ng-leave.ng-leave-active,
19322      .animate-repeat.ng-move,
19323      .animate-repeat.ng-enter {
19324        opacity:0;
19325        max-height:0;
19326      }
19327
19328      .animate-repeat.ng-leave,
19329      .animate-repeat.ng-move.ng-move-active,
19330      .animate-repeat.ng-enter.ng-enter-active {
19331        opacity:1;
19332        max-height:40px;
19333      }
19334    </file>
19335    <file name="protractorTest.js">
19336      var friends = element(by.css('.doc-example-live'))
19337          .element.all(by.repeater('friend in friends'));
19338
19339      it('should render initial data set', function() {
19340        expect(friends.count()).toBe(10);
19341        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
19342        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
19343        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
19344        expect(element(by.binding('friends.length')).getText())
19345            .toMatch("I have 10 friends. They are:");
19346      });
19347
19348       it('should update repeater when filter predicate changes', function() {
19349         expect(friends.count()).toBe(10);
19350
19351         element(by.css('.doc-example-live')).element(by.model('q')).sendKeys('ma');
19352
19353         expect(friends.count()).toBe(2);
19354         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
19355         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
19356       });
19357      </file>
19358    </example>
19359 */
19360var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
19361  var NG_REMOVED = '$$NG_REMOVED';
19362  var ngRepeatMinErr = minErr('ngRepeat');
19363  return {
19364    transclude: 'element',
19365    priority: 1000,
19366    terminal: true,
19367    $$tlb: true,
19368    link: function($scope, $element, $attr, ctrl, $transclude){
19369        var expression = $attr.ngRepeat;
19370        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
19371          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
19372          lhs, rhs, valueIdentifier, keyIdentifier,
19373          hashFnLocals = {$id: hashKey};
19374
19375        if (!match) {
19376          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
19377            expression);
19378        }
19379
19380        lhs = match[1];
19381        rhs = match[2];
19382        trackByExp = match[3];
19383
19384        if (trackByExp) {
19385          trackByExpGetter = $parse(trackByExp);
19386          trackByIdExpFn = function(key, value, index) {
19387            // assign key, value, and $index to the locals so that they can be used in hash functions
19388            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
19389            hashFnLocals[valueIdentifier] = value;
19390            hashFnLocals.$index = index;
19391            return trackByExpGetter($scope, hashFnLocals);
19392          };
19393        } else {
19394          trackByIdArrayFn = function(key, value) {
19395            return hashKey(value);
19396          };
19397          trackByIdObjFn = function(key) {
19398            return key;
19399          };
19400        }
19401
19402        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
19403        if (!match) {
19404          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
19405                                                                    lhs);
19406        }
19407        valueIdentifier = match[3] || match[1];
19408        keyIdentifier = match[2];
19409
19410        // Store a list of elements from previous run. This is a hash where key is the item from the
19411        // iterator, and the value is objects with following properties.
19412        //   - scope: bound scope
19413        //   - element: previous element.
19414        //   - index: position
19415        var lastBlockMap = {};
19416
19417        //watch props
19418        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
19419          var index, length,
19420              previousNode = $element[0],     // current position of the node
19421              nextNode,
19422              // Same as lastBlockMap but it has the current state. It will become the
19423              // lastBlockMap on the next iteration.
19424              nextBlockMap = {},
19425              arrayLength,
19426              childScope,
19427              key, value, // key/value of iteration
19428              trackById,
19429              trackByIdFn,
19430              collectionKeys,
19431              block,       // last object information {scope, element, id}
19432              nextBlockOrder = [],
19433              elementsToRemove;
19434
19435
19436          if (isArrayLike(collection)) {
19437            collectionKeys = collection;
19438            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
19439          } else {
19440            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
19441            // if object, extract keys, sort them and use to determine order of iteration over obj props
19442            collectionKeys = [];
19443            for (key in collection) {
19444              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
19445                collectionKeys.push(key);
19446              }
19447            }
19448            collectionKeys.sort();
19449          }
19450
19451          arrayLength = collectionKeys.length;
19452
19453          // locate existing items
19454          length = nextBlockOrder.length = collectionKeys.length;
19455          for(index = 0; index < length; index++) {
19456           key = (collection === collectionKeys) ? index : collectionKeys[index];
19457           value = collection[key];
19458           trackById = trackByIdFn(key, value, index);
19459           assertNotHasOwnProperty(trackById, '`track by` id');
19460           if(lastBlockMap.hasOwnProperty(trackById)) {
19461             block = lastBlockMap[trackById];
19462             delete lastBlockMap[trackById];
19463             nextBlockMap[trackById] = block;
19464             nextBlockOrder[index] = block;
19465           } else if (nextBlockMap.hasOwnProperty(trackById)) {
19466             // restore lastBlockMap
19467             forEach(nextBlockOrder, function(block) {
19468               if (block && block.scope) lastBlockMap[block.id] = block;
19469             });
19470             // This is a duplicate and we need to throw an error
19471             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
19472                                                                                                                                                    expression,       trackById);
19473           } else {
19474             // new never before seen block
19475             nextBlockOrder[index] = { id: trackById };
19476             nextBlockMap[trackById] = false;
19477           }
19478         }
19479
19480          // remove existing items
19481          for (key in lastBlockMap) {
19482            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
19483            if (lastBlockMap.hasOwnProperty(key)) {
19484              block = lastBlockMap[key];
19485              elementsToRemove = getBlockElements(block.clone);
19486              $animate.leave(elementsToRemove);
19487              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
19488              block.scope.$destroy();
19489            }
19490          }
19491
19492          // we are not using forEach for perf reasons (trying to avoid #call)
19493          for (index = 0, length = collectionKeys.length; index < length; index++) {
19494            key = (collection === collectionKeys) ? index : collectionKeys[index];
19495            value = collection[key];
19496            block = nextBlockOrder[index];
19497            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
19498
19499            if (block.scope) {
19500              // if we have already seen this object, then we need to reuse the
19501              // associated scope/element
19502              childScope = block.scope;
19503
19504              nextNode = previousNode;
19505              do {
19506                nextNode = nextNode.nextSibling;
19507              } while(nextNode && nextNode[NG_REMOVED]);
19508
19509              if (getBlockStart(block) != nextNode) {
19510                // existing item which got moved
19511                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
19512              }
19513              previousNode = getBlockEnd(block);
19514            } else {
19515              // new item which we don't know about
19516              childScope = $scope.$new();
19517            }
19518
19519            childScope[valueIdentifier] = value;
19520            if (keyIdentifier) childScope[keyIdentifier] = key;
19521            childScope.$index = index;
19522            childScope.$first = (index === 0);
19523            childScope.$last = (index === (arrayLength - 1));
19524            childScope.$middle = !(childScope.$first || childScope.$last);
19525            // jshint bitwise: false
19526            childScope.$odd = !(childScope.$even = (index&1) === 0);
19527            // jshint bitwise: true
19528
19529            if (!block.scope) {
19530              $transclude(childScope, function(clone) {
19531                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
19532                $animate.enter(clone, null, jqLite(previousNode));
19533                previousNode = clone;
19534                block.scope = childScope;
19535                // Note: We only need the first/last node of the cloned nodes.
19536                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19537                // by a directive with templateUrl when it's template arrives.
19538                block.clone = clone;
19539                nextBlockMap[block.id] = block;
19540              });
19541            }
19542          }
19543          lastBlockMap = nextBlockMap;
19544        });
19545    }
19546  };
19547
19548  function getBlockStart(block) {
19549    return block.clone[0];
19550  }
19551
19552  function getBlockEnd(block) {
19553    return block.clone[block.clone.length - 1];
19554  }
19555}];
19556
19557/**
19558 * @ngdoc directive
19559 * @name ng.directive:ngShow
19560 *
19561 * @description
19562 * The `ngShow` directive shows or hides the given HTML element based on the expression
19563 * provided to the ngShow attribute. The element is shown or hidden by removing or adding
19564 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
19565 * in AngularJS and sets the display style to none (using an !important flag).
19566 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
19567 *
19568 * <pre>
19569 * <!-- when $scope.myValue is truthy (element is visible) -->
19570 * <div ng-show="myValue"></div>
19571 *
19572 * <!-- when $scope.myValue is falsy (element is hidden) -->
19573 * <div ng-show="myValue" class="ng-hide"></div>
19574 * </pre>
19575 *
19576 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
19577 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
19578 * from the element causing the element not to appear hidden.
19579 *
19580 * ## Why is !important used?
19581 *
19582 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
19583 * can be easily overridden by heavier selectors. For example, something as simple
19584 * as changing the display style on a HTML list item would make hidden elements appear visible.
19585 * This also becomes a bigger issue when dealing with CSS frameworks.
19586 *
19587 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
19588 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
19589 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
19590 *
19591 * ### Overriding .ng-hide
19592 *
19593 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
19594 * restating the styles for the .ng-hide class in CSS:
19595 * <pre>
19596 * .ng-hide {
19597 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
19598 *   display:block!important;
19599 *
19600 *   //this is just another form of hiding an element
19601 *   position:absolute;
19602 *   top:-9999px;
19603 *   left:-9999px;
19604 * }
19605 * </pre>
19606 *
19607 * Just remember to include the important flag so the CSS override will function.
19608 *
19609 * <div class="alert alert-warning">
19610 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
19611 * "f" / "0" / "false" / "no" / "n" / "[]"
19612 * </div>
19613 * 
19614 * ## A note about animations with ngShow
19615 *
19616 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
19617 * is true and false. This system works like the animation system present with ngClass except that
19618 * you must also include the !important flag to override the display property
19619 * so that you can perform an animation when the element is hidden during the time of the animation.
19620 *
19621 * <pre>
19622 * //
19623 * //a working example can be found at the bottom of this page
19624 * //
19625 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
19626 *   transition:0.5s linear all;
19627 *   display:block!important;
19628 * }
19629 *
19630 * .my-element.ng-hide-add { ... }
19631 * .my-element.ng-hide-add.ng-hide-add-active { ... }
19632 * .my-element.ng-hide-remove { ... }
19633 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
19634 * </pre>
19635 *
19636 * @animations
19637 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
19638 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
19639 *
19640 * @element ANY
19641 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
19642 *     then the element is shown or hidden respectively.
19643 *
19644 * @example
19645  <example animations="true">
19646    <file name="index.html">
19647      Click me: <input type="checkbox" ng-model="checked"><br/>
19648      <div>
19649        Show:
19650        <div class="check-element animate-show" ng-show="checked">
19651          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
19652        </div>
19653      </div>
19654      <div>
19655        Hide:
19656        <div class="check-element animate-show" ng-hide="checked">
19657          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
19658        </div>
19659      </div>
19660    </file>
19661    <file name="animations.css">
19662      .animate-show {
19663        -webkit-transition:all linear 0.5s;
19664        transition:all linear 0.5s;
19665        line-height:20px;
19666        opacity:1;
19667        padding:10px;
19668        border:1px solid black;
19669        background:white;
19670      }
19671
19672      .animate-show.ng-hide-add,
19673      .animate-show.ng-hide-remove {
19674        display:block!important;
19675      }
19676
19677      .animate-show.ng-hide {
19678        line-height:0;
19679        opacity:0;
19680        padding:0 10px;
19681      }
19682
19683      .check-element {
19684        padding:10px;
19685        border:1px solid black;
19686        background:white;
19687      }
19688    </file>
19689    <file name="protractorTest.js">
19690      var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
19691      var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
19692
19693      it('should check ng-show / ng-hide', function() {
19694        expect(thumbsUp.isDisplayed()).toBeFalsy();
19695        expect(thumbsDown.isDisplayed()).toBeTruthy();
19696
19697        element(by.model('checked')).click();
19698
19699        expect(thumbsUp.isDisplayed()).toBeTruthy();
19700        expect(thumbsDown.isDisplayed()).toBeFalsy();
19701      });
19702    </file>
19703  </example>
19704 */
19705var ngShowDirective = ['$animate', function($animate) {
19706  return function(scope, element, attr) {
19707    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
19708      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
19709    });
19710  };
19711}];
19712
19713
19714/**
19715 * @ngdoc directive
19716 * @name ng.directive:ngHide
19717 *
19718 * @description
19719 * The `ngHide` directive shows or hides the given HTML element based on the expression
19720 * provided to the ngHide attribute. The element is shown or hidden by removing or adding
19721 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
19722 * in AngularJS and sets the display style to none (using an !important flag).
19723 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
19724 *
19725 * <pre>
19726 * <!-- when $scope.myValue is truthy (element is hidden) -->
19727 * <div ng-hide="myValue"></div>
19728 *
19729 * <!-- when $scope.myValue is falsy (element is visible) -->
19730 * <div ng-hide="myValue" class="ng-hide"></div>
19731 * </pre>
19732 *
19733 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
19734 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
19735 * from the element causing the element not to appear hidden.
19736 *
19737 * ## Why is !important used?
19738 *
19739 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
19740 * can be easily overridden by heavier selectors. For example, something as simple
19741 * as changing the display style on a HTML list item would make hidden elements appear visible.
19742 * This also becomes a bigger issue when dealing with CSS frameworks.
19743 *
19744 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
19745 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
19746 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
19747 *
19748 * ### Overriding .ng-hide
19749 *
19750 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
19751 * restating the styles for the .ng-hide class in CSS:
19752 * <pre>
19753 * .ng-hide {
19754 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
19755 *   display:block!important;
19756 *
19757 *   //this is just another form of hiding an element
19758 *   position:absolute;
19759 *   top:-9999px;
19760 *   left:-9999px;
19761 * }
19762 * </pre>
19763 *
19764 * Just remember to include the important flag so the CSS override will function.
19765 * 
19766 * <div class="alert alert-warning">
19767 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
19768 * "f" / "0" / "false" / "no" / "n" / "[]"
19769 * </div>
19770 *
19771 * ## A note about animations with ngHide
19772 *
19773 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
19774 * is true and false. This system works like the animation system present with ngClass, except that
19775 * you must also include the !important flag to override the display property so
19776 * that you can perform an animation when the element is hidden during the time of the animation.
19777 *
19778 * <pre>
19779 * //
19780 * //a working example can be found at the bottom of this page
19781 * //
19782 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
19783 *   transition:0.5s linear all;
19784 *   display:block!important;
19785 * }
19786 *
19787 * .my-element.ng-hide-add { ... }
19788 * .my-element.ng-hide-add.ng-hide-add-active { ... }
19789 * .my-element.ng-hide-remove { ... }
19790 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
19791 * </pre>
19792 *
19793 * @animations
19794 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
19795 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
19796 *
19797 * @element ANY
19798 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
19799 *     the element is shown or hidden respectively.
19800 *
19801 * @example
19802  <example animations="true">
19803    <file name="index.html">
19804      Click me: <input type="checkbox" ng-model="checked"><br/>
19805      <div>
19806        Show:
19807        <div class="check-element animate-hide" ng-show="checked">
19808          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
19809        </div>
19810      </div>
19811      <div>
19812        Hide:
19813        <div class="check-element animate-hide" ng-hide="checked">
19814          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
19815        </div>
19816      </div>
19817    </file>
19818    <file name="animations.css">
19819      .animate-hide {
19820        -webkit-transition:all linear 0.5s;
19821        transition:all linear 0.5s;
19822        line-height:20px;
19823        opacity:1;
19824        padding:10px;
19825        border:1px solid black;
19826        background:white;
19827      }
19828
19829      .animate-hide.ng-hide-add,
19830      .animate-hide.ng-hide-remove {
19831        display:block!important;
19832      }
19833
19834      .animate-hide.ng-hide {
19835        line-height:0;
19836        opacity:0;
19837        padding:0 10px;
19838      }
19839
19840      .check-element {
19841        padding:10px;
19842        border:1px solid black;
19843        background:white;
19844      }
19845    </file>
19846    <file name="protractorTest.js">
19847      var thumbsUp = element(by.css('.doc-example-live span.icon-thumbs-up'));
19848      var thumbsDown = element(by.css('.doc-example-live span.icon-thumbs-down'));
19849
19850      it('should check ng-show / ng-hide', function() {
19851        expect(thumbsUp.isDisplayed()).toBeFalsy();
19852        expect(thumbsDown.isDisplayed()).toBeTruthy();
19853
19854        element(by.model('checked')).click();
19855
19856        expect(thumbsUp.isDisplayed()).toBeTruthy();
19857        expect(thumbsDown.isDisplayed()).toBeFalsy();
19858      });
19859    </file>
19860  </example>
19861 */
19862var ngHideDirective = ['$animate', function($animate) {
19863  return function(scope, element, attr) {
19864    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
19865      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
19866    });
19867  };
19868}];
19869
19870/**
19871 * @ngdoc directive
19872 * @name ng.directive:ngStyle
19873 * @restrict AC
19874 *
19875 * @description
19876 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
19877 *
19878 * @element ANY
19879 * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
19880 *      object whose keys are CSS style names and values are corresponding values for those CSS
19881 *      keys.
19882 *
19883 * @example
19884   <example>
19885     <file name="index.html">
19886        <input type="button" value="set" ng-click="myStyle={color:'red'}">
19887        <input type="button" value="clear" ng-click="myStyle={}">
19888        <br/>
19889        <span ng-style="myStyle">Sample Text</span>
19890        <pre>myStyle={{myStyle}}</pre>
19891     </file>
19892     <file name="style.css">
19893       span {
19894         color: black;
19895       }
19896     </file>
19897     <file name="protractorTest.js">
19898       var colorSpan = element(by.css('.doc-example-live span'));
19899
19900       it('should check ng-style', function() {
19901         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
19902         element(by.css('.doc-example-live input[value=set]')).click();
19903         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
19904         element(by.css('.doc-example-live input[value=clear]')).click();
19905         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
19906       });
19907     </file>
19908   </example>
19909 */
19910var ngStyleDirective = ngDirective(function(scope, element, attr) {
19911  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
19912    if (oldStyles && (newStyles !== oldStyles)) {
19913      forEach(oldStyles, function(val, style) { element.css(style, '');});
19914    }
19915    if (newStyles) element.css(newStyles);
19916  }, true);
19917});
19918
19919/**
19920 * @ngdoc directive
19921 * @name ng.directive:ngSwitch
19922 * @restrict EA
19923 *
19924 * @description
19925 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
19926 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
19927 * as specified in the template.
19928 *
19929 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
19930 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
19931 * matches the value obtained from the evaluated expression. In other words, you define a container element
19932 * (where you place the directive), place an expression on the **`on="..."` attribute**
19933 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
19934 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
19935 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
19936 * attribute is displayed.
19937 *
19938 * <div class="alert alert-info">
19939 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
19940 * as literal string values to match against.
19941 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
19941omeVal"` not against the
19942 * value of the expression `$scope.someVal`.
19943 * </div>
19944
19945 * @animations
19946 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
19947 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
19948 *
19949 * @usage
19950 * <ANY ng-switch="expression">
19951 *   <ANY ng-switch-when="matchValue1">...</ANY>
19952 *   <ANY ng-switch-when="matchValue2">...</ANY>
19953 *   <ANY ng-switch-default>...</ANY>
19954 * </ANY>
19955 *
19956 *
19957 * @scope
19958 * @priority 800
19959 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
19960 * @paramDescription
19961 * On child elements add:
19962 *
19963 * * `ngSwitchWhen`: the case statement to match against. If match then this
19964 *   case will be displayed. If the same match appears multiple times, all the
19965 *   elements will be displayed.
19966 * * `ngSwitchDefault`: the default case when no other case match. If there
19967 *   are multiple default cases, all of them will be displayed when no other
19968 *   case match.
19969 *
19970 *
19971 * @example
19972  <example animations="true">
19973    <file name="index.html">
19974      <div ng-controller="Ctrl">
19975        <select ng-model="selection" ng-options="item for item in items">
19976        </select>
19977        <tt>selection={{selection}}</tt>
19978        <hr/>
19979        <div class="animate-switch-container"
19980          ng-switch on="selection">
19981            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
19982            <div class="animate-switch" ng-switch-when="home">Home Span</div>
19983            <div class="animate-switch" ng-switch-default>default</div>
19984        </div>
19985      </div>
19986    </file>
19987    <file name="script.js">
19988      function Ctrl($scope) {
19989        $scope.items = ['settings', 'home', 'other'];
19990        $scope.selection = $scope.items[0];
19991      }
19992    </file>
19993    <file name="animations.css">
19994      .animate-switch-container {
19995        position:relative;
19996        background:white;
19997        border:1px solid black;
19998        height:40px;
19999        overflow:hidden;
20000      }
20001
20002      .animate-switch {
20003        padding:10px;
20004      }
20005
20006      .animate-switch.ng-animate {
20007        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20008        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20009
20010        position:absolute;
20011        top:0;
20012        left:0;
20013        right:0;
20014        bottom:0;
20015      }
20016
20017      .animate-switch.ng-leave.ng-leave-active,
20018      .animate-switch.ng-enter {
20019        top:-50px;
20020      }
20021      .animate-switch.ng-leave,
20022      .animate-switch.ng-enter.ng-enter-active {
20023        top:0;
20024      }
20025    </file>
20026    <file name="protractorTest.js">
20027      var switchElem = element(by.css('.doc-example-live [ng-switch]'));
20028      var select = element(by.model('selection'));
20029
20030      it('should start in settings', function() {
20031        expect(switchElem.getText()).toMatch(/Settings Div/);
20032      });
20033      it('should change to home', function() {
20034        select.element.all(by.css('option')).get(1).click();
20035        expect(switchElem.getText()).toMatch(/Home Span/);
20036      });
20037      it('should select default', function() {
20038        select.element.all(by.css('option')).get(2).click();
20039        expect(switchElem.getText()).toMatch(/default/);
20040      });
20041    </file>
20042  </example>
20043 */
20044var ngSwitchDirective = ['$animate', function($animate) {
20045  return {
20046    restrict: 'EA',
20047    require: 'ngSwitch',
20048
20049    // asks for $scope to fool the BC controller module
20050    controller: ['$scope', function ngSwitchController() {
20051     this.cases = {};
20052    }],
20053    link: function(scope, element, attr, ngSwitchController) {
20054      var watchExpr = attr.ngSwitch || attr.on,
20055          selectedTranscludes,
20056          selectedElements,
20057          selectedScopes = [];
20058
20059      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
20060        for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
20061          selectedScopes[i].$destroy();
20062          $animate.leave(selectedElements[i]);
20063        }
20064
20065        selectedElements = [];
20066        selectedScopes = [];
20067
20068        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
20069          scope.$eval(attr.change);
20070          forEach(selectedTranscludes, function(selectedTransclude) {
20071            var selectedScope = scope.$new();
20072            selectedScopes.push(selectedScope);
20073            selectedTransclude.transclude(selectedScope, function(caseElement) {
20074              var anchor = selectedTransclude.element;
20075
20076              selectedElements.push(caseElement);
20077              $animate.enter(caseElement, anchor.parent(), anchor);
20078            });
20079          });
20080        }
20081      });
20082    }
20083  };
20084}];
20085
20086var ngSwitchWhenDirective = ngDirective({
20087  transclude: 'element',
20088  priority: 800,
20089  require: '^ngSwitch',
20090  link: function(scope, element, attrs, ctrl, $transclude) {
20091    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
20092    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
20093  }
20094});
20095
20096var ngSwitchDefaultDirective = ngDirective({
20097  transclude: 'element',
20098  priority: 800,
20099  require: '^ngSwitch',
20100  link: function(scope, element, attr, ctrl, $transclude) {
20101    ctrl.cases['?'] = (ctrl.cases['?'] || []);
20102    ctrl.cases['?'].push({ transclude: $transclude, element: element });
20103   }
20104});
20105
20106/**
20107 * @ngdoc directive
20108 * @name ng.directive:ngTransclude
20109 * @restrict AC
20110 *
20111 * @description
20112 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
20113 *
20114 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
20115 *
20116 * @element ANY
20117 *
20118 * @example
20119   <doc:example module="transclude">
20120     <doc:source>
20121       <script>
20122         function Ctrl($scope) {
20123           $scope.title = 'Lorem Ipsum';
20124           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
20125         }
20126
20127         angular.module('transclude', [])
20128          .directive('pane', function(){
20129             return {
20130               restrict: 'E',
20131               transclude: true,
20132               scope: { title:'@' },
20133               template: '<div style="border: 1px solid black;">' +
20134                           '<div style="background-color: gray">{{title}}</div>' +
20135                           '<div ng-transclude></div>' +
20136                         '</div>'
20137             };
20138         });
20139       </script>
20140       <div ng-controller="Ctrl">
20141         <input ng-model="title"><br>
20142         <textarea ng-model="text"></textarea> <br/>
20143         <pane title="{{title}}">{{text}}</pane>
20144       </div>
20145     </doc:source>
20146     <doc:protractor>
20147        it('should have transcluded', function() {
20148          var titleElement = element(by.model('title'));
20149          titleElement.clear();
20150          titleElement.sendKeys('TITLE');
20151          var textElement = element(by.model('text'));
20152          textElement.clear();
20153          textElement.sendKeys('TEXT');
20154          expect(element(by.binding('title')).getText()).toEqual('TITLE');
20155          expect(element(by.binding('text')).getText()).toEqual('TEXT');
20156        });
20157     </doc:protractor>
20158   </doc:example>
20159 *
20160 */
20161var ngTranscludeDirective = ngDirective({
20162  link: function($scope, $element, $attrs, controller, $transclude) {
20163    if (!$transclude) {
20164      throw minErr('ngTransclude')('orphan',
20165       'Illegal use of ngTransclude directive in the template! ' +
20166       'No parent directive that requires a transclusion found. ' +
20167       'Element: {0}',
20168       startingTag($element));
20169    }
20170    
20171    $transclude(function(clone) {
20172      $element.empty();
20173      $element.append(clone);
20174    });
20175  }
20176});
20177
20178/**
20179 * @ngdoc directive
20180 * @name ng.directive:script
20181 * @restrict E
20182 *
20183 * @description
20184 * Load the content of a `<script>` element into {@link api/ng.$templateCache `$templateCache`}, so that the
20185 * template can be used by {@link api/ng.directive:ngInclude `ngInclude`},
20186 * {@link api/ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
20187 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
20188 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
20189 *
20190 * @param {'text/ng-template'} type Must be set to `'text/ng-template'`.
20191 * @param {string} id Cache name of the template.
20192 *
20193 * @example
20194  <doc:example>
20195    <doc:source>
20196      <script type="text/ng-template" id="/tpl.html">
20197        Content of the template.
20198      </script>
20199
20200      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
20201      <div id="tpl-content" ng-include src="currentTpl"></div>
20202    </doc:source>
20203    <doc:protractor>
20204      it('should load template defined inside script tag', function() {
20205        element(by.css('#tpl-link')).click();
20206        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
20207      });
20208    </doc:protractor>
20209  </doc:example>
20210 */
20211var scriptDirective = ['$templateCache', function($templateCache) {
20212  return {
20213    restrict: 'E',
20214    terminal: true,
20215    compile: function(element, attr) {
20216      if (attr.type == 'text/ng-template') {
20217        var templateUrl = attr.id,
20218            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
20219            text = element[0].text;
20220
20221        $templateCache.put(templateUrl, text);
20222      }
20223    }
20224  };
20225}];
20226
20227var ngOptionsMinErr = minErr('ngOptions');
20228/**
20229 * @ngdoc directive
20230 * @name ng.directive:select
20231 * @restrict E
20232 *
20233 * @description
20234 * HTML `SELECT` element with angular data-binding.
20235 *
20236 * # `ngOptions`
20237 *
20238 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
20239 * elements for the `<select>` element using the array or object obtained by evaluating the
20240 * `ngOptions` comprehension_expression.
20241 *
20242 * When an item in the `<select>` menu is selected, the array element or object property
20243 * represented by the selected option will be bound to the model identified by the `ngModel`
20244 * directive.
20245 *
20246 * <div class="alert alert-warning">
20247 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
20248 * array of objects. See an example {@link http://jsfiddle.net/qWzTb/ in this jsfiddle}.
20249 * </div>
20250 *
20251 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
20252 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
20253 * option. See example below for demonstration.
20254 *
20255 * <div class="alert alert-warning">
20256 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
20257 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
20258 * `select` model to be bound to a non-string value. This is because an option element can only
20259 * be bound to string values at present.
20260 * </div>
20261 *
20262 * @param {string} ngModel Assignable angular expression to data-bind to.
20263 * @param {string=} name Property name of the form under which the control is published.
20264 * @param {string=} required The control is considered valid only if value is entered.
20265 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20266 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20267 *    `required` when you want to data-bind to the `required` attribute.
20268 * @param {comprehension_expression=} ngOptions in one of the following forms:
20269 *
20270 *   * for array data sources:
20271 *     * `label` **`for`** `value` **`in`** `array`
20272 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
20273 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
20274 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
20275 *   * for object data sources:
20276 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20277 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20278 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
20279 *     * `select` **`as`** `label` **`group by`** `group`
20280 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
20281 *
20282 * Where:
20283 *
20284 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
20285 *   * `value`: local variable which will refer to each item in the `array` or each property value
20286 *      of `object` during iteration.
20287 *   * `key`: local variable which will refer to a property name in `object` during iteration.
20288 *   * `label`: The result of this expression will be the label for `<option>` element. The
20289 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
20290 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
20291 *      element. If not specified, `select` expression will default to `value`.
20292 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
20293 *      DOM element.
20294 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
20295 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
20296 *     `value` variable (e.g. `value.propertyName`).
20297 *
20298 * @example
20299    <doc:example>
20300      <doc:source>
20301        <script>
20302        function MyCntrl($scope) {
20303          $scope.colors = [
20304            {name:'black', shade:'dark'},
20305            {name:'white', shade:'light'},
20306            {name:'red', shade:'dark'},
20307            {name:'blue', shade:'dark'},
20308            {name:'yellow', shade:'light'}
20309          ];
20310          $scope.color = $scope.colors[2]; // red
20311        }
20312        </script>
20313        <div ng-controller="MyCntrl">
20314          <ul>
20315            <li ng-repeat="color in colors">
20316              Name: <input ng-model="color.name">
20317              [<a href ng-click="colors.splice($index, 1)">X</a>]
20318            </li>
20319            <li>
20320              [<a href ng-click="colors.push({})">add</a>]
20321            </li>
20322          </ul>
20323          <hr/>
20324          Color (null not allowed):
20325          <select ng-model="color" ng-options="c.name for c in colors"></select><br>
20326
20327          Color (null allowed):
20328          <span  class="nullable">
20329            <select ng-model="color" ng-options="c.name for c in colors">
20330              <option value="">-- choose color --</option>
20331            </select>
20332          </span><br/>
20333
20334          Color grouped by shade:
20335          <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
20336          </select><br/>
20337
20338
20339          Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
20340          <hr/>
20341          Currently selected: {{ {selected_color:color}  }}
20342          <div style="border:solid 1px black; height:20px"
20343               ng-style="{'background-color':color.name}">
20344          </div>
20345        </div>
20346      </doc:source>
20347      <doc:protractor>
20348         it('should check ng-options', function() {
20349           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
20350           element.all(by.select('color')).first().click();
20351           element.all(by.css('select[ng-model="color"] option')).first().click();
20352           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
20353           element(by.css('.nullable select[ng-model="color"]')).click();
20354           element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
20355           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
20356         });
20357      </doc:protractor>
20358    </doc:example>
20359 */
20360
20361var ngOptionsDirective = valueFn({ terminal: true });
20362// jshint maxlen: false
20363var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
20364                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
20365  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]+?))?$/,
20366      nullModelCtrl = {$setViewValue: noop};
20367// jshint maxlen: 100
20368
20369  return {
20370    restrict: 'E',
20371    require: ['select', '?ngModel'],
20372    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
20373      var self = this,
20374          optionsMap = {},
20375          ngModelCtrl = nullModelCtrl,
20376          nullOption,
20377          unknownOption;
20378
20379
20380      self.databound = $attrs.ngModel;
20381
20382
20383      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
20384        ngModelCtrl = ngModelCtrl_;
20385        nullOption = nullOption_;
20386        unknownOption = unknownOption_;
20387      };
20388
20389
20390      self.addOption = function(value) {
20391        assertNotHasOwnProperty(value, '"option value"');
20392        optionsMap[value] = true;
20393
20394        if (ngModelCtrl.$viewValue == value) {
20395          $element.val(value);
20396          if (unknownOption.parent()) unknownOption.remove();
20397        }
20398      };
20399
20400
20401      self.removeOption = function(value) {
20402        if (this.hasOption(value)) {
20403          delete optionsMap[value];
20404          if (ngModelCtrl.$viewValue == value) {
20405            this.renderUnknownOption(value);
20406          }
20407        }
20408      };
20409
20410
20411      self.renderUnknownOption = function(val) {
20412        var unknownVal = '? ' + hashKey(val) + ' ?';
20413        unknownOption.val(unknownVal);
20414        $element.prepend(unknownOption);
20415        $element.val(unknownVal);
20416        unknownOption.prop('selected', true); // needed for IE
20417      };
20418
20419
20420      self.hasOption = function(value) {
20421        return optionsMap.hasOwnProperty(value);
20422      };
20423
20424      $scope.$on('$destroy', function() {
20425        // disable unknown option so that we don't do work when the whole select is being destroyed
20426        self.renderUnknownOption = noop;
20427      });
20428    }],
20429
20430    link: function(scope, element, attr, ctrls) {
20431      // if ngModel is not defined, we don't need to do anything
20432      if (!ctrls[1]) return;
20433
20434      var selectCtrl = ctrls[0],
20435          ngModelCtrl = ctrls[1],
20436          multiple = attr.multiple,
20437          optionsExp = attr.ngOptions,
20438          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
20439          emptyOption,
20440          // we can't just jqLite('<option>') since jqLite is not smart enough
20441          // to create it in <select> and IE barfs otherwise.
20442          optionTemplate = jqLite(document.createElement('option')),
20443          optGroupTemplate =jqLite(document.createElement('optgroup')),
20444          unknownOption = optionTemplate.clone();
20445
20446      // find "null" option
20447      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
20448        if (children[i].value === '') {
20449          emptyOption = nullOption = children.eq(i);
20450          break;
20451        }
20452      }
20453
20454      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
20455
20456      // required validator
20457      if (multiple) {
20458        ngModelCtrl.$isEmpty = function(value) {
20459          return !value || value.length === 0;
20460        };
20461      }
20462
20463      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
20464      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
20465      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
20466
20467
20468      ////////////////////////////
20469
20470
20471
20472      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
20473        ngModelCtrl.$render = function() {
20474          var viewValue = ngModelCtrl.$viewValue;
20475
20476          if (selectCtrl.hasOption(viewValue)) {
20477            if (unknownOption.parent()) unknownOption.remove();
20478            selectElement.val(viewValue);
20479            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
20480          } else {
20481            if (isUndefined(viewValue) && emptyOption) {
20482              selectElement.val('');
20483            } else {
20484              selectCtrl.renderUnknownOption(viewValue);
20485            }
20486          }
20487        };
20488
20489        selectElement.on('change', function() {
20490          scope.$apply(function() {
20491            if (unknownOption.parent()) unknownOption.remove();
20492            ngModelCtrl.$setViewValue(selectElement.val());
20493          });
20494        });
20495      }
20496
20497      function setupAsMultiple(scope, selectElement, ctrl) {
20498        var lastView;
20499        ctrl.$render = function() {
20500          var items = new HashMap(ctrl.$viewValue);
20501          forEach(selectElement.find('option'), function(option) {
20502            option.selected = isDefined(items.get(option.value));
20503          });
20504        };
20505
20506        // we have to do it on each watch since ngModel watches reference, but
20507        // we need to work of an array, so we need to see if anything was inserted/removed
20508        scope.$watch(function selectMultipleWatch() {
20509          if (!equals(lastView, ctrl.$viewValue)) {
20510            lastView = copy(ctrl.$viewValue);
20511            ctrl.$render();
20512          }
20513        });
20514
20515        selectElement.on('change', function() {
20516          scope.$apply(function() {
20517            var array = [];
20518            forEach(selectElement.find('option'), function(option) {
20519              if (option.selected) {
20520                array.push(option.value);
20521              }
20522            });
20523            ctrl.$setViewValue(array);
20524          });
20525        });
20526      }
20527
20528      function setupAsOptions(scope, selectElement, ctrl) {
20529        var match;
20530
20531        if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
20532          throw ngOptionsMinErr('iexp',
20533            "Expected expression in form of " +
20534            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
20535            " but got '{0}'. Element: {1}",
20536            optionsExp, startingTag(selectElement));
20537        }
20538
20539        var displayFn = $parse(match[2] || match[1]),
20540            valueName = match[4] || match[6],
20541            keyName = match[5],
20542            groupByFn = $parse(match[3] || ''),
20543            valueFn = $parse(match[2] ? match[1] : valueName),
20544            valuesFn = $parse(match[7]),
20545            track = match[8],
20546            trackFn = track ? $parse(match[8]) : null,
20547            // This is an array of array of existing option groups in DOM.
20548            // We try to reuse these if possible
20549            // - optionGroupsCache[0] is the options with no option group
20550            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
20551            optionGroupsCache = [[{element: selectElement, label:''}]];
20552
20553        if (nullOption) {
20554          // compile the element since there might be bindings in it
20555          $compile(nullOption)(scope);
20556
20557          // remove the class, which is added automatically because we recompile the element and it
20558          // becomes the compilation root
20559          nullOption.removeClass('ng-scope');
20560
20561          // we need to remove it before calling selectElement.empty() because otherwise IE will
20562          // remove the label from the element. wtf?
20563          nullOption.remove();
20564        }
20565
20566        // clear contents, we'll add what's needed based on the model
20567        selectElement.empty();
20568
20569        selectElement.on('change', function() {
20570          scope.$apply(function() {
20571            var optionGroup,
20572                collection = valuesFn(scope) || [],
20573                locals = {},
20574                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
20575
20576            if (multiple) {
20577              value = [];
20578              for (groupIndex = 0, groupLength = optionGroupsCache.length;
20579                   groupIndex < groupLength;
20580                   groupIndex++) {
20581                // list of options for that group. (first item has the parent)
20582                optionGroup = optionGroupsCache[groupIndex];
20583
20584                for(index = 1, length = optionGroup.length; index < length; index++) {
20585                  if ((optionElement = optionGroup[index].element)[0].selected) {
20586                    key = optionElement.val();
20587                    if (keyName) locals[keyName] = key;
20588                    if (trackFn) {
20589                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
20590                        locals[valueName] = collection[trackIndex];
20591                        if (trackFn(scope, locals) == key) break;
20592                      }
20593                    } else {
20594                      locals[valueName] = collection[key];
20595                    }
20596                    value.push(valueFn(scope, locals));
20597                  }
20598                }
20599              }
20600            } else {
20601              key = selectElement.val();
20602              if (key == '?') {
20603                value = undefined;
20604              } else if (key === ''){
20605                value = null;
20606              } else {
20607                if (trackFn) {
20608                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
20609                    locals[valueName] = collection[trackIndex];
20610                    if (trackFn(scope, locals) == key) {
20611                      value = valueFn(scope, locals);
20612                      break;
20613                    }
20614                  }
20615                } else {
20616                  locals[valueName] = collection[key];
20617                  if (keyName) locals[keyName] = key;
20618                  value = valueFn(scope, locals);
20619                }
20620              }
20621            }
20622            ctrl.$setViewValue(value);
20623          });
20624        });
20625
20626        ctrl.$render = render;
20627
20628        // TODO(vojta): can't we optimize this ?
20629        scope.$watch(render);
20630
20631        function render() {
20632              // Temporary location for the option groups before we render them
20633          var optionGroups = {'':[]},
20634              optionGroupNames = [''],
20635              optionGroupName,
20636              optionGroup,
20637              option,
20638              existingParent, existingOptions, existingOption,
20639              modelValue = ctrl.$modelValue,
20640              values = valuesFn(scope) || [],
20641              keys = keyName ? sortedKeys(values) : values,
20642              key,
20643              groupLength, length,
20644              groupIndex, index,
20645              locals = {},
20646              selected,
20647              selectedSet = false, // nothing is selected yet
20648              lastElement,
20649              element,
20650              label;
20651
20652          if (multiple) {
20653            if (trackFn && isArray(modelValue)) {
20654              selectedSet = new HashMap([]);
20655              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
20656                locals[valueName] = modelValue[trackIndex];
20657                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
20658              }
20659            } else {
20660              selectedSet = new HashMap(modelValue);
20661            }
20662          }
20663
20664          // We now build up the list of options we need (we merge later)
20665          for (index = 0; length = keys.length, index < length; index++) {
20666
20667            key = index;
20668            if (keyName) {
20669              key = keys[index];
20670              if ( key.charAt(0) === '$' ) continue;
20671              locals[keyName] = key;
20672            }
20673
20674            locals[valueName] = values[key];
20675
20676            optionGroupName = groupByFn(scope, locals) || '';
20677            if (!(optionGroup = optionGroups[optionGroupName])) {
20678              optionGroup = optionGroups[optionGroupName] = [];
20679              optionGroupNames.push(optionGroupName);
20680            }
20681            if (multiple) {
20682              selected = isDefined(
20683                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
20684              );
20685            } else {
20686              if (trackFn) {
20687                var modelCast = {};
20688                modelCast[valueName] = modelValue;
20689                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
20690              } else {
20691                selected = modelValue === valueFn(scope, locals);
20692              }
20693              selectedSet = selectedSet || selected; // see if at least one item is selected
20694            }
20695            label = displayFn(scope, locals); // what will be seen by the user
20696
20697            // doing displayFn(scope, locals) || '' overwrites zero values
20698            label = isDefined(label) ? label : '';
20699            optionGroup.push({
20700              // either the index into array or key from object
20701              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
20702              label: label,
20703              selected: selected                   // determine if we should be selected
20704            });
20705          }
20706          if (!multiple) {
20707            if (nullOption || modelValue === null) {
20708              // insert null option if we have a placeholder, or the model is null
20709              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
20710            } else if (!selectedSet) {
20711              // option could not be found, we have to insert the undefined item
20712              optionGroups[''].unshift({id:'?', label:'', selected:true});
20713            }
20714          }
20715
20716          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
20717          for (groupIndex = 0, groupLength = optionGroupNames.length;
20718               groupIndex < groupLength;
20719               groupIndex++) {
20720            // current option group name or '' if no group
20721            optionGroupName = optionGroupNames[groupIndex];
20722
20723            // list of options for that group. (first item has the parent)
20724            optionGroup = optionGroups[optionGroupName];
20725
20726            if (optionGroupsCache.length <= groupIndex) {
20727              // we need to grow the optionGroups
20728              existingParent = {
20729                element: optGroupTemplate.clone().attr('label', optionGroupName),
20730                label: optionGroup.label
20731              };
20732              existingOptions = [existingParent];
20733              optionGroupsCache.push(existingOptions);
20734              selectElement.append(existingParent.element);
20735            } else {
20736              existingOptions = optionGroupsCache[groupIndex];
20737              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
20738
20739              // update the OPTGROUP label if not the same.
20740              if (existingParent.label != optionGroupName) {
20741                existingParent.element.attr('label', existingParent.label = optionGroupName);
20742              }
20743            }
20744
20745            lastElement = null;  // start at the beginning
20746            for(index = 0, length = optionGroup.length; index < length; index++) {
20747              option = optionGroup[index];
20748              if ((existingOption = existingOptions[index+1])) {
20749                // reuse elements
20750                lastElement = existingOption.element;
20751                if (existingOption.label !== option.label) {
20752                  lastElement.text(existingOption.label = option.label);
20753                }
20754                if (existingOption.id !== option.id) {
20755                  lastElement.val(existingOption.id = option.id);
20756                }
20757                // lastElement.prop('selected') provided by jQuery has side-effects
20758                if (lastElement[0].selected !== option.selected) {
20759                  lastElement.prop('selected', (existingOption.selected = option.selected));
20760                }
20761              } else {
20762                // grow elements
20763
20764                // if it's a null option
20765                if (option.id === '' && nullOption) {
20766                  // put back the pre-compiled element
20767                  element = nullOption;
20768                } else {
20769                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
20770                  // in this version of jQuery on some browser the .text() returns a string
20771                  // rather then the element.
20772                  (element = optionTemplate.clone())
20773                      .val(option.id)
20774                      .attr('selected', option.selected)
20775                      .text(option.label);
20776                }
20777
20778                existingOptions.push(existingOption = {
20779                    element: element,
20780                    label: option.label,
20781                    id: option.id,
20782                    selected: option.selected
20783                });
20784                if (lastElement) {
20785                  lastElement.after(element);
20786                } else {
20787                  existingParent.element.append(element);
20788                }
20789                lastElement = element;
20790              }
20791            }
20792            // remove any excessive OPTIONs in a group
20793            index++; // increment since the existingOptions[0] is parent element not OPTION
20794            while(existingOptions.length > index) {
20795              existingOptions.pop().element.remove();
20796            }
20797          }
20798          // remove any excessive OPTGROUPs from select
20799          while(optionGroupsCache.length > groupIndex) {
20800            optionGroupsCache.pop()[0].element.remove();
20801          }
20802        }
20803      }
20804    }
20805  };
20806}];
20807
20808var optionDirective = ['$interpolate', function($interpolate) {
20809  var nullSelectCtrl = {
20810    addOption: noop,
20811    removeOption: noop
20812  };
20813
20814  return {
20815    restrict: 'E',
20816    priority: 100,
20817    compile: function(element, attr) {
20818      if (isUndefined(attr.value)) {
20819        var interpolateFn = $interpolate(element.text(), true);
20820        if (!interpolateFn) {
20821          attr.$set('value', element.text());
20822        }
20823      }
20824
20825      return function (scope, element, attr) {
20826        var selectCtrlName = '$selectController',
20827            parent = element.parent(),
20828            selectCtrl = parent.data(selectCtrlName) ||
20829              parent.parent().data(selectCtrlName); // in case we are in optgroup
20830
20831        if (selectCtrl && selectCtrl.databound) {
20832          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
20833          // We don't want the view to drive the initialization of the model anyway.
20834          element.prop('selected', false);
20835        } else {
20836          selectCtrl = nullSelectCtrl;
20837        }
20838
20839        if (interpolateFn) {
20840          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
20841            attr.$set('value', newVal);
20842            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
20843            selectCtrl.addOption(newVal);
20844          });
20845        } else {
20846          selectCtrl.addOption(attr.value);
20847        }
20848
20849        element.on('$destroy', function() {
20850          selectCtrl.removeOption(attr.value);
20851        });
20852      };
20853    }
20854  };
20855}];
20856
20857var styleDirective = valueFn({
20858  restrict: 'E',
20859  terminal: true
20860});
20861
20862  //try to bind to jquery now so that one can write angular.element().read()
20863  //but we will rebind on bootstrap again.
20864  bindJQuery();
20865
20866  publishExternalAPI(angular);
20867
20868  jqLite(document).ready(function() {
20869    angularInit(document, bootstrap);
20870  });
20871
20872})(window, document);
20873
20874!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;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');

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