PageSourceSearch

https://guialopesdalaguna.ms.gov.br/bower_components/angular/angular.js

js guialopesdalaguna.ms.gov.br collected 2026-10-02 22:52:58 UTC 777,951 bytes, 21,464 lines download raw bytes

1/**
2 * @license AngularJS v1.2.16
3 * (c) 2010-2014 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window, document, undefined) {'use strict';
7
8/**
9 * @description
10 *
11 * This object provides a utility for producing rich Error messages within
12 * Angular. It can be called as follows:
13 *
14 * var exampleMinErr = minErr('example');
15 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16 *
17 * The above creates an instance of minErr in the example namespace. The
18 * resulting error will have a namespaced error code of example.one.  The
19 * resulting error will replace {0} with the value of foo, and {1} with the
20 * value of bar. The object is not restricted in the number of arguments it can
21 * take.
22 *
23 * If fewer arguments are specified than necessary for interpolation, the extra
24 * interpolation markers will be preserved in the final string.
25 *
26 * Since data will be parsed statically during a build step, some restrictions
27 * are applied with respect to how minErr instances are created and called.
28 * Instances should have names of the form namespaceMinErr for a minErr created
29 * using minErr('namespace') . Error codes, namespaces and template strings
30 * should all be static strings, not variables or general expressions.
31 *
32 * @param {string} module The namespace to use for the new minErr instance.
33 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
34 */
35
36function minErr(module) {
37  return function () {
38    var code = arguments[0],
39      prefix = '[' + (module ? module + ':' : '') + code + '] ',
40      template = arguments[1],
41      templateArgs = arguments,
42      stringify = function (obj) {
43        if (typeof obj === 'function') {
44          return obj.toString().replace(/ \{[\s\S]*$/, '');
45        } else if (typeof obj === 'undefined') {
46          return 'undefined';
47        } else if (typeof obj !== 'string') {
48          return JSON.stringify(obj);
49        }
50        return obj;
51      },
52      message, i;
53
54    message = prefix + template.replace(/\{\d+\}/g, function (match) {
55      var index = +match.slice(1, -1), arg;
56
57      if (index + 2 < templateArgs.length) {
58        arg = templateArgs[index + 2];
59        if (typeof arg === 'function') {
60          return arg.toString().replace(/ ?\{[\s\S]*$/, '');
61        } else if (typeof arg === 'undefined') {
62          return 'undefined';
63        } else if (typeof arg !== 'string') {
64          return toJson(arg);
65        }
66        return arg;
67      }
68      return match;
69    });
70
71    message = message + '\nhttp://errors.angularjs.org/1.2.16/' +
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    -isBlob,
128    -isBoolean,
129    -trim,
130    -isElement,
131    -makeMap,
132    -map,
133    -size,
134    -includes,
135    -indexOf,
136    -arrayRemove,
137    -isLeafNode,
138    -copy,
139    -shallowCopy,
140    -equals,
141    -csp,
142    -concat,
143    -sliceArgs,
144    -bind,
145    -toJsonReplacer,
146    -toJson,
147    -fromJson,
148    -toBoolean,
149    -startingTag,
150    -tryDecodeURIComponent,
151    -parseKeyValue,
152    -toKeyValue,
153    -encodeUriSegment,
154    -encodeUriQuery,
155    -angularInit,
156    -bootstrap,
157    -snake_case,
158    -bindJQuery,
159    -assertArg,
160    -assertArgFn,
161    -assertNotHasOwnProperty,
162    -getter,
163    -getBlockElements,
164    -hasOwnProperty,
165
166*/
167
168////////////////////////////////////
169
170/**
171 * @ngdoc module
172 * @name ng
173 * @module ng
174 * @description
175 *
176 * # ng (core module)
177 * The ng module is loaded by default when an AngularJS application is started. The module itself
178 * contains the essential components for an AngularJS application to function. The table below
179 * lists a high level breakdown of each of the services/factories, filters, directives and testing
180 * components available within this core module.
181 *
182 * <div doc-module-components="ng"></div>
183 */
184
185/**
186 * @ngdoc function
187 * @name angular.lowercase
188 * @module ng
189 * @function
190 *
191 * @description Converts the specified string to lowercase.
192 * @param {string} string String to be converted to lowercase.
193 * @returns {string} Lowercased string.
194 */
195var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
196var hasOwnProperty = Object.prototype.hasOwnProperty;
197
198/**
199 * @ngdoc function
200 * @name angular.uppercase
201 * @module ng
202 * @function
203 *
204 * @description Converts the specified string to uppercase.
205 * @param {string} string String to be converted to uppercase.
206 * @returns {string} Uppercased string.
207 */
208var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
209
210
211var manualLowercase = function(s) {
212  /* jshint bitwise: false */
213  return isString(s)
214      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
215      : s;
216};
217var manualUppercase = function(s) {
218  /* jshint bitwise: false */
219  return isString(s)
220      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
221      : s;
222};
223
224
225// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
226// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
227// with correct but slower alternatives.
228if ('i' !== 'I'.toLowerCase()) {
229  lowercase = manualLowercase;
230  uppercase = manualUppercase;
231}
232
233
234var /** holds major version number for IE or NaN for real browsers */
235    msie,
236    jqLite,           // delay binding since jQuery could be loaded after us.
237    jQuery,           // delay binding
238    slice             = [].slice,
239    push              = [].push,
240    toString          = Object.prototype.toString,
241    ngMinErr          = minErr('ng'),
242
243
244    _angular          = window.angular,
245    /** @name angular */
246    angular           = window.angular || (window.angular = {}),
247    angularModule,
248    nodeName_,
249    uid               = ['0', '0', '0'];
250
251/**
252 * IE 11 changed the format of the UserAgent string.
253 * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
254 */
255msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
256if (isNaN(msie)) {
257  msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
258}
259
260
261/**
262 * @private
263 * @param {*} obj
264 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
265 *                   String ...)
266 */
267function isArrayLike(obj) {
268  if (obj == null || isWindow(obj)) {
269    return false;
270  }
271
272  var length = obj.length;
273
274  if (obj.nodeType === 1 && length) {
275    return true;
276  }
277
278  return isString(obj) || isArray(obj) || length === 0 ||
279         typeof length === 'number' && length > 0 && (length - 1) in obj;
280}
281
282/**
283 * @ngdoc function
284 * @name angular.forEach
285 * @module ng
286 * @function
287 *
288 * @description
289 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
290 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
291 * is the value of an object property or an array element and `key` is the object property key or
292 * array element index. Specifying a `context` for the function is optional.
293 *
294 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
295 * using the `hasOwnProperty` method.
296 *
297   ```js
298     var values = {name: 'misko', gender: 'male'};
299     var log = [];
300     angular.forEach(values, function(value, key){
301       this.push(key + ': ' + value);
302     }, log);
303     expect(log).toEqual(['name: misko', 'gender: male']);
304   ```
305 *
306 * @param {Object|Array} obj Object to iterate over.
307 * @param {Function} iterator Iterator function.
308 * @param {Object=} context Object to become context (`this`) for the iterator function.
309 * @returns {Object|Array} Reference to `obj`.
310 */
311function forEach(obj, iterator, context) {
312  var key;
313  if (obj) {
314    if (isFunction(obj)){
315      for (key in obj) {
316        // Need to check if hasOwnProperty exists,
317        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
318        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
319          iterator.call(context, obj[key], key);
320        }
321      }
322    }
322 else if (obj.forEach && obj.forEach !== forEach) {
323      obj.forEach(iterator, context);
324    } else if (isArrayLike(obj)) {
325      for (key = 0; key < obj.length; key++)
326        iterator.call(context, obj[key], key);
327    } else {
328      for (key in obj) {
329        if (obj.hasOwnProperty(key)) {
330          iterator.call(context, obj[key], key);
331        }
332      }
333    }
334  }
335  return obj;
336}
337
338function sortedKeys(obj) {
339  var keys = [];
340  for (var key in obj) {
341    if (obj.hasOwnProperty(key)) {
342      keys.push(key);
343    }
344  }
345  return keys.sort();
346}
347
348function forEachSorted(obj, iterator, context) {
349  var keys = sortedKeys(obj);
350  for ( var i = 0; i < keys.length; i++) {
351    iterator.call(context, obj[keys[i]], keys[i]);
352  }
353  return keys;
354}
355
356
357/**
358 * when using forEach the params are value, key, but it is often useful to have key, value.
359 * @param {function(string, *)} iteratorFn
360 * @returns {function(*, string)}
361 */
362function reverseParams(iteratorFn) {
363  return function(value, key) { iteratorFn(key, value); };
364}
365
366/**
367 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
368 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
369 * the number string gets longer over time, and it can also overflow, where as the nextId
370 * will grow much slower, it is a string, and it will never overflow.
371 *
372 * @returns {string} an unique alpha-numeric string
373 */
374function nextUid() {
375  var index = uid.length;
376  var digit;
377
378  while(index) {
379    index--;
380    digit = uid[index].charCodeAt(0);
381    if (digit == 57 /*'9'*/) {
382      uid[index] = 'A';
383      return uid.join('');
384    }
385    if (digit == 90  /*'Z'*/) {
386      uid[index] = '0';
387    } else {
388      uid[index] = String.fromCharCode(digit + 1);
389      return uid.join('');
390    }
391  }
392  uid.unshift('0');
393  return uid.join('');
394}
395
396
397/**
398 * Set or clear the hashkey for an object.
399 * @param obj object
400 * @param h the hashkey (!truthy to delete the hashkey)
401 */
402function setHashKey(obj, h) {
403  if (h) {
404    obj.$$hashKey = h;
405  }
406  else {
407    delete obj.$$hashKey;
408  }
409}
410
411/**
412 * @ngdoc function
413 * @name angular.extend
414 * @module ng
415 * @function
416 *
417 * @description
418 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
419 * to `dst`. You can specify multiple `src` objects.
420 *
421 * @param {Object} dst Destination object.
422 * @param {...Object} src Source object(s).
423 * @returns {Object} Reference to `dst`.
424 */
425function extend(dst) {
426  var h = dst.$$hashKey;
427  forEach(arguments, function(obj){
428    if (obj !== dst) {
429      forEach(obj, function(value, key){
430        dst[key] = value;
431      });
432    }
433  });
434
435  setHashKey(dst,h);
436  return dst;
437}
438
439function int(str) {
440  return parseInt(str, 10);
441}
442
443
444function inherit(parent, extra) {
445  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
446}
447
448/**
449 * @ngdoc function
450 * @name angular.noop
451 * @module ng
452 * @function
453 *
454 * @description
455 * A function that performs no operations. This function can be useful when writing code in the
456 * functional style.
457   ```js
458     function foo(callback) {
459       var result = calculateResult();
460       (callback || angular.noop)(result);
461     }
462   ```
463 */
464function noop() {}
465noop.$inject = [];
466
467
468/**
469 * @ngdoc function
470 * @name angular.identity
471 * @module ng
472 * @function
473 *
474 * @description
475 * A function that returns its first argument. This function is useful when writing code in the
476 * functional style.
477 *
478   ```js
479     function transformer(transformationFn, value) {
480       return (transformationFn || angular.identity)(value);
481     };
482   ```
483 */
484function identity($) {return $;}
485identity.$inject = [];
486
487
488function valueFn(value) {return function() {return value;};}
489
490/**
491 * @ngdoc function
492 * @name angular.isUndefined
493 * @module ng
494 * @function
495 *
496 * @description
497 * Determines if a reference is undefined.
498 *
499 * @param {*} value Reference to check.
500 * @returns {boolean} True if `value` is undefined.
501 */
502function isUndefined(value){return typeof value === 'undefined';}
503
504
505/**
506 * @ngdoc function
507 * @name angular.isDefined
508 * @module ng
509 * @function
510 *
511 * @description
512 * Determines if a reference is defined.
513 *
514 * @param {*} value Reference to check.
515 * @returns {boolean} True if `value` is defined.
516 */
517function isDefined(value){return typeof value !== 'undefined';}
518
519
520/**
521 * @ngdoc function
522 * @name angular.isObject
523 * @module ng
524 * @function
525 *
526 * @description
527 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
528 * considered to be objects. Note that JavaScript arrays are objects.
529 *
530 * @param {*} value Reference to check.
531 * @returns {boolean} True if `value` is an `Object` but not `null`.
532 */
533function isObject(value){return value != null && typeof value === 'object';}
534
535
536/**
537 * @ngdoc function
538 * @name angular.isString
539 * @module ng
540 * @function
541 *
542 * @description
543 * Determines if a reference is a `String`.
544 *
545 * @param {*} value Reference to check.
546 * @returns {boolean} True if `value` is a `String`.
547 */
548function isString(value){return typeof value === 'string';}
549
550
551/**
552 * @ngdoc function
553 * @name angular.isNumber
554 * @module ng
555 * @function
556 *
557 * @description
558 * Determines if a reference is a `Number`.
559 *
560 * @param {*} value Reference to check.
561 * @returns {boolean} True if `value` is a `Number`.
562 */
563function isNumber(value){return typeof value === 'number';}
564
565
566/**
567 * @ngdoc function
568 * @name angular.isDate
569 * @module ng
570 * @function
571 *
572 * @description
573 * Determines if a value is a date.
574 *
575 * @param {*} value Reference to check.
576 * @returns {boolean} True if `value` is a `Date`.
577 */
578function isDate(value){
579  return toString.call(value) === '[object Date]';
580}
581
582
583/**
584 * @ngdoc function
585 * @name angular.isArray
586 * @module ng
587 * @function
588 *
589 * @description
590 * Determines if a reference is an `Array`.
591 *
592 * @param {*} value Reference to check.
593 * @returns {boolean} True if `value` is an `Array`.
594 */
595function isArray(value) {
596  return toString.call(value) === '[object Array]';
597}
598
599
600/**
601 * @ngdoc function
602 * @name angular.isFunction
603 * @module ng
604 * @function
605 *
606 * @description
607 * Determines if a reference is a `Function`.
608 *
609 * @param {*} value Reference to check.
610 * @returns {boolean} True if `value` is a `Function`.
611 */
612function isFunction(value){return typeof value === 'function';}
613
614
615/**
616 * Determines if a value is a regular expression object.
617 *
618 * @private
619 * @param {*} value Reference to check.
620 * @returns {boolean} True if `value` is a `RegExp`.
621 */
622function isRegExp(value) {
623  return toString.call(value) === '[object RegExp]';
624}
625
626
627/**
628 * Checks if `obj` is a window object.
629 *
630 * @private
631 * @param {*} obj Object to check
632 * @returns {boolean} True if `obj` is a window obj.
633 */
634function isWindow(obj) {
635  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
636}
637
638
639function isScope(obj) {
640  return obj && obj.$evalAsync && obj.$watch;
641}
642
643
644function isFile(obj) {
645  return toString.call(obj) === '[object File]';
646}
647
648
649function isBlob(obj) {
650  return toString.call(obj) === '[object Blob]';
651}
652
653
654function isBoolean(value) {
655  return typeof value === 'boolean';
656}
657
658
659var trim = (function() {
660  // native trim is way faster: http://jsperf.com/angular-trim-test
661  // but IE doesn't have it... :-(
662  // TODO: we should move this into IE/ES5 polyfill
663  if (!String.prototype.trim) {
664    return function(value) {
665      return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
666    };
667  }
668  return function(value) {
669    return isString(value) ? value.trim() : value;
670  };
671})();
672
673
674/**
675 * @ngdoc function
676 * @name angular.isElement
677 * @module ng
678 * @function
679 *
680 * @description
681 * Determines if a reference is a DOM element (or wrapped jQuery element).
682 *
683 * @param {*} value Reference to check.
684 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
685 */
686function isElement(node) {
687  return !!(node &&
688    (node.nodeName  // we are a direct element
689    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
690}
691
692/**
693 * @param str 'key1,key2,...'
694 * @returns {object} in the form of {key1:true, key2:true, ...}
695 */
696function makeMap(str){
697  var obj = {}, items = str.split(","), i;
698  for ( i = 0; i < items.length; i++ )
699    obj[ items[i] ] = true;
700  return obj;
701}
702
703
704if (msie < 9) {
705  nodeName_ = function(element) {
706    element = element.nodeName ? element : element[0];
707    return (element.scopeName && element.scopeName != 'HTML')
708      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
709  };
710} else {
711  nodeName_ = function(element) {
712    return element.nodeName ? element.nodeName : element[0].nodeName;
713  };
714}
715
716
717function map(obj, iterator, context) {
718  var results = [];
719  forEach(obj, function(value, index, list) {
720    results.push(iterator.call(context, value, index, list));
721  });
722  return results;
723}
724
725
726/**
727 * @description
728 * Determines the number of elements in an array, the number of properties an object has, or
729 * the length of a string.
730 *
731 * Note: This function is used to augment the Object type in Angular expressions. See
732 * {@link angular.Object} for more information about Angular arrays.
733 *
734 * @param {Object|Array|string} obj Object, array, or string to inspect.
735 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
736 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
737 */
738function size(obj, ownPropsOnly) {
739  var count = 0, key;
740
741  if (isArray(obj) || isString(obj)) {
742    return obj.length;
743  } else if (isObject(obj)){
744    for (key in obj)
745      if (!ownPropsOnly || obj.hasOwnProperty(key))
746        count++;
747  }
748
749  return count;
750}
751
752
753function includes(array, obj) {
754  return indexOf(array, obj) != -1;
755}
756
757function indexOf(array, obj) {
758  if (array.indexOf) return array.indexOf(obj);
759
760  for (var i = 0; i < array.length; i++) {
761    if (obj === array[i]) return i;
762  }
763  return -1;
764}
765
766function arrayRemove(array, value) {
767  var index = indexOf(array, value);
768  if (index >=0)
769    array.splice(index, 1);
770  return value;
771}
772
773function isLeafNode (node) {
774  if (node) {
775    switch (node.nodeName) {
776    case "OPTION":
777    case "PRE":
778    case "TITLE":
779      return true;
780    }
781  }
782  return false;
783}
784
785/**
786 * @ngdoc function
787 * @name angular.copy
788 * @module ng
789 * @function
790 *
791 * @description
792 * Creates a deep copy of `source`, which should be an object or an array.
793 *
794 * * If no destination is supplied, a copy of the object or array is created.
795 * * If a destination is provided, all of its elements (for array) or properties (for objects)
796 *   are deleted and then all elements/properties from the source are copied to it.
797 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
798 * * If `source` is identical to 'destination' an exception will be thrown.
799 *
800 * @param {*} source The source that will be used to make a copy.
801 *                   Can be any type, including primitives, `null`, and `undefined`.
802 * @param {(Object|Array)=} destination Destination into which the source is copied. If
803 *     provided, must be of the same type as `source`.
804 * @returns {*} The copy or updated `destination`, if `destination` was specified.
805 *
806 * @example
807 <example>
808 <file name="index.html">
809 <div ng-controller="Controller">
810 <form novalidate class="simple-form">
811 Name: <input type="text" ng-model="user.name" /><br />
812 E-mail: <input type="email" ng-model="user.email" /><br />
813 Gender: <input type="radio" ng-model="user.gender" value="male" />male
814 <input type="radio" ng-model="user.gender" value="female" />female<br />
815 <button ng-click="reset()">RESET</button>
816 <button ng-click="update(user)">SAVE</button>
817 </form>
818 <pre>form = {{user | json}}</pre>
819 <pre>master = {{master | json}}</pre>
820 </div>
821
822 <script>
823 function Controller($scope) {
824    $scope.master= {};
825
826    $scope.update = function(user) {
827      // Example with 1 argument
828      $scope.master= angular.copy(user);
829    };
830
831    $scope.reset = function() {
832      // Example with 2 arguments
833      angular.copy($scope.master, $scope.user);
834    };
835
836    $scope.reset();
837  }
838 </script>
839 </file>
840 </example>
841 */
842function copy(source, destination){
843  if (isWindow(source) || isScope(source)) {
844    throw ngMinErr('cpws',
845      "Can't copy! Making copies of Window or Scope instances is not supported.");
846  }
847
848  if (!destination) {
849    destination = source;
850    if (source) {
851      if (isArray(source)) {
852        destination = copy(source, []);
853      } else if (isDate(source)) {
854        destination = new Date(source.getTime());
855      } else if (isRegExp(source)) {
856        destination = new RegExp(source.source);
857      } else if (isObject(source)) {
858        destination = copy(source, {});
859      }
860    }
861  } else {
862    if (source === destination) throw ngMinErr('cpi',
863      "Can't copy! Source and destination are identical.");
864    if (isArray(source)) {
865      destination.length = 0;
866      for ( var i = 0; i < source.length; i++) {
867        destination.push(copy(source[i]));
868      }
869    } else {
870      var h = destination.$$hashKey;
871      forEach(destination, function(value, key){
872        delete destination[key];
873      });
874      for ( var key in source) {
875        destination[key] = copy(source[key]);
876      }
877      setHashKey(destination,h);
878    }
879  }
880  return destination;
881}
882
883/**
884 * Create a shallow copy of an object
885 */
886function shallowCopy(src, dst) {
887  dst = dst || {};
888
889  for(var key in src) {
890    // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
891    // so we don't need to worry about using our custom hasOwnProperty here
892    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
893      dst[key] = src[key];
894    }
895  }
896
897  return dst;
898}
899
900
901/**
902 * @ngdoc function
903 * @name angular.equals
904 * @module ng
905 * @function
906 *
907 * @description
908 * Determines if two objects or two values are equivalent. Supports value types, regular
909 * expressions, arrays and objects.
910 *
911 * Two objects or values are considered equivalent if at least one of the following is true:
912 *
913 * * Both objects or values pass `===` comparison.
914 * * Both objects or values are of the same type and all of their properties are equal by
915 *   comparing them with `angular.equals`.
916 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
917 * * Both values represent the same regular expression (In JavasScript,
918 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
919 *   representation matches).
920 *
921 * During a property comparison, properties of `function` type and properties with names
922 * that begin with `$` are ignored.
923 *
924 * Scope and DOMWindow objects are being compared only by identify (`===`).
925 *
926 * @param {*} o1 Object or value to compare.
927 * @param {*} o2 Object or value to compare.
928 * @returns {boolean} True if arguments are equal.
929 */
930function equals(o1, o2) {
931  if (o1 === o2) return true;
932  if (o1 === null || o2 === null) return false;
933  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
934  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
935  if (t1 == t2) {
936    if (t1 == 'object') {
937      if (isArray(o1)) {
938        if (!isArray(o2)) return false;
939        if ((length = o1.length) == o2.length) {
940          for(key=0; key<length; key++) {
941            if (!equals(o1[key], o2[key])) return false;
942          }
943          return true;
944        }
945      } else if (isDate(o1)) {
946        return isDate(o2) && o1.getTime() == o2.getTime();
947      } else if (isRegExp(o1) && isRegExp(o2)) {
948        return o1.toString() == o2.toString();
949      } else {
950        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
951        keySet = {};
952        for(key in o1) {
953          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
954          if (!equals(o1[key], o2[key])) return false;
955          keySet[key] = true;
956        }
957        for(key in o2) {
958          if (!keySet.hasOwnProperty(key) &&
959              key.charAt(0) !== '$' &&
960              o2[key] !== undefined &&
961              !isFunction(o2[key])) return false;
962        }
963        return true;
964      }
965    }
966  }
967  return false;
968}
969
970
971function csp() {
972  return (document.securityPolicy && document.securityPolicy.isActive) ||
973      (document.querySelector &&
974      !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
975}
976
977
978function concat(array1, array2, index) {
979  return array1.concat(slice.call(array2, index));
980}
981
982function sliceArgs(args, startIndex) {
983  return slice.call(args, startIndex || 0);
984}
985
986
987/* jshint -W101 */
988/**
989 * @ngdoc function
990 * @name angular.bind
991 * @module ng
992 * @function
993 *
994 * @description
995 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
996 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
997 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
998 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
999 *
1000 * @param {Object} self Context which `fn` should be evaluated in.
1001 * @param {function()} fn Function to be bound.
1002 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1003 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1004 */
1005/* jshint +W101 */
1006function bind(self, fn) {
1007  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1008  if (isFunction(fn) && !(fn instanceof RegExp)) {
1009    return curryArgs.length
1010      ? function() {
1011          return arguments.length
1012            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1013            : fn.apply(self, curryArgs);
1014        }
1015      : function() {
1016          return arguments.length
1017            ? fn.apply(self, arguments)
1018            : fn.call(self);
1019        };
1020  } else {
1021    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1022    return fn;
1023  }
1024}
1025
1026
1027function toJsonReplacer(key, value) {
1028  var val = value;
1029
1030  if (typeof key === 'string' && key.charAt(0) === '$') {
1031    val = undefined;
1032  } else if (isWindow(value)) {
1033    val = '$WINDOW';
1034  } else if (value &&  document === value) {
1035    val = '$DOCUMENT';
1036  } else if (isScope(value)) {
1037    val = '$SCOPE';
1038  }
1039
1040  return val;
1041}
1042
1043
1044/**
1045 * @ngdoc function
1046 * @name angular.toJson
1047 * @module ng
1048 * @function
1049 *
1050 * @description
1051 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1052 * stripped since angular uses this notation internally.
1053 *
1054 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1055 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
1056 * @returns {string|undefined} JSON-ified string representing `obj`.
1057 */
1058function toJson(obj, pretty) {
1059  if (typeof obj === 'undefined') return undefined;
1060  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1061}
1062
1063
1064/**
1065 * @ngdoc function
1066 * @name angular.fromJson
1067 * @module ng
1068 * @function
1069 *
1070 * @description
1071 * Deserializes a JSON string.
1072 *
1073 * @param {string} json JSON string to deserialize.
1074 * @returns {Object|Array|string|number} Deserialized thingy.
1075 */
1076function fromJson(json) {
1077  return isString(json)
1078      ? JSON.parse(json)
1079      : json;
1080}
1081
1082
1083function toBoolean(value) {
1084  if (typeof value === 'function') {
1085    value = true;
1086  } else if (value && value.length !== 0) {
1087    var v = lowercase("" + value);
1088    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1089  } else {
1090    value = false;
1091  }
1092  return value;
1093}
1094
1095/**
1096 * @returns {string} Returns the string representation of the element.
1097 */
1098function startingTag(element) {
1099  element = jqLite(element).clone();
1100  try {
1101    // turns out IE does not let you set .html() on elements which
1102    // are not allowed to have children. So we just ignore it.
1103    element.empty();
1104  } catch(e) {}
1105  // As Per DOM Standards
1106  var TEXT_NODE = 3;
1107  var elemHtml = jqLite('<div>').append(element).html();
1108  try {
1109    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1110        elemHtml.
1111          match(/^(<[^>]+>)/)[1].
1112          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1113  } catch(e) {
1114    return lowercase(elemHtml);
1115  }
1116
1117}
1118
1119
1120/////////////////////////////////////////////////
1121
1122/**
1123 * Tries to decode the URI component without throwing an exception.
1124 *
1125 * @private
1126 * @param str value potential URI component to check.
1127 * @returns {boolean} True if `value` can be decoded
1128 * with the decodeURIComponent function.
1129 */
1130function tryDecodeURIComponent(value) {
1131  try {
1132    return decodeURIComponent(value);
1133  } catch(e) {
1134    // Ignore any invalid uri component
1135  }
1136}
1137
1138
1139/**
1140 * Parses an escaped url query string into key-value pairs.
1141 * @returns {Object.<string,boolean|Array>}
1142 */
1143function parseKeyValue(/**string*/keyValue) {
1144  var obj = {}, key_value, key;
1145  forEach((keyValue || "").split('&'), function(keyValue){
1146    if ( keyValue ) {
1147      key_value = keyValue.split('=');
1148      key = tryDecodeURIComponent(key_value[0]);
1149      if ( isDefined(key) ) {
1150        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1151        if (!obj[key]) {
1152          obj[key] = val;
1153        } else if(isArray(obj[key])) {
1154          obj[key].push(val);
1155        } else {
1156          obj[key] = [obj[key],val];
1157        }
1158      }
1159    }
1160  });
1161  return obj;
1162}
1163
1164function toKeyValue(obj) {
1165  var parts = [];
1166  forEach(obj, function(value, key) {
1167    if (isArray(value)) {
1168      forEach(value, function(arrayValue) {
1169        parts.push(encodeUriQuery(key, true) +
1170                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1171      });
1172    } else {
1173    parts.push(encodeUriQuery(key, true) +
1174               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1175    }
1176  });
1177  return parts.length ? parts.join('&') : '';
1178}
1179
1180
1181/**
1182 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1183 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1184 * segments:
1185 *    segment       = *pchar
1186 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1187 *    pct-encoded   = "%" HEXDIG HEXDIG
1188 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1189 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1190 *                     / "*" / "+" / "," / ";" / "="
1191 */
1192function encodeUriSegment(val) {
1193  return encodeUriQuery(val, true).
1194             replace(/%26/gi, '&').
1195             replace(/%3D/gi, '=').
1196             replace(/%2B/gi, '+');
1197}
1198
1199
1200/**
1201 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1202 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1203 * encoded per http://tools.ietf.org/html/rfc3986:
1204 *    query       = *( pchar / "/" / "?" )
1205 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1206 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1207 *    pct-encoded   = "%" HEXDIG HEXDIG
1208 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1209 *                     / "*" / "+" / "," / ";" / "="
1210 */
1211function encodeUriQuery(val, pctEncodeSpaces) {
1212  return encodeURIComponent(val).
1213             replace(/%40/gi, '@').
1214             replace(/%3A/gi, ':').
1215             replace(/%24/g, '$').
1216             replace(/%2C/gi, ',').
1217             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1218}
1219
1220
1221/**
1222 * @ngdoc directive
1223 * @name ngApp
1224 * @module ng
1225 *
1226 * @element ANY
1227 * @param {angular.Module} ngApp an optional application
1228 *   {@link angular.module module} name to load.
1229 *
1230 * @description
1231 *
1232 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1233 * designates the **root element** of the application and is typically placed near the root element
1234 * of the page - e.g. on the `<body>` or `<html>` tags.
1235 *
1236 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1237 * found in the document will be used to define the root element to auto-bootstrap as an
1238 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1239 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1240 *
1241 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1242 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1243 * should contain the application code needed or have dependencies on other modules that will
1244 * contain the code. See {@link angular.module} for more information.
1245 *
1246 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1247 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1248 * would not be resolved to `3`.
1249 *
1250 * `ngApp` is the easiest, and most common, way to bootstrap an application.
1251 *
1252 <example module="ngAppDemo">
1253   <file name="index.html">
1254   <div ng-controller="ngAppDemoController">
1255     I can add: {{a}} + {{b}} =  {{ a+b }}
1256   </div>
1257   </file>
1258   <file name="script.js">
1259   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1260     $scope.a = 1;
1261     $scope.b = 2;
1262   });
1263   </file>
1264 </example>
1265 *
1266 */
1267function angularInit(element, bootstrap) {
1268  var elements = [element],
1269      appElement,
1270      module,
1271      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1272      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1273
1274  function append(element) {
1275    element && elements.push(element);
1276  }
1277
1278  forEach(names, function(name) {
1279    names[name] = true;
1280    append(document.getElementById(name));
1281    name = name.replace(':', '\\:');
1282    if (element.querySelectorAll) {
1283      forEach(element.querySelectorAll('.' + name), append);
1284      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1285      forEach(element.querySelectorAll('[' + name + ']'), append);
1286    }
1287  });
1288
1289  forEach(elements, function(element) {
1290    if (!appElement) {
1291      var className = ' ' + element.className + ' ';
1292      var match = NG_APP_CLASS_REGEXP.exec(className);
1293      if (match) {
1294        appElement = element;
1295        module = (match[2] || '').replace(/\s+/g, ',');
1296      } else {
1297        forEach(element.attributes, function(attr) {
1298          if (!appElement && names[attr.name]) {
1299            appElement = element;
1300            module = attr.value;
1301          }
1302        });
1303      }
1304    }
1305  });
1306  if (appElement) {
1307    bootstrap(appElement, module ? [module] : []);
1308  }
1309}
1310
1311/**
1312 * @ngdoc function
1313 * @name angular.bootstrap
1314 * @module ng
1315 * @description
1316 * Use this function to manually start up angular application.
1317 *
1318 * See: {@link guide/bootstrap Bootstrap}
1319 *
1320 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1321 * They must use {@link ng.directive:ngApp ngApp}.
1322 *
1323 * Angular will detect if it has been loaded into the browser more than once and only allow the
1324 * first loaded script to be bootstrapped and will report a warning to the browser console for
1325 * each of the subsequent scripts.   This prevents strange results in applications, where otherwise
1326 * multiple instances of Angular try to work on the DOM.
1327 *
1328 * <example name="multi-bootstrap" module="multi-bootstrap">
1329 * <file name="index.html">
1330 * <script src="../../../angular.js"></script>
1331 * <div ng-controller="BrokenTable">
1332 *   <table>
1333 *   <tr>
1334 *     <th ng-repeat="heading in headings">{{heading}}</th>
1335 *   </tr>
1336 *   <tr ng-repeat="filling in fillings">
1337 *     <td ng-repeat="fill in filling">{{fill}}</td>
1338 *   </tr>
1339 * </table>
1340 * </div>
1341 * </file>
1342 * <file name="controller.js">
1343 * var app = angular.module('multi-bootstrap', [])
1344 *
1345 * .controller('BrokenTable', function($scope) {
1346 *     $scope.headings = ['One', 'Two', 'Three'];
1347 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1348 * });
1349 * </file>
1350 * <file name="protractor.js" type="protractor">
1351 * it('should only insert one table cell for each item in $scope.fillings', function() {
1352 *  expect(element.all(by.css('td')).count())
1353 *      .toBe(9);
1354 * });
1355 * </file>
1356 * </example>
1357 *
1358 * @param {DOMElement} element DOM element which is the root of angular application.
1359 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1360 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1361 *     function that will be invoked by the injector as a run block.
1362 *     See: {@link angular.module modules}
1363 * @returns {auto.$injector} Returns the newly created injector for this app.
1364 */
1365function bootstrap(element, modules) {
1366  var doBootstrap = function() {
1367    element = jqLite(element);
1368
1369    if (element.injector()) {
1370      var tag = (element[0] === document) ? 'document' : startingTag(element);
1371      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1372    }
1373
1374    modules = modules || [];
1375    modules.unshift(['$provide', function($provide) {
1376      $provide.value('$rootElement', element);
1377    }]);
1378    modules.unshift('ng');
1379    var injector = createInjector(modules);
1380    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1381       function(scope, element, compile, injector, animate) {
1382        scope.$apply(function() {
1383          element.data('$injector', injector);
1384          compile(element)(scope);
1385        });
1386      }]
1387    );
1388    return injector;
1389  };
1390
1391  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1392
1393  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1394    return doBootstrap();
1395  }
1396
1397  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1398  angular.resumeBootstrap = function(extraModules) {
1399    forEach(extraModules, function(module) {
1400      modules.push(module);
1401    });
vendor: 2,868 bytes, lines 1402-1499
1402    doBootstrap();
1403  };
1404}
1405
1406var SNAKE_CASE_REGEXP = /[A-Z]/g;
1407function snake_case(name, separator){
1408  separator = separator || '_';
1409  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1410    return (pos ? separator : '') + letter.toLowerCase();
1411  });
1412}
1413
1414function bindJQuery() {
1415  // bind to jQuery if present;
1416  jQuery = window.jQuery;
1417  // reset to jQuery or default to us.
1418  if (jQuery) {
1419    jqLite = jQuery;
1420    extend(jQuery.fn, {
1421      scope: JQLitePrototype.scope,
1422      isolateScope: JQLitePrototype.isolateScope,
1423      controller: JQLitePrototype.controller,
1424      injector: JQLitePrototype.injector,
1425      inheritedData: JQLitePrototype.inheritedData
1426    });
1427    // Method signature:
1428    //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1429    jqLitePatchJQueryRemove('remove', true, true, false);
1430    jqLitePatchJQueryRemove('empty', false, false, false);
1431    jqLitePatchJQueryRemove('html', false, false, true);
1432  } else {
1433    jqLite = JQLite;
1434  }
1435  angular.element = jqLite;
1436}
1437
1438/**
1439 * throw error if the argument is falsy.
1440 */
1441function assertArg(arg, name, reason) {
1442  if (!arg) {
1443    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1444  }
1445  return arg;
1446}
1447
1448function assertArgFn(arg, name, acceptArrayAnnotation) {
1449  if (acceptArrayAnnotation && isArray(arg)) {
1450      arg = arg[arg.length - 1];
1451  }
1452
1453  assertArg(isFunction(arg), name, 'not a function, got ' +
1454      (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
1455  return arg;
1456}
1457
1458/**
1459 * throw error if the name given is hasOwnProperty
1460 * @param  {String} name    the name to test
1461 * @param  {String} context the context in which the name is used, such as module or directive
1462 */
1463function assertNotHasOwnProperty(name, context) {
1464  if (name === 'hasOwnProperty') {
1465    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1466  }
1467}
1468
1469/**
1470 * Return the value accessible from the object by path. Any undefined traversals are ignored
1471 * @param {Object} obj starting object
1472 * @param {String} path path to traverse
1473 * @param {boolean} [bindFnToScope=true]
1474 * @returns {Object} value as accessible by path
1475 */
1476//TODO(misko): this function needs to be removed
1477function getter(obj, path, bindFnToScope) {
1478  if (!path) return obj;
1479  var keys = path.split('.');
1480  var key;
1481  var lastInstance = obj;
1482  var len = keys.length;
1483
1484  for (var i = 0; i < len; i++) {
1485    key = keys[i];
1486    if (obj) {
1487      obj = (lastInstance = obj)[key];
1488    }
1489  }
1490  if (!bindFnToScope && isFunction(obj)) {
1491    return bind(lastInstance, obj);
1492  }
1493  return obj;
1494}
1495
1496/**
1497 * Return the DOM siblings between the first and last node in the given array.
1498 * @param {Array} array like object
1499 * @returns {DOMElement}
1499 object containing the elements
1500 */
1501function getBlockElements(nodes) {
1502  var startNode = nodes[0],
1503      endNode = nodes[nodes.length - 1];
1504  if (startNode === endNode) {
1505    return jqLite(startNode);
1506  }
1507
1508  var element = startNode;
1509  var elements = [element];
1510
1511  do {
1512    element = element.nextSibling;
1513    if (!element) break;
1514    elements.push(element);
1515  } while (element !== endNode);
1516
1517  return jqLite(elements);
1518}
1519
1520/**
1521 * @ngdoc type
1522 * @name angular.Module
1523 * @module ng
1524 * @description
1525 *
1526 * Interface for configuring angular {@link angular.module modules}.
1527 */
1528
1529function setupModuleLoader(window) {
1530
1531  var $injectorMinErr = minErr('$injector');
1532  var ngMinErr = minErr('ng');
1533
1534  function ensure(obj, name, factory) {
1535    return obj[name] || (obj[name] = factory());
1536  }
1537
1538  var angular = ensure(window, 'angular', Object);
1539
1540  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1541  angular.$$minErr = angular.$$minErr || minErr;
1542
1543  return ensure(angular, 'module', function() {
1544    /** @type {Object.<string, angular.Module>} */
1545    var modules = {};
1546
1547    /**
1548     * @ngdoc function
1549     * @name angular.module
1550     * @module ng
1551     * @description
1552     *
1553     * The `angular.module` is a global place for creating, registering and retrieving Angular
1554     * modules.
1555     * All modules (angular core or 3rd party) that should be available to an application must be
1556     * registered using this mechanism.
1557     *
1558     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1559     * existing module (the name passed as the first argument to `module`) is retrieved.
1560     *
1561     *
1562     * # Module
1563     *
1564     * A module is a collection of services, directives, filters, and configuration information.
1565     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1566     *
1567     * ```js
1568     * // Create a new module
1569     * var myModule = angular.module('myModule', []);
1570     *
1571     * // register a new service
1572     * myModule.value('appName', 'MyCoolApp');
1573     *
1574     * // configure existing services inside initialization blocks.
1575     * myModule.config(['$locationProvider', function($locationProvider) {
1576     *   // Configure existing providers
1577     *   $locationProvider.hashPrefix('!');
1578     * }]);
1579     * ```
1580     *
1581     * Then you can create an injector and load your modules like this:
1582     *
1583     * ```js
1584     * var injector = angular.injector(['ng', 'myModule'])
1585     * ```
1586     *
1587     * However it's more likely that you'll just use
1588     * {@link ng.directive:ngApp ngApp} or
1589     * {@link angular.bootstrap} to simplify this process for you.
1590     *
1591     * @param {!string} name The name of the module to create or retrieve.
1592<<<<<* @param {!Array.<string>=} requires If specified then new module is being created. If
1593>>>>>*        unspecified then the module is being retrieved for further configuration.
1594     * @param {Function} configFn Optional configuration function for the module. Same as
1595     *        {@link angular.Module#config Module#config()}.
1596     * @returns {module} new module with the {@link angular.Module} api.
1597     */
1598    return function module(name, requires, configFn) {
1599      var assertNotHasOwnProperty = function(name, context) {
1600        if (name === 'hasOwnProperty') {
1601          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1602        }
1603      };
1604
1605      assertNotHasOwnProperty(name, 'module');
1606      if (requires && modules.hasOwnProperty(name)) {
1607        modules[name] = null;
1608      }
1609      return ensure(modules, name, function() {
1610        if (!requires) {
1611          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1612             "the module name or forgot to load it. If registering a module ensure that you " +
1613             "specify the dependencies as the second argument.", name);
1614        }
1615
1616        /** @type {!Array.<Array.<*>>} */
1617        var invokeQueue = [];
1618
1619        /** @type {!Array.<Function>} */
1620        var runBlocks = [];
1621
1622        var config = invokeLater('$injector', 'invoke');
1623
1624        /** @type {angular.Module} */
1625        var moduleInstance = {
1626          // Private state
1627          _invokeQueue: invokeQueue,
1628          _runBlocks: runBlocks,
1629
1630          /**
1631           * @ngdoc property
1632           * @name angular.Module#requires
1633           * @module ng
1634           * @returns {Array.<string>} List of module names which must be loaded before this module.
1635           * @description
1636           * Holds the list of modules which the injector will load before the current module is
1637           * loaded.
1638           */
1639          requires: requires,
1640
1641          /**
1642           * @ngdoc property
1643           * @name angular.Module#name
1644           * @module ng
1645           * @returns {string} Name of the module.
1646           * @description
1647           */
1648          name: name,
1649
1650
1651          /**
1652           * @ngdoc method
1653           * @name angular.Module#provider
1654           * @module ng
1655           * @param {string} name service name
1656           * @param {Function} providerType Construction function for creating new instance of the
1657           *                                service.
1658           * @description
1659           * See {@link auto.$provide#provider $provide.provider()}.
1660           */
1661          provider: invokeLater('$provide', 'provider'),
1662
1663          /**
1664           * @ngdoc method
1665           * @name angular.Module#factory
1666           * @module ng
1667           * @param {string} name service name
1668           * @param {Function} providerFunction Function for creating new instance of the service.
1669           * @description
1670           * See {@link auto.$provide#factory $provide.factory()}.
1671           */
1672          factory: invokeLater('$provide', 'factory'),
1673
1674          /**
1675           * @ngdoc method
1676           * @name angular.Module#service
1677           * @module ng
1678           * @param {string} name service name
1679           * @param {Function} constructor A constructor function that will be instantiated.
1680           * @description
1681           * See {@link auto.$provide#service $provide.service()}.
1682           */
1683          service: invokeLater('$provide', 'service'),
1684
1685          /**
1686           * @ngdoc method
1687           * @name angular.Module#value
1688           * @module ng
1689           * @param {string} name service name
1690           * @param {*} object Service instance object.
1691           * @description
1692           * See {@link auto.$provide#value $provide.value()}.
1693           */
1694          value: invokeLater('$provide', 'value'),
1695
1696          /**
1697           * @ngdoc method
1698           * @name angular.Module#constant
1699           * @module ng
1700           * @param {string} name constant name
1701           * @param {*} object Constant value.
1702           * @description
1703           * Because the constant are fixed, they get applied before other provide methods.
1704           * See {@link auto.$provide#constant $provide.constant()}.
1705           */
1706          constant: invokeLater('$provide', 'constant', 'unshift'),
1707
1708          /**
1709           * @ngdoc method
1710           * @name angular.Module#animation
1711           * @module ng
1712           * @param {string} name animation name
1713           * @param {Function} animationFactory Factory function for creating new instance of an
1714           *                                    animation.
1715           * @description
1716           *
1717           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1718           *
1719           *
1720           * Defines an animation hook that can be later used with
1721           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1722           *
1723           * ```js
1724           * module.animation('.animation-name', function($inject1, $inject2) {
1725           *   return {
1726           *     eventName : function(element, done) {
1727           *       //code to run the animation
1728           *       //once complete, then run done()
1729           *       return function cancellationFunction(element) {
1730           *         //code to cancel the animation
1731           *       }
1732           *     }
1733           *   }
1734           * })
1735           * ```
1736           *
1737           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1738           * {@link ngAnimate ngAnimate module} for more information.
1739           */
1740          animation: invokeLater('$animateProvider', 'register'),
1741
1742          /**
1743           * @ngdoc method
1744           * @name angular.Module#filter
1745           * @module ng
1746           * @param {string} name Filter name.
1747           * @param {Function} filterFactory Factory function for creating new instance of filter.
1748           * @description
1749           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1750           */
1751          filter: invokeLater('$filterProvider', 'register'),
1752
1753          /**
1754           * @ngdoc method
1755           * @name angular.Module#controller
1756           * @module ng
1757           * @param {string|Object} name Controller name, or an object map of controllers where the
1758           *    keys are the names and the values are the constructors.
1759           * @param {Function} constructor Controller constructor function.
1760           * @description
1761           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1762           */
1763          controller: invokeLater('$controllerProvider', 'register'),
1764
1765          /**
1766           * @ngdoc method
1767           * @name angular.Module#directive
1768           * @module ng
1769           * @param {string|Object} name Directive name, or an object map of directives where the
1770           *    keys are the names and the values are the factories.
1771           * @param {Function} directiveFactory Factory function for creating new instance of
1772           * directives.
1773           * @description
1774           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1775           */
1776          directive: invokeLater('$compileProvider', 'directive'),
1777
1778          /**
1779           * @ngdoc method
1780           * @name angular.Module#config
1781           * @module ng
1782           * @param {Function} configFn Execute this function on module load. Useful for service
1783           *    configuration.
1784           * @description
1785           * Use this method to register work which needs to be performed on module loading.
1786           */
1787          config: config,
1788
1789          /**
1790           * @ngdoc method
1791           * @name angular.Module#run
1792           * @module ng
1793           * @param {Function} initializationFn Execute this function after injector creation.
1794           *    Useful for application initialization.
1795           * @description
1796           * Use this method to register work which should be performed when the injector is done
1797           * loading all modules.
1798           */
1799          run: function(block) {
1800            runBlocks.push(block);
1801            return this;
1802          }
1803        };
1804
1805        if (configFn) {
1806          config(configFn);
1807        }
1808
1809        return  moduleInstance;
1810
1811        /**
1812         * @param {string} provider
1813         * @param {string} method
1814         * @param {String=} insertMethod
1815         * @returns {angular.Module}
1816         */
1817        function invokeLater(provider, method, insertMethod) {
1818          return function() {
1819            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1820            return moduleInstance;
1821          };
1822        }
1823      });
1824    };
1825  });
1826
1827}
1828
1829/* global
1830    angularModule: true,
1831    version: true,
1832
1833    $LocaleProvider,
1834    $CompileProvider,
1835
1836    htmlAnchorDirective,
1837    inputDirective,
1838    inputDirective,
1839    formDirective,
1840    scriptDirective,
1841    selectDirective,
1842    styleDirective,
1843    optionDirective,
1844    ngBindDirective,
1845    ngBindHtmlDirective,
1846    ngBindTemplateDirective,
1847    ngClassDirective,
1848    ngClassEvenDirective,
1849    ngClassOddDirective,
1850    ngCspDirective,
1851    ngCloakDirective,
1852    ngControllerDirective,
1853    ngFormDirective,
1854    ngHideDirective,
1855    ngIfDirective,
1856    ngIncludeDirective,
1857    ngIncludeFillContentDirective,
1858    ngInitDirective,
1859    ngNonBindableDirective,
1860    ngPluralizeDirective,
1861    ngRepeatDirective,
1862    ngShowDirective,
1863    ngStyleDirective,
1864    ngSwitchDirective,
1865    ngSwitchWhenDirective,
1866    ngSwitchDefaultDirective,
1867    ngOptionsDirective,
1868    ngTranscludeDirective,
1869    ngModelDirective,
1870    ngListDirective,
1871    ngChangeDirective,
1872    requiredDirective,
1873    requiredDirective,
1874    ngValueDirective,
1875    ngAttributeAliasDirectives,
1876    ngEventDirectives,
1877
1878    $AnchorScrollProvider,
1879    $AnimateProvider,
1880    $BrowserProvider,
1881    $CacheFactoryProvider,
1882    $ControllerProvider,
1883    $DocumentProvider,
1884    $ExceptionHandlerProvider,
1885    $FilterProvider,
1886    $InterpolateProvider,
1887    $IntervalProvider,
1888    $HttpProvider,
1889    $HttpBackendProvider,
1890    $LocationProvider,
1891    $LogProvider,
1892    $ParseProvider,
1893    $RootScopeProvider,
1894    $QProvider,
1895    $$SanitizeUriProvider,
1896    $SceProvider,
1897    $SceDelegateProvider,
1898    $SnifferProvider,
1899    $TemplateCacheProvider,
1900    $TimeoutProvider,
1901    $$RAFProvider,
1902    $$AsyncCallbackProvider,
1903    $WindowProvider
1904*/
1905
1906
1907/**
1908 * @ngdoc object
1909 * @name angular.version
1910 * @module ng
1911 * @description
1912 * An object that contains information about the current AngularJS version. This object has the
1913 * following properties:
1914 *
1915 * - `full` – `{string}` – Full version string, such as "0.9.18".
1916 * - `major` – `{number}` – Major version number, such as "0".
1917 * - `minor` – `{number}` – Minor version number, such as "9".
1918 * - `dot` – `{number}` – Dot version number, such as "18".
1919 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1920 */
1921var version = {
1922  full: '1.2.16',    // all of these placeholder strings will be replaced by grunt's
1923  major: 1,    // package task
1924  minor: 2,
1925  dot: 16,
1926  codeName: 'badger-enumeration'
1927};
1928
1929
1930function publishExternalAPI(angular){
1931  extend(angular, {
1932    'bootstrap': bootstrap,
1933    'copy': copy,
1934    'extend': extend,
1935    'equals': equals,
1936    'element': jqLite,
1937    'forEach': forEach,
1938    'injector': createInjector,
1939    'noop':noop,
1940    'bind':bind,
1941    'toJson': toJson,
1942    'fromJson': fromJson,
1943    'identity':identity,
1944    'isUndefined': isUndefined,
1945    'isDefined': isDefined,
1946    'isString': isString,
1947    'isFunction': isFunction,
1948    'isObject': isObject,
1949    'isNumber': isNumber,
1950    'isElement': isElement,
1951    'isArray': isArray,
1952    'version': version,
1953    'isDate': isDate,
1954    'lowercase': lowercase,
1955    'uppercase': uppercase,
1956    'callbacks': {counter: 0},
1957    '$$minErr': minErr,
1958    '$$csp': csp
1959  });
1960
1961  angularModule = setupModuleLoader(window);
1962  try {
1963    angularModule('ngLocale');
1964  } catch (e) {
1965    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
1966  }
1967
1968  angularModule('ng', ['ngLocale'], ['$provide',
1969    function ngModule($provide) {
1970      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
1971      $provide.provider({
1972        $$sanitizeUri: $$SanitizeUriProvider
1973      });
1974      $provide.provider('$compile', $CompileProvider).
1975        directive({
1976            a: htmlAnchorDirective,
1977            input: inputDirective,
1978            textarea: inputDirective,
1979            form: formDirective,
1980            script: scriptDirective,
1981            select: selectDirective,
1982            style: styleDirective,
1983            option: optionDirective,
1984            ngBind: ngBindDirective,
1985            ngBindHtml: ngBindHtmlDirective,
1986            ngBindTemplate: ngBindTemplateDirective,
1987            ngClass: ngClassDirective,
1988            ngClassEven: ngClassEvenDirective,
1989            ngClassOdd: ngClassOddDirective,
1990            ngCloak: ngCloakDirective,
1991            ngController: ngControllerDirective,
1992            ngForm: ngFormDirective,
1993            ngHide: ngHideDirective,
1994            ngIf: ngIfDirective,
1995            ngInclude: ngIncludeDirective,
1996            ngInit: ngInitDirective,
1997            ngNonBindable: ngNonBindableDirective,
1998            ngPluralize: ngPluralizeDirective,
1999            ngRepeat: ngRepeatDirective,
2000            ngShow: ngShowDirective,
2001            ngStyle: ngStyleDirective,
2002            ngSwitch: ngSwitchDirective,
2003            ngSwitchWhen: ngSwitchWhenDirective,
2004            ngSwitchDefault: ngSwitchDefaultDirective,
2005            ngOptions: ngOptionsDirective,
2006            ngTransclude: ngTranscludeDirective,
2007            ngModel: ngModelDirective,
2008            ngList: ngListDirective,
2009            ngChange: ngChangeDirective,
2010            required: requiredDirective,
2011            ngRequired: requiredDirective,
2012            ngValue: ngValueDirective
2013        }).
2014        directive({
2015          ngInclude: ngIncludeFillContentDirective
2016        }).
2017        directive(ngAttributeAliasDirectives).
2018        directive(ngEventDirectives);
2019      $provide.provider({
2020        $anchorScroll: $AnchorScrollProvider,
2021        $animate: $AnimateProvider,
2022        $browser: $BrowserProvider,
2023        $cacheFactory: $CacheFactoryProvider,
2024        $controller: $ControllerProvider,
2025        $document: $DocumentProvider,
2026        $exceptionHandler: $ExceptionHandlerProvider,
2027        $filter: $FilterProvider,
2028        $interpolate: $InterpolateProvider,
2029        $interval: $IntervalProvider,
2030        $http: $HttpProvider,
2031        $httpBackend: $HttpBackendProvider,
2032        $location: $LocationProvider,
2033        $log: $LogProvider,
2034        $parse: $ParseProvider,
2035        $rootScope: $RootScopeProvider,
2036        $q: $QProvider,
2037        $sce: $SceProvider,
2038        $sceDelegate: $SceDelegateProvider,
2039        $sniffer: $SnifferProvider,
2040        $templateCache: $TemplateCacheProvider,
2041        $timeout: $TimeoutProvider,
2042        $window: $WindowProvider,
2043        $$rAF: $$RAFProvider,
2044        $$asyncCallback : $$AsyncCallbackProvider
2045      });
2046    }
2047  ]);
2048}
2049
2050/* global
2051
2052  -JQLitePrototype,
2053  -addEventListenerFn,
2054  -removeEventListenerFn,
2055  -BOOLEAN_ATTR
2056*/
2057
2058//////////////////////////////////
2059//JQLite
2060//////////////////////////////////
2061
2062/**
2063 * @ngdoc function
2064 * @name angular.element
2065 * @module ng
2066 * @function
2067 *
2068 * @description
2069 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2070 *
2071 * If jQuery is available, `angular.element` is an alias for the
2072 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2073 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2074 *
2075 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2076 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2077 * commonly needed functionality with the goal of having a very small footprint.</div>
2078 *
2079 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2080 *
2081 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2082 * jqLite; they are never raw DOM references.</div>
2083 *
2084 * ## Angular's jqLite
2085 * jqLite provides only the following jQuery methods:
2086 *
2087 * - [`addClass()`](http://api.jquery.com/addClass/)
2088 * - [`after()`](http://api.jquery.com/after/)
2089 * - [`append()`](http://api.jquery.com/append/)
2090 * - [`attr()`](http://api.jquery.com/attr/)
2091 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2092 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2093 * - [`clone()`](http://api.jquery.com/clone/)
2094 * - [`contents()`](http://api.jquery.com/contents/)
2095 * - [`css()`](http://api.jquery.com/css/)
2096 * - [`data()`](http://api.jquery.com/data/)
2097 * - [`empty()`](http://api.jquery.com/empty/)
2098 * - [`eq()`](http://api.jquery.com/eq/)
2099 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2100 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2101 * - [`html()`](http://api.jquery.com/html/)
2102 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2103 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2104 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2105 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2106 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2107 * - [`prepend()`](http://api.jquery.com/prepend/)
2108 * - [`prop()`](http://api.jquery.com/prop/)
2109 * - [`ready()`](http://api.jquery.com/ready/)
2110 * - [`remove()`](http://api.jquery.com/remove/)
2111 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2112 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2113 * - [`removeData()`](http://api.jquery.com/removeData/)
2114 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2115 * - [`text()`](http://api.jquery.com/text/)
2116 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2117 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2118 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2119 * - [`val()`](http://api.jquery.com/val/)
2120 * - [`wrap()`](http://api.jquery.com/wrap/)
2121 *
2122 * ## jQuery/jqLite Extras
2123 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2124 *
2125 * ### Events
2126 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2126pis and fires this event
2127 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2128 *    element before it is removed.
2129 *
2130 * ### Methods
2131 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2132 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2133 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2134 *   `'ngModel'`).
2135 * - `injector()` - retrieves the injector of the current element or its parent.
2136 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2137 *   element or its parent.
2138 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2139 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2140 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2141 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2142 *   parent element is reached.
2143 *
2144 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2145 * @returns {Object} jQuery object.
2146 */
2147
2148var jqCache = JQLite.cache = {},
2149    jqName = JQLite.expando = 'ng-' + new Date().getTime(),
2150    jqId = 1,
2151    addEventListenerFn = (window.document.addEventListener
2152      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
2153      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
2154    removeEventListenerFn = (window.document.removeEventListener
2155      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
2156      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
2157
2158/*
2159 * !!! This is an undocumented "private" function !!!
2160 */
2161var jqData = JQLite._data = function(node) {
2162  //jQuery always returns an object on cache miss
2163  return this.cache[node[this.expando]] || {};
2164};
2165
2166function jqNextId() { return ++jqId; }
2167
2168
2169var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2170var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2171var jqLiteMinErr = minErr('jqLite');
2172
2173/**
2174 * Converts snake_case to camelCase.
2175 * Also there is special case for Moz prefix starting with upper case letter.
2176 * @param name Name to normalize
2177 */
2178function camelCase(name) {
2179  return name.
2180    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2181      return offset ? letter.toUpperCase() : letter;
2182    }).
2183    replace(MOZ_HACK_REGEXP, 'Moz$1');
2184}
2185
2186/////////////////////////////////////////////
2187// jQuery mutation patch
2188//
2189// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2190// $destroy event on all DOM nodes being removed.
2191//
2192/////////////////////////////////////////////
2193
2194function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2195  var originalJqFn = jQuery.fn[name];
2196  originalJqFn = originalJqFn.$original || originalJqFn;
2197  removePatch.$original = originalJqFn;
2198  jQuery.fn[name] = removePatch;
2199
2200  function removePatch(param) {
2201    // jshint -W040
2202    var list = filterElems && param ? [this.filter(param)] : [this],
2203        fireEvent = dispatchThis,
2204        set, setIndex, setLength,
2205        element, childIndex, childLength, children;
2206
2207    if (!getterIfNoArguments || param != null) {
2208      while(list.length) {
2209        set = list.shift();
2210        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2211          element = jqLite(set[setIndex]);
2212          if (fireEvent) {
2213            element.triggerHandler('$destroy');
2214          } else {
2215            fireEvent = !fireEvent;
2216          }
2217          for(childIndex = 0, childLength = (children = element.children()).length;
2218              childIndex < childLength;
2219              childIndex++) {
2220            list.push(jQuery(children[childIndex]));
2221          }
2222        }
2223      }
2224    }
2225    return originalJqFn.apply(this, arguments);
2226  }
2227}
2228
2229var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2230var HTML_REGEXP = /<|&#?\w+;/;
2231var TAG_NAME_REGEXP = /<([\w:]+)/;
2232var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2233
2234var wrapMap = {
2235  'option': [1, '<select multiple="multiple">', '</select>'],
2236
2237  'thead': [1, '<table>', '</table>'],
2238  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2239  'tr': [2, '<table><tbody>', '</tbody></table>'],
2240  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2241  '_default': [0, "", ""]
2242};
2243
2244wrapMap.optgroup = wrapMap.option;
2245wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2246wrapMap.th = wrapMap.td;
2247
2248function jqLiteIsTextNode(html) {
2249  return !HTML_REGEXP.test(html);
2250}
2251
2252function jqLiteBuildFragment(html, context) {
2253  var elem, tmp, tag, wrap,
2254      fragment = context.createDocumentFragment(),
2255      nodes = [], i, j, jj;
2256
2257  if (jqLiteIsTextNode(html)) {
2258    // Convert non-html into a text node
2259    nodes.push(context.createTextNode(html));
2260  } else {
2261    tmp = fragment.appendChild(context.createElement('div'));
2262    // Convert html into DOM nodes
2263    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2264    wrap = wrapMap[tag] || wrapMap._default;
2265    tmp.innerHTML = '<div>&#160;</div>' +
2266      wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2267    tmp.removeChild(tmp.firstChild);
2268
2269    // Descend through wrappers to the right content
2270    i = wrap[0];
2271    while (i--) {
2272      tmp = tmp.lastChild;
2273    }
2274
2275    for (j=0, jj=tmp.childNodes.length; j<jj; ++j) nodes.push(tmp.childNodes[j]);
2276
2277    tmp = fragment.firstChild;
2278    tmp.textContent = "";
2279  }
2280
2281  // Remove wrapper from fragment
2282  fragment.textContent = "";
2283  fragment.innerHTML = ""; // Clear inner HTML
2284  return nodes;
2285}
2286
2287function jqLiteParseHTML(html, context) {
2288  context = context || document;
2289  var parsed;
2290
2291  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2292    return [context.createElement(parsed[1])];
2293  }
2294
2295  return jqLiteBuildFragment(html, context);
2296}
2297
2298/////////////////////////////////////////////
2299function JQLite(element) {
2300  if (element instanceof JQLite) {
2301    return element;
2302  }
2303  if (isString(element)) {
2304    element = trim(element);
2305  }
2306  if (!(this instanceof JQLite)) {
2307    if (isString(element) && element.charAt(0) != '<') {
2308      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2309    }
2310    return new JQLite(element);
2311  }
2312
2313  if (isString(element)) {
2314    jqLiteAddNodes(this, jqLiteParseHTML(element));
2315    var fragment = jqLite(document.createDocumentFragment());
2316    fragment.append(this);
2317  } else {
2318    jqLiteAddNodes(this, element);
2319  }
2320}
2321
2322function jqLiteClone(element) {
2323  return element.cloneNode(true);
2324}
2325
2326function jqLiteDealoc(element){
2327  jqLiteRemoveData(element);
2328  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
2329    jqLiteDealoc(children[i]);
2330  }
2331}
2332
2333function jqLiteOff(element, type, fn, unsupported) {
2334  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2335
2336  var events = jqLiteExpandoStore(element, 'events'),
2337      handle = jqLiteExpandoStore(element, 'handle');
2338
2339  if (!handle) return; //no listeners registered
2340
2341  if (isUndefined(type)) {
2342    forEach(events, function(eventHandler, type) {
2343      removeEventListenerFn(element, type, eventHandler);
2344      delete events[type];
2345    });
2346  } else {
2347    forEach(type.split(' '), function(type) {
2348      if (isUndefined(fn)) {
2349        removeEventListenerFn(element, type, events[type]);
2350        delete events[type];
2351      } else {
2352        arrayRemove(events[type] || [], fn);
2353      }
2354    });
2355  }
2356}
2357
2358function jqLiteRemoveData(element, name) {
2359  var expandoId = element[jqName],
2360      expandoStore = jqCache[expandoId];
2361
2362  if (expandoStore) {
2363    if (name) {
2364      delete jqCache[expandoId].data[name];
2365      return;
2366    }
2367
2368    if (expandoStore.handle) {
2369      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2370      jqLiteOff(element);
2371    }
2372    delete jqCache[expandoId];
2373    element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
2374  }
2375}
2376
2377function jqLiteExpandoStore(element, key, value) {
2378  var expandoId = element[jqName],
2379      expandoStore = jqCache[expandoId || -1];
2380
2381  if (isDefined(value)) {
2382    if (!expandoStore) {
2383      element[jqName] = expandoId = jqNextId();
2384      expandoStore = jqCache[expandoId] = {};
2385    }
2386    expandoStore[key] = value;
2387  } else {
2388    return expandoStore && expandoStore[key];
2389  }
2390}
2391
2392function jqLiteData(element, key, value) {
2393  var data = jqLiteExpandoStore(element, 'data'),
2394      isSetter = isDefined(value),
2395      keyDefined = !isSetter && isDefined(key),
2396      isSimpleGetter = keyDefined && !isObject(key);
2397
2398  if (!data && !isSimpleGetter) {
2399    jqLiteExpandoStore(element, 'data', data = {});
2400  }
2401
2402  if (isSetter) {
2403    data[key] = value;
2404  } else {
2405    if (keyDefined) {
2406      if (isSimpleGetter) {
2407        // don't create data in this case.
2408        return data && data[key];
2409      } else {
2410        extend(data, key);
2411      }
2412    } else {
2413      return data;
2414    }
2415  }
2416}
2417
2418function jqLiteHasClass(element, selector) {
2419  if (!element.getAttribute) return false;
2420  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2421      indexOf( " " + selector + " " ) > -1);
2422}
2423
2424function jqLiteRemoveClass(element, cssClasses) {
2425  if (cssClasses && element.setAttribute) {
2426    forEach(cssClasses.split(' '), function(cssClass) {
2427      element.setAttribute('class', trim(
2428          (" " + (element.getAttribute('class') || '') + " ")
2429          .replace(/[\n\t]/g, " ")
2430          .replace(" " + trim(cssClass) + " ", " "))
2431      );
2432    });
2433  }
2434}
2435
2436function jqLiteAddClass(element, cssClasses) {
2437  if (cssClasses && element.setAttribute) {
2438    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2439                            .replace(/[\n\t]/g, " ");
2440
2441    forEach(cssClasses.split(' '), function(cssClass) {
2442      cssClass = trim(cssClass);
2443      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2444        existingClasses += cssClass + ' ';
2445      }
2446    });
2447
2448    element.setAttribute('class', trim(existingClasses));
2449  }
2450}
2451
2452function jqLiteAddNodes(root, elements) {
2453  if (elements) {
2454    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2455      ? elements
2456      : [ elements ];
2457    for(var i=0; i < elements.length; i++) {
2458      root.push(elements[i]);
2459    }
2460  }
2461}
2462
2463function jqLiteController(element, name) {
2464  return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2465}
2466
2467function jqLiteInheritedData(element, name, value) {
2468  element = jqLite(element);
2469
2470  // if element is the document object work with the html element instead
2471  // this makes $(document).scope() possible
2472  if(element[0].nodeType == 9) {
2473    element = element.find('html');
2474  }
2475  var names = isArray(name) ? name : [name];
2476
2477  while (element.length) {
2478    var node = element[0];
2479    for (var i = 0, ii = names.length; i < ii; i++) {
2480      if ((value = element.data(names[i])) !== undefined) return value;
2481    }
2482
2483    // If dealing with a document fragment node with a host element, and no parent, use the host
2484    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2485    // to lookup parent controllers.
2486    element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
2487  }
2488}
2489
2490function jqLiteEmpty(element) {
2491  for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2492    jqLiteDealoc(childNodes[i]);
2493  }
2494  while (element.firstChild) {
2495    element.removeChild(element.firstChild);
2496  }
2497}
2498
2499//////////////////////////////////////////
2500// Functions which are declared directly.
2501//////////////////////////////////////////
2502var JQLitePrototype = JQLite.prototype = {
2503  ready: function(fn) {
2504    var fired = false;
2505
2506    function trigger() {
2507      if (fired) return;
2508      fired = true;
2509      fn();
2510    }
2511
2512    // check if document already is loaded
2513    if (document.readyState === 'complete'){
2514      setTimeout(trigger);
2515    } else {
2516      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2517      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2518      // jshint -W064
2519      JQLite(window).on('load', trigger); // fallback to window.onload for others
2520      // jshint +W064
2521    }
2522  },
2523  toString: function() {
2524    var value = [];
2525    forEach(this, function(e){ value.push('' + e);});
2526    return '[' + value.join(', ') + ']';
2527  },
2528
2529  eq: function(index) {
2530      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2531  },
2532
2533  length: 0,
2534  push: push,
2535  sort: [].sort,
2536  splice: [].splice
2537};
2538
2539//////////////////////////////////////////
2540// Functions iterating getter/setters.
2541// these functions return self on setter and
2542// value on get.
2543//////////////////////////////////////////
2544var BOOLEAN_ATTR = {};
2545forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2546  BOOLEAN_ATTR[lowercase(value)] = value;
2547});
2548var BOOLEAN_ELEMENTS = {};
2549forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2550  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2551});
2552
2553function getBooleanAttrName(element, name) {
2554  // check dom last since we will most likely fail on name
2555  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2556
2557  // booleanAttr is here twice to minimize DOM access
2558  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2559}
2560
2561forEach({
2562  data: jqLiteData,
2563  inheritedData: jqLiteInheritedData,
2564
2565  scope: function(element) {
2566    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2567    return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2568  },
2569
2570  isolateScope: function(element) {
2571    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2572    return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
2573  },
2574
2575  controller: jqLiteController,
2576
2577  injector: function(element) {
2578    return jqLiteInheritedData(element, '$injector');
2579  },
2580
2581  removeAttr: function(element,name) {
2582    element.removeAttribute(name);
2583  },
2584
2585  hasClass: jqLiteHasClass,
2586
2587  css: function(element, name, value) {
2588    name = camelCase(name);
2589
2590    if (isDefined(value)) {
2591      element.style[name] = value;
2592    } else {
2593      var val;
2594
2595      if (msie <= 8) {
2596        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2597        val = element.currentStyle && element.currentStyle[name];
2598        if (val === '') val = 'auto';
2599      }
2600
2601      val = val || element.style[name];
2602
2603      if (msie <= 8) {
2604        // jquery weirdness :-/
2605        val = (val === '') ? undefined : val;
2606      }
2607
2608      return  val;
2609    }
2610  },
2611
2612  attr: function(element, name, value){
2613    var lowercasedName = lowercase(name);
2614    if (BOOLEAN_ATTR[lowercasedName]) {
2615      if (isDefined(value)) {
2616        if (!!value) {
2617          element[name] = true;
2618          element.setAttribute(name, lowercasedName);
2619        } else {
2620          element[name] = false;
2621          element.removeAttribute(lowercasedName);
2622        }
2623      } else {
2624        return (element[name] ||
2625                 (element.attributes.getNamedItem(name)|| noop).specified)
2626               ? lowercasedName
2627               : undefined;
2628      }
2629    } else if (isDefined(value)) {
2630      element.setAttribute(name, value);
2631    } else if (element.getAttribute) {
2632      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2633      // some elements (e.g. Document) don't have get attribute, so return undefined
2634      var ret = element.getAttribute(name, 2);
2635      // normalize non-existing attributes to undefined (as jQuery)
2636      return ret === null ? undefined : ret;
2637    }
2638  },
2639
2640  prop: function(element, name, value) {
2641    if (isDefined(value)) {
2642      element[name] = value;
2643    } else {
2644      return element[name];
2645    }
2646  },
2647
2648  text: (function() {
2649    var NODE_TYPE_TEXT_PROPERTY = [];
2650    if (msie < 9) {
2651      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2652      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2653    } else {
2654      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2655      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2656    }
2657    getText.$dv = '';
2658    return getText;
2659
2660    function getText(element, value) {
2661      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2662      if (isUndefined(value)) {
2663        return textProp ? element[textProp] : '';
2664      }
2665      element[textProp] = value;
2666    }
2667  })(),
2668
2669  val: function(element, value) {
2670    if (isUndefined(value)) {
2671      if (nodeName_(element) === 'SELECT' && element.multiple) {
2672        var result = [];
2673        forEach(element.options, function (option) {
2674          if (option.selected) {
2675            result.push(option.value || option.text);
2676          }
2677        });
2678        return result.length === 0 ? null : result;
2679      }
2680      return element.value;
2681    }
2682    element.value = value;
2683  },
2684
2685  html: function(element, value) {
2686    if (isUndefined(value)) {
2687      return element.innerHTML;
2688    }
2689    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2690      jqLiteDealoc(childNodes[i]);
2691    }
2692    element.innerHTML = value;
2693  },
2694
2695  empty: jqLiteEmpty
2696}, function(fn, name){
2697  /**
2698   * Properties: writes return selection, reads return first value
2699   */
2700  JQLite.prototype[name] = function(arg1, arg2) {
2701    var i, key;
2702
2703    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2704    // in a way that survives minification.
2705    // jqLiteEmpty takes no arguments but is a setter.
2706    if (fn !== jqLiteEmpty &&
2707        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2708      if (isObject(arg1)) {
2709
2710        // we are a write, but the object properties are the key/values
2711        for (i = 0; i < this.length; i++) {
2712          if (fn === jqLiteData) {
2713            // data() takes the whole object in jQuery
2714            fn(this[i], arg1);
2715          } else {
2716            for (key in arg1) {
2717              fn(this[i], key, arg1[key]);
2718            }
2719          }
2720        }
2721        // return self for chaining
2722        return this;
2723      } else {
2724        // we are a read, so read the first child.
2725        var value = fn.$dv;
2726        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2727        var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
2728        for (var j = 0; j < jj; j++) {
2729          var nodeValue = fn(this[j], arg1, arg2);
2730          value = value ? value + nodeValue : nodeValue;
2731        }
2732        return value;
2733      }
2734    } else {
2735      // we are a write, so apply to all children
2736      for (i = 0; i < this.length; i++) {
2737        fn(this[i], arg1, arg2);
2738      }
2739      // return self for chaining
2740      return this;
2741    }
2742  };
2743});
2744
2745function createEventHandler(element, events) {
2746  var eventHandler = function (event, type) {
2747    if (!event.preventDefault) {
2748      event.preventDefault = function() {
2749        event.returnValue = false; //ie
2750      };
2751    }
2752
2753    if (!event.stopPropagation) {
2754      event.stopPropagation = function() {
2755        event.cancelBubble = true; //ie
2756      };
2757    }
2758
2759    if (!event.target) {
2760      event.target = event.srcElement || document;
2761    }
2762
2763    if (isUndefined(event.defaultPrevented)) {
2764      var prevent = event.preventDefault;
2765      event.preventDefault = function() {
2766        event.defaultPrevented = true;
2767        prevent.call(event);
2768      };
2769      event.defaultPrevented = false;
2770    }
2771
2772    event.isDefaultPrevented = function() {
2773      return event.defaultPrevented || event.returnValue === false;
2774    };
2775
2776    // Copy event handlers in case event handlers array is modified during execution.
2777    var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2778
2779    forEach(eventHandlersCopy, function(fn) {
2780      fn.call(element, event);
2781    });
2782
2783    // Remove monkey-patched methods (IE),
2784    // as they would cause memory leaks in IE8.
2785    if (msie <= 8) {
2786      // IE7/8 does not allow to delete property on native object
2787      event.preventDefault = null;
2788      event.stopPropagation = null;
2789      event.isDefaultPrevented = null;
2790    } else {
2791      // It shouldn't affect normal browsers (native methods are defined on prototype).
2792      delete event.preventDefault;
2793      delete event.stopPropagation;
2794      delete event.isDefaultPrevented;
2795    }
2796  };
2797  eventHandler.elem = element;
2798  return eventHandler;
2799}
2800
2801//////////////////////////////////////////
2802// Functions iterating traversal.
2803// These functions chain results into a single
2804// selector.
2805//////////////////////////////////////////
2806forEach({
2807  removeData: jqLiteRemoveData,
2808
2809  dealoc: jqLiteDealoc,
2810
2811  on: function onFn(element, type, fn, unsupported){
2812    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2813
2814    var events = jqLiteExpandoStore(element, 'events'),
2815        handle = jqLiteExpandoStore(element, 'handle');
2816
2817    if (!events) jqLiteExpandoStore(element, 'events', events = {});
2818    if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2819
2820    forEach(type.split(' '), function(type){
2821      var eventFns = events[type];
2822
2823      if (!eventFns) {
2824        if (type == 'mouseenter' || type == 'mouseleave') {
2825          var contains = document.body.contains || document.body.compareDocumentPosition ?
2826          function( a, b ) {
2827            // jshint bitwise: false
2828            var adown = a.nodeType === 9 ? a.documentElement : a,
2829            bup = b && b.parentNode;
2830            return a === bup || !!( bup && bup.nodeType === 1 && (
2831              adown.contains ?
2832              adown.contains( bup ) :
2833              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2834              ));
2835            } :
2836            function( a, b ) {
2837              if ( b ) {
2838                while ( (b = b.parentNode) ) {
2839                  if ( b === a ) {
2840                    return true;
2841                  }
2842                }
2843              }
2844              return false;
2845            };
2846
2847          events[type] = [];
2848
2849          // Refer to jQuery's implementation of mouseenter & mouseleave
2850          // Read about mouseenter and mouseleave:
2851          // http://www.quirksmode.org/js/events_mouse.html#link8
2852          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2853
2854          onFn(element, eventmap[type], function(event) {
2855            var target = this, related = event.relatedTarget;
2856            // For mousenter/leave call the handler if related is outside the target.
2857            // NB: No relatedTarget if the mouse left/entered the browser window
2858            if ( !related || (related !== target && !contains(target, related)) ){
2859              handle(event, type);
2860            }
2861          });
2862
2863        } else {
2864          addEventListenerFn(element, type, handle);
2865          events[type] = [];
2866        }
2867        eventFns = events[type];
2868      }
2869      eventFns.push(fn);
2870    });
2871  },
2872
2873  off: jqLiteOff,
2874
2875  one: function(element, type, fn) {
2876    element = jqLite(element);
2877
2878    //add the listener twice so that when it is called
2879    //you can remove the original function and still be
2880    //able to call element.off(ev, fn) normally
2881    element.on(type, function onFn() {
2882      element.off(type, fn);
2883      element.off(type, onFn);
2884    });
2885    element.on(type, fn);
2886  },
2887
2888  replaceWith: function(element, replaceNode) {
2889    var index, parent = element.parentNode;
2890    jqLiteDealoc(element);
2891    forEach(new JQLite(replaceNode), function(node){
2892      if (index) {
2893        parent.insertBefore(node, index.nextSibling);
2894      } else {
2895        parent.replaceChild(node, element);
2896      }
2897      index = node;
2898    });
2899  },
2900
2901  children: function(element) {
2902    var children = [];
2903    forEach(element.childNodes, function(element){
2904      if (element.nodeType === 1)
2905        children.push(element);
2906    });
2907    return children;
2908  },
2909
2910  contents: function(element) {
2911    return element.contentDocument || element.childNodes || [];
2912  },
2913
2914  append: function(element, node) {
2915    forEach(new JQLite(node), function(child){
2916      if (element.nodeType === 1 || element.nodeType === 11) {
2917        element.appendChild(child);
2918      }
2919    });
2920  },
2921
2922  prepend: function(element, node) {
2923    if (element.nodeType === 1) {
2924      var index = element.firstChild;
2925      forEach(new JQLite(node), function(child){
2926        element.insertBefore(child, index);
2927      });
2928    }
2929  },
2930
2931  wrap: function(element, wrapNode) {
2932    wrapNode = jqLite(wrapNode)[0];
2933    var parent = element.parentNode;
2934    if (parent) {
2935      parent.replaceChild(wrapNode, element);
2936    }
2937    wrapNode.appendChild(element);
2938  },
2939
2940  remove: function(element) {
2941    jqLiteDealoc(element);
2942    var parent = element.parentNode;
2943    if (parent) parent.removeChild(element);
2944  },
2945
2946  after: function(element, newElement) {
2947    var index = element, parent = element.parentNode;
2948    forEach(new JQLite(newElement), function(node){
2949      parent.insertBefore(node, index.nextSibling);
2950      index = node;
2951    });
2952  },
2953
2954  addClass: jqLiteAddClass,
2955  removeClass: jqLiteRemoveClass,
2956
2957  toggleClass: function(element, selector, condition) {
2958    if (selector) {
2959      forEach(selector.split(' '), function(className){
2960        var classCondition = condition;
2961        if (isUndefined(classCondition)) {
2962          classCondition = !jqLiteHasClass(element, className);
2963        }
2964        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
2965      });
2966    }
2967  },
2968
2969  parent: function(element) {
2970    var parent = element.parentNode;
2971    return parent && parent.nodeType !== 11 ? parent : null;
2972  },
2973
2974  next: function(element) {
2975    if (element.nextElementSibling) {
2976      return element.nextElementSibling;
2977    }
2978
2979    // IE8 doesn't have nextElementSibling
2980    var elm = element.nextSibling;
2981    while (elm != null && elm.nodeType !== 1) {
2982      elm = elm.nextSibling;
2983    }
2984    return elm;
2985  },
2986
2987  find: function(element, selector) {
2988    if (element.getElementsByTagName) {
2989      return element.getElementsByTagName(selector);
2990    } else {
2991      return [];
2992    }
2993  },
2994
2995  clone: jqLiteClone,
2996
2997  triggerHandler: function(element, eventName, eventData) {
2998    var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
2999
3000    eventData = eventData || [];
3001
3002    var event = [{
3003      preventDefault: noop,
3004      stopPropagation: noop
3005    }];
3006
3007    forEach(eventFns, function(fn) {
3008      fn.apply(element, event.concat(eventData));
3009    });
3010  }
3011}, function(fn, name){
3012  /**
3013   * chaining functions
3014   */
3015  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3016    var value;
3017    for(var i=0; i < this.length; i++) {
3018      if (isUndefined(value)) {
3019        value = fn(this[i], arg1, arg2, arg3);
3020        if (isDefined(value)) {
3021          // any function which returns a value needs to be wrapped
3022          value = jqLite(value);
3023        }
3024      } else {
3025        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3026      }
3027    }
3028    return isDefined(value) ? value : this;
3029  };
3030
3031  // bind legacy bind/unbind to on/off
3032  JQLite.prototype.bind = JQLite.prototype.on;
3033  JQLite.prototype.unbind = JQLite.prototype.off;
3034});
3035
3036/**
3037 * Computes a hash of an 'obj'.
3038 * Hash of a:
3039 *  string is string
3040 *  number is number as string
3041 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3042 *         that is also assigned to the $$hashKey property of the object.
3043 *
3044 * @param obj
3045 * @returns {string} hash string such that the same input will have the same hash string.
3046 *         The resulting string key is in 'type:hashKey' format.
3047 */
3048function hashKey(obj) {
3049  var objType = typeof obj,
3050      key;
3051
3052  if (objType == 'object' && obj !== null) {
3053    if (typeof (key = obj.$$hashKey) == 'function') {
3054      // must invoke on object to keep the right this
3055      key = obj.$$hashKey();
3056    } else if (key === undefined) {
3057      key = obj.$$hashKey = nextUid();
3058    }
3059  } else {
3060    key = obj;
3061  }
3062
3063  return objType + ':' + key;
3064}
3065
3066/**
3067 * HashMap which can use objects as keys
3068 */
3069function HashMap(array){
3070  forEach(array, this.put, this);
3071}
3072HashMap.prototype = {
3073  /**
3074   * Store key value pair
3075   * @param key key to store can be any type
3076   * @param value value to store can be any type
3077   */
3078  put: function(key, value) {
3079    this[hashKey(key)] = value;
3080  },
3081
3082  /**
3083   * @param key
3084   * @returns {Object} the value for the key
3085   */
3086  get: function(key) {
3087    return this[hashKey(key)];
3088  },
3089
3090  /**
3091   * Remove the key/value pair
3092   * @param key
3093   */
3094  remove: function(key) {
3095    var value = this[key = hashKey(key)];
3096    delete this[key];
3097    return value;
3098  }
3099};
3100
3101/**
3102 * @ngdoc function
3103 * @module ng
3104 * @name angular.injector
3105 * @function
3106 *
3107 * @description
3108 * Creates an injector function that can be used for retrieving services as well as for
3109 * dependency injection (see {@link guide/di dependency injection}).
3110 *
3111
3112 * @param {Array.<string|Function>}
3112 modules A list of module functions or their aliases. See
3113 *        {@link angular.module}. The `ng` module must be explicitly added.
3114 * @returns {function()} Injector function. See {@link auto.$injector $injector}.
3115 *
3116 * @example
3117 * Typical usage
3118 * ```js
3119 *   // create an injector
3120 *   var $injector = angular.injector(['ng']);
3121 *
3122 *   // use the injector to kick off your application
3123 *   // use the type inference to auto inject arguments, or use implicit injection
3124 *   $injector.invoke(function($rootScope, $compile, $document){
3125 *     $compile($document)($rootScope);
3126 *     $rootScope.$digest();
3127 *   });
3128 * ```
3129 *
3130 * Sometimes you want to get access to the injector of a currently running Angular app
3131 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3132 * application has been bootstrapped. You can do this using extra `injector()` added
3133 * to JQuery/jqLite elements. See {@link angular.element}.
3134 *
3135 * *This is fairly rare but could be the case if a third party library is injecting the
3136 * markup.*
3137 *
3138 * In the following example a new block of HTML containing a `ng-controller`
3139 * directive is added to the end of the document body by JQuery. We then compile and link
3140 * it into the current AngularJS scope.
3141 *
3142 * ```js
3143 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3144 * $(document.body).append($div);
3145 *
3146 * angular.element(document).injector().invoke(function($compile) {
3147 *   var scope = angular.element($div).scope();
3148 *   $compile($div)(scope);
3149 * });
3150 * ```
3151 */
3152
3153
3154/**
3155 * @ngdoc module
3156 * @name auto
3157 * @description
3158 *
3159 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3160 */
3161
3162var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3163var FN_ARG_SPLIT = /,/;
3164var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3165var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3166var $injectorMinErr = minErr('$injector');
3167function annotate(fn) {
3168  var $inject,
3169      fnText,
3170      argDecl,
3171      last;
3172
3173  if (typeof fn == 'function') {
3174    if (!($inject = fn.$inject)) {
3175      $inject = [];
3176      if (fn.length) {
3177        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3178        argDecl = fnText.match(FN_ARGS);
3179        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
3180          arg.replace(FN_ARG, function(all, underscore, name){
3181            $inject.push(name);
3182          });
3183        });
3184      }
3185      fn.$inject = $inject;
3186    }
3187  } else if (isArray(fn)) {
3188    last = fn.length - 1;
3189    assertArgFn(fn[last], 'fn');
3190    $inject = fn.slice(0, last);
3191  } else {
3192    assertArgFn(fn, 'fn', true);
3193  }
3194  return $inject;
3195}
3196
3197///////////////////////////////////////
3198
3199/**
3200 * @ngdoc service
3201 * @name $injector
3202 * @function
3203 *
3204 * @description
3205 *
3206 * `$injector` is used to retrieve object instances as defined by
3207 * {@link auto.$provide provider}, instantiate types, invoke methods,
3208 * and load modules.
3209 *
3210 * The following always holds true:
3211 *
3212 * ```js
3213 *   var $injector = angular.injector();
3214 *   expect($injector.get('$injector')).toBe($injector);
3215 *   expect($injector.invoke(function($injector){
3216 *     return $injector;
3217 *   }).toBe($injector);
3218 * ```
3219 *
3220 * # Injection Function Annotation
3221 *
3222 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3223 * following are all valid ways of annotating function with injection arguments and are equivalent.
3224 *
3225 * ```js
3226 *   // inferred (only works if code not minified/obfuscated)
3227 *   $injector.invoke(function(serviceA){});
3228 *
3229 *   // annotated
3230 *   function explicit(serviceA) {};
3231 *   explicit.$inject = ['serviceA'];
3232 *   $injector.invoke(explicit);
3233 *
3234 *   // inline
3235 *   $injector.invoke(['serviceA', function(serviceA){}]);
3236 * ```
3237 *
3238 * ## Inference
3239 *
3240 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3241 * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3242 * minification, and obfuscation tools since these tools change the argument names.
3243 *
3244 * ## `$inject` Annotation
3245 * By adding a `$inject` property onto a function the injection parameters can be specified.
3246 *
3247 * ## Inline
3248 * As an array of injection names, where the last item in the array is the function to call.
3249 */
3250
3251/**
3252 * @ngdoc method
3253 * @name $injector#get
3254 *
3255 * @description
3256 * Return an instance of the service.
3257 *
3258 * @param {string} name The name of the instance to retrieve.
3259 * @return {*} The instance.
3260 */
3261
3262/**
3263 * @ngdoc method
3264 * @name $injector#invoke
3265 *
3266 * @description
3267 * Invoke the method and supply the method arguments from the `$injector`.
3268 *
3269 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3270 *   {@link guide/di $inject Annotation} rules.
3271 * @param {Object=} self The `this` for the invoked method.
3272 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3273 *                         object first, before the `$injector` is consulted.
3274 * @returns {*} the value returned by the invoked `fn` function.
3275 */
3276
3277/**
3278 * @ngdoc method
3279 * @name $injector#has
3280 *
3281 * @description
3282 * Allows the user to query if the particular service exist.
3283 *
3284 * @param {string} Name of the service to query.
3285 * @returns {boolean} returns true if injector has given service.
3286 */
3287
3288/**
3289 * @ngdoc method
3290 * @name $injector#instantiate
3291 * @description
3292 * Create a new instance of JS type. The method takes a constructor function invokes the new
3293 * operator and supplies all of the arguments to the constructor function as specified by the
3294 * constructor annotation.
3295 *
3296 * @param {Function} Type Annotated constructor function.
3297 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3298 * object first, before the `$injector` is consulted.
3299 * @returns {Object} new instance of `Type`.
3300 */
3301
3302/**
3303 * @ngdoc method
3304 * @name $injector#annotate
3305 *
3306 * @description
3307 * Returns an array of service names which the function is requesting for injection. This API is
3308 * used by the injector to determine which services need to be injected into the function when the
3309 * function is invoked. There are three ways in which the function can be annotated with the needed
3310 * dependencies.
3311 *
3312 * # Argument names
3313 *
3314 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3315 * by converting the function into a string using `toString()` method and extracting the argument
3316 * names.
3317 * ```js
3318 *   // Given
3319 *   function MyController($scope, $route) {
3320 *     // ...
3321 *   }
3322 *
3323 *   // Then
3324 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3325 * ```
3326 *
3327 * This method does not work with code minification / obfuscation. For this reason the following
3328 * annotation strategies are supported.
3329 *
3330 * # The `$inject` property
3331 *
3332 * If a function has an `$inject` property and its value is an array of strings, then the strings
3333 * represent names of services to be injected into the function.
3334 * ```js
3335 *   // Given
3336 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3337 *     // ...
3338 *   }
3339 *   // Define function dependencies
3340 *   MyController['$inject'] = ['$scope', '$route'];
3341 *
3342 *   // Then
3343 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3344 * ```
3345 *
3346 * # The array notation
3347 *
3348 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3349 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3350 * a way that survives minification is a better choice:
3351 *
3352 * ```js
3353 *   // We wish to write this (not minification / obfuscation safe)
3354 *   injector.invoke(function($compile, $rootScope) {
3355 *     // ...
3356 *   });
3357 *
3358 *   // We are forced to write break inlining
3359 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3360 *     // ...
3361 *   };
3362 *   tmpFn.$inject = ['$compile', '$rootScope'];
3363 *   injector.invoke(tmpFn);
3364 *
3365 *   // To better support inline function the inline annotation is supported
3366 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3367 *     // ...
3368 *   }]);
3369 *
3370 *   // Therefore
3371 *   expect(injector.annotate(
3372 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3373 *    ).toEqual(['$compile', '$rootScope']);
3374 * ```
3375 *
3376 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3377 * be retrieved as described above.
3378 *
3379 * @returns {Array.<string>} The names of the services which the function requires.
3380 */
3381
3382
3383
3384
3385/**
3386 * @ngdoc object
3387 * @name $provide
3388 *
3389 * @description
3390 *
3391 * The {@link auto.$provide $provide} service has a number of methods for registering components
3392 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3393 * {@link angular.Module}.
3394 *
3395 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3396 * factories** are functions which, in turn, are created by a **service provider**.
3397 * The **service providers** are constructor functions. When instantiated they must contain a
3398 * property called `$get`, which holds the **service factory** function.
3399 *
3400 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3401 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3402 * function to get the instance of the **service**.
3403 *
3404 * Often services have no configuration options and there is no need to add methods to the service
3405 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3406 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3407 * services without specifying a provider.
3408 *
3409 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3410 *     {@link auto.$injector $injector}
3411 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3412 *     providers and services.
3413 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3414 *     services, not providers.
3415 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3416 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3417 *     given factory function.
3418 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3419 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3420 *      a new object using the given constructor function.
3421 *
3422 * See the individual methods for more information and examples.
3423 */
3424
3425/**
3426 * @ngdoc method
3427 * @name $provide#provider
3428 * @description
3429 *
3430 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3431 * are constructor functions, whose instances are responsible for "providing" a factory for a
3432 * service.
3433 *
3434 * Service provider names start with the name of the service they provide followed by `Provider`.
3435 * For example, the {@link ng.$log $log} service has a provider called
3436 * {@link ng.$logProvider $logProvider}.
3437 *
3438 * Service provider objects can have additional methods which allow configuration of the provider
3439 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3440 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3441 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3442 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3443 * console or not.
3444 *
3445 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3446                        'Provider'` key.
3447 * @param {(Object|function())} provider If the provider is:
3448 *
3449 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3450 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3451 *   - `Constructor`: a new instance of the provider will be created using
3452 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3453 *
3454 * @returns {Object} registered provider instance
3455
3456 * @example
3457 *
3458 * The following example shows how to create a simple event tracking service and register it using
3459 * {@link auto.$provide#provider $provide.provider()}.
3460 *
3461 * ```js
3462 *  // Define the eventTracker provider
3463 *  function EventTrackerProvider() {
3464 *    var trackingUrl = '/track';
3465 *
3466 *    // A provider method for configuring where the tracked events should been saved
3467 *    this.setTrackingUrl = function(url) {
3468 *      trackingUrl = url;
3469 *    };
3470 *
3471 *    // The service factory function
3472 *    this.$get = ['$http', function($http) {
3473 *      var trackedEvents = {};
3474 *      return {
3475 *        // Call this to track an event
3476 *        event: function(event) {
3477 *          var count = trackedEvents[event] || 0;
3478 *          count += 1;
3479 *          trackedEvents[event] = count;
3480 *          return count;
3481 *        },
3482 *        // Call this to save the tracked events to the trackingUrl
3483 *        save: function() {
3484 *          $http.post(trackingUrl, trackedEvents);
3485 *        }
3486 *      };
3487 *    }];
3488 *  }
3489 *
3490 *  describe('eventTracker', function() {
3491 *    var postSpy;
3492 *
3493 *    beforeEach(module(function($provide) {
3494 *      // Register the eventTracker provider
3495 *      $provide.provider('eventTracker', EventTrackerProvider);
3496 *    }));
3497 *
3498 *    beforeEach(module(function(eventTrackerProvider) {
3499 *      // Configure eventTracker provider
3500 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3501 *    }));
3502 *
3503 *    it('tracks events', inject(function(eventTracker) {
3504 *      expect(eventTracker.event('login')).toEqual(1);
3505 *      expect(eventTracker.event('login')).toEqual(2);
3506 *    }));
3507 *
3508 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3509 *      postSpy = spyOn($http, 'post');
3510 *      eventTracker.event('login');
3511 *      eventTracker.save();
3512 *      expect(postSpy).toHaveBeenCalled();
3513 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3514 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3515 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3516 *    }));
3517 *  });
3518 * ```
3519 */
3520
3521/**
3522 * @ngdoc method
3523 * @name $provide#factory
3524 * @description
3525 *
3526 * Register a **service factory**, which will be called to return the service instance.
3527 * This is short for registering a service where its provider consists of only a `$get` property,
3528 * which is the given service factory function.
3529 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3530 * configure your service in a provider.
3531 *
3532 * @param {string} name The name of the instance.
3533 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3534 *                            for `$provide.provider(name, {$get: $getFn})`.
3535 * @returns {Object} registered provider instance
3536 *
3537 * @example
3538 * Here is an example of registering a service
3539 * ```js
3540 *   $provide.factory('ping', ['$http', function($http) {
3541 *     return function ping() {
3542 *       return $http.send('/ping');
3543 *     };
3544 *   }]);
3545 * ```
3546 * You would then inject and use this service like this:
3547 * ```js
3548 *   someModule.controller('Ctrl', ['ping', function(ping) {
3549 *     ping();
3550 *   }]);
3551 * ```
3552 */
3553
3554
3555/**
3556 * @ngdoc method
3557 * @name $provide#service
3558 * @description
3559 *
3560 * Register a **service constructor**, which will be invoked with `new` to create the service
3561 * instance.
3562 * This is short for registering a service where its provider's `$get` property is the service
3563 * constructor function that will be used to instantiate the service instance.
3564 *
3565 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3566 * as a type/class.
3567 *
3568 * @param {string} name The name of the instance.
3569 * @param {Function} constructor A class (constructor function) that will be instantiated.
3570 * @returns {Object} registered provider instance
3571 *
3572 * @example
3573 * Here is an example of registering a service using
3574 * {@link auto.$provide#service $provide.service(class)}.
3575 * ```js
3576 *   var Ping = function($http) {
3577 *     this.$http = $http;
3578 *   };
3579 *
3580 *   Ping.$inject = ['$http'];
3581 *
3582 *   Ping.prototype.send = function() {
3583 *     return this.$http.get('/ping');
3584 *   };
3585 *   $provide.service('ping', Ping);
3586 * ```
3587 * You would then inject and use this service like this:
3588 * ```js
3589 *   someModule.controller('Ctrl', ['ping', function(ping) {
3590 *     ping.send();
3591 *   }]);
3592 * ```
3593 */
3594
3595
3596/**
3597 * @ngdoc method
3598 * @name $provide#value
3599 * @description
3600 *
3601 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3602 * number, an array, an object or a function.  This is short for registering a service where its
3603 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3604 * service**.
3605 *
3606 * Value services are similar to constant services, except that they cannot be injected into a
3607 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3608 * an Angular
3609 * {@link auto.$provide#decorator decorator}.
3610 *
3611 * @param {string} name The name of the instance.
3612 * @param {*} value The value.
3613 * @returns {Object} registered provider instance
3614 *
3615 * @example
3616 * Here are some examples of creating value services.
3617 * ```js
3618 *   $provide.value('ADMIN_USER', 'admin');
3619 *
3620 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3621 *
3622 *   $provide.value('halfOf', function(value) {
3623 *     return value / 2;
3624 *   });
3625 * ```
3626 */
3627
3628
3629/**
3630 * @ngdoc method
3631 * @name $provide#constant
3632 * @description
3633 *
3634 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3635 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3636 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3637 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3638 *
3639 * @param {string} name The name of the constant.
3640 * @param {*} value The constant value.
3641 * @returns {Object} registered instance
3642 *
3643 * @example
3644 * Here a some examples of creating constants:
3645 * ```js
3646 *   $provide.constant('SHARD_HEIGHT', 306);
3647 *
3648 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3649 *
3650 *   $provide.constant('double', function(value) {
3651 *     return value * 2;
3652 *   });
3653 * ```
3654 */
3655
3656
3657/**
3658 * @ngdoc method
3659 * @name $provide#decorator
3660 * @description
3661 *
3662 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3663 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3664 * service. The object returned by the decorator may be the original service, or a new service
3665 * object which replaces or wraps and delegates to the original service.
3666 *
3667 * @param {string} name The name of the service to decorate.
3668 * @param {function()} decorator This function will be invoked when the service needs to be
3669 *    instantiated and should return the decorated service instance. The function is called using
3670 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3671 *    Local injection arguments:
3672 *
3673 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3674 *      decorated or delegated to.
3675 *
3676 * @example
3677 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3678 * calls to {@link ng.$log#error $log.warn()}.
3679 * ```js
3680 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3681 *     $delegate.warn = $delegate.error;
3682 *     return $delegate;
3683 *   }]);
3684 * ```
3685 */
3686
3687
3688function createInjector(modulesToLoad) {
3689  var INSTANTIATING = {},
3690      providerSuffix = 'Provider',
3691      path = [],
3692      loadedModules = new HashMap(),
3693      providerCache = {
3694        $provide: {
3695            provider: supportObject(provider),
3696            factory: supportObject(factory),
3697            service: supportObject(service),
3698            value: supportObject(value),
3699            constant: supportObject(constant),
3700            decorator: decorator
3701          }
3702      },
3703      providerInjector = (providerCache.$injector =
3704          createInternalInjector(providerCache, function() {
3705            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3706          })),
3707      instanceCache = {},
3708      instanceInjector = (instanceCache.$injector =
3709          createInternalInjector(instanceCache, function(servicename) {
3710            var provider = providerInjector.get(servicename + providerSuffix);
3711            return instanceInjector.invoke(provider.$get, provider);
3712          }));
3713
3714
3715  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
3716
3717  return instanceInjector;
3718
3719  ////////////////////////////////////
3720  // $provider
3721  ////////////////////////////////////
3722
3723  function supportObject(delegate) {
3724    return function(key, value) {
3725      if (isObject(key)) {
3726        forEach(key, reverseParams(delegate));
3727      } else {
3728        return delegate(key, value);
3729      }
3730    };
3731  }
3732
3733  function provider(name, provider_) {
3734    assertNotHasOwnProperty(name, 'service');
3735    if (isFunction(provider_) || isArray(provider_)) {
3736      provider_ = providerInjector.instantiate(provider_);
3737    }
3738    if (!provider_.$get) {
3739      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3740    }
3741    return providerCache[name + providerSuffix] = provider_;
3742  }
3743
3744  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3745
3746  function service(name, constructor) {
3747    return factory(name, ['$injector', function($injector) {
3748      return $injector.instantiate(constructor);
3749    }]);
3750  }
3751
3752  function value(name, val) { return factory(name, valueFn(val)); }
3753
3754  function constant(name, value) {
3755    assertNotHasOwnProperty(name, 'constant');
3756    providerCache[name] = value;
3757    instanceCache[name] = value;
3758  }
3759
3760  function decorator(serviceName, decorFn) {
3761    var origProvider = providerInjector.get(serviceName + providerSuffix),
3762        orig$get = origProvider.$get;
3763
3764    origProvider.$get = function() {
3765      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3766      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3767    };
3768  }
3769
3770  ////////////////////////////////////
3771  // Module Loading
3772  ////////////////////////////////////
3773  function loadModules(modulesToLoad){
3774    var runBlocks = [], moduleFn, invokeQueue, i, ii;
3775    forEach(modulesToLoad, function(module) {
3776      if (loadedModules.get(module)) return;
3777      loadedModules.put(module, true);
3778
3779      try {
3780        if (isString(module)) {
3781          moduleFn = angularModule(module);
3782          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3783
3784          for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3785            var invokeArgs = invokeQueue[i],
3786                provider = providerInjector.get(invokeArgs[0]);
3787
3788            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3789          }
3790        } else if (isFunction(module)) {
3791            runBlocks.push(providerInjector.invoke(module));
3792        } else if (isArray(module)) {
3793            runBlocks.push(providerInjector.invoke(module));
3794        } else {
3795          assertArgFn(module, 'module');
3796        }
3797      } catch (e) {
3798        if (isArray(module)) {
3799          module = module[module.length - 1];
3800        }
3801        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3802          // Safari & FF's stack traces don't contain error.message content
3803          // unlike those of Chrome and IE
3804          // So if stack doesn't contain message, we create a new string that contains both.
3805          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3806          /* jshint -W022 */
3807          e = e.message + '\n' + e.stack;
3808        }
3809        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3810                  module, e.stack || e.message || e);
3811      }
3812    });
3813    return runBlocks;
3814  }
3815
3816  ////////////////////////////////////
3817  // internal Injector
3818  ////////////////////////////////////
3819
3820  function createInternalInjector(cache, factory) {
3821
3822    function getService(serviceName) {
3823      if (cache.hasOwnProperty(serviceName)) {
3824        if (cache[serviceName] === INSTANTIATING) {
3825          throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
3826        }
3827        return cache[serviceName];
3828      } else {
3829        try {
3830          path.unshift(serviceName);
3831          cache[serviceName] = INSTANTIATING;
3832          return cache[serviceName] = factory(serviceName);
3833        } catch (err) {
3834          if (cache[serviceName] === INSTANTIATING) {
3835            delete cache[serviceName];
3836          }
3837          throw err;
3838        } finally {
3839          path.shift();
3840        }
3841      }
3842    }
3843
3844    function invoke(fn, self, locals){
3845      var args = [],
3846          $inject = annotate(fn),
3847          length, i,
3848          key;
3849
3850      for(i = 0, length = $inject.length; i < length; i++) {
3851        key = $inject[i];
3852        if (typeof key !== 'string') {
3853          throw $injectorMinErr('itkn',
3854                  'Incorrect injection token! Expected service name as string, got {0}', key);
3855        }
3856        args.push(
3857          locals && locals.hasOwnProperty(key)
3858          ? locals[key]
3859          : getService(key)
3860        );
3861      }
3862      if (!fn.$inject) {
3863        // this means that we must be an array.
3864        fn = fn[length];
3865      }
3866
3867      // http://jsperf.com/angularjs-invoke-apply-vs-switch
3868      // #5388
3869      return fn.apply(self, args);
3870    }
3871
3872    function instantiate(Type, locals) {
3873      var Constructor = function() {},
3874          instance, returnedValue;
3875
3876      // Check if Type is annotated and use just the given function at n-1 as parameter
3877      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3878      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3879      instance = new Constructor();
3880      returnedValue = invoke(Type, instance, locals);
3881
3882      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3883    }
3884
3885    return {
3886      invoke: invoke,
3887      instantiate: instantiate,
3888      get: getService,
3889      annotate: annotate,
3890      has: function(name) {
3891        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3892      }
3893    };
3894  }
3895}
3896
3897/**
3898 * @ngdoc service
3899 * @name $anchorScroll
3900 * @kind function
3901 * @requires $window
3902 * @requires $location
3903 * @requires $rootScope
3904 *
3905 * @description
3906 * When called, it checks current value of `$location.hash()` and scroll to related element,
3907 * according to rules specified in
3908 * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
3909 *
3910 * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3911 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3912 *
3913 * @example
3914   <example>
3915     <file name="index.html">
3916       <div id="scrollArea" ng-controller="ScrollCtrl">
3917         <a ng-click="gotoBottom()">Go to bottom</a>
3918         <a id="bottom"></a> You're at the bottom!
3919       </div>
3920     </file>
3921     <file name="script.js">
3922       function ScrollCtrl($scope, $location, $anchorScroll) {
3923         $scope.gotoBottom = function (){
3924           // set the location.hash to the id of
3925           // the element you wish to scroll to.
3926           $location.hash('bottom');
3927
3928           // call $anchorScroll()
3929           $anchorScroll();
3930         };
3931       }
3932     </file>
3933     <file name="style.css">
3934       #scrollArea {
3935         height: 350px;
3936         overflow: auto;
3937       }
3938
3939       #bottom {
3940         display: block;
3941         margin-top: 2000px;
3942       }
3943     </file>
3944   </example>
3945 */
3946function $AnchorScrollProvider() {
3947
3948  var autoScrollingEnabled = true;
3949
3950  this.disableAutoScrolling = function() {
3951    autoScrollingEnabled = false;
3952  };
3953
3954  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
3955    var document = $window.document;
3956
3957    // helper function to get first anchor from a NodeList
3958    // can't use filter.filter, as it accepts only instances of Array
3959    // and IE can't convert NodeList to an array using [].slice
3960    // TODO(vojta): use filter if we change it to accept lists as well
3961    function getFirstAnchor(list) {
3962      var result = null;
3963      forEach(list, function(element) {
3964        if (!result && lowercase(element.nodeName) === 'a') result = element;
3965      });
3966      return result;
3967    }
3968
3969    function scroll() {
3970      var hash = $location.hash(), elm;
3971
3972      // empty hash, scroll to the top of the page
3973      if (!hash) $window.scrollTo(0, 0);
3974
3975      // element with given id
3976      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
3977
3978      // first anchor with given name :-D
3979      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
3980
3981      // no element and hash == 'top', scroll to the top of the page
3982      else if (hash === 'top') $window.scrollTo(0, 0);
3983    }
3984
3985    // does not scroll when user clicks on anchor link that is currently on
3986    // (no url change, no $location.hash() change), browser native does scroll
3987    if (autoScrollingEnabled) {
3988      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
3989        function autoScrollWatchAction() {
3990          $rootScope.$evalAsync(scroll);
3991        });
3992    }
3993
3994    return scroll;
3995  }];
3996}
3997
3998var $animateMinErr = minErr('$animate');
3999
4000/**
4001 * @ngdoc provider
4002 * @name $animateProvider
4003 *
4004 * @description
4005 * Default implementation of $animate that doesn't perform any animations, instead just
4006 * synchronously performs DOM
4007 * updates and calls done() callbacks.
4008 *
4009 * In order to enable animations the ngAnimate module has to be loaded.
4010 *
4011 * To see the functional implementation check out src/ngAnimate/animate.js
4012 */
4013var $AnimateProvider = ['$provide', function($provide) {
4014
4015
4016  this.$$selectors = {};
4017
4018
4019  /**
4020   * @ngdoc method
4021   * @name $animateProvider#register
4022   *
4023   * @description
4024   * Registers a new injectable animation factory function. The factory function produces the
4025   * animation object which contains callback functions for each event that is expected to be
4026   * animated.
4027   *
4028   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4029   *   must be called once the element animation is complete. If a function is returned then the
4030   *   animation service will use this function to cancel the animation whenever a cancel event is
4031   *   triggered.
4032   *
4033   *
4034   * ```js
4035   *   return {
4036     *     eventFn : function(element, done) {
4037     *       //code to run the animation
4038     *       //once complete, then run done()
4039     *       return function cancellationFunction() {
4040     *         //code to cancel the animation
4041     *       }
4042     *     }
4043     *   }
4044   * ```
4045   *
4046   * @param {string} name The name of the animation.
4047   * @param {Function} factory The factory function that will be executed to return the animation
4048   *                           object.
4049   */
4050  this.register = function(name, factory) {
4051    var key = name + '-animation';
4052    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4053        "Expecting class selector starting with '.' got '{0}'.", name);
4054    this.$$selectors[name.substr(1)] = key;
4055    $provide.factory(key, factory);
4056  };
4057
4058  /**
4059   * @ngdoc method
4060   * @name $animateProvider#classNameFilter
4061   *
4062   * @description
4063   * Sets and/or returns the CSS class regular expression that is checked when performing
4064   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4065   * therefore enable $animate to attempt to perform an animation on any element.
4066   * When setting the classNameFilter value, animations will only be performed on elements
4067   * that successfully match the filter expression. This in turn can boost performance
4068   * for low-powered devices as well as applications containing a lot of structural operations.
4069   * @param {RegExp=} expression The className expression which will be checked against all animations
4070   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4071   */
4072  this.classNameFilter = function(expression) {
4073    if(arguments.length === 1) {
4074      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4075    }
4076    return this.$$classNameFilter;
4077  };
4078
4079  this.$get = ['$timeout', '$$asyncCallback', function($timeout, $$asyncCallback) {
4080
4081    function async(fn) {
4082      fn && $$asyncCallback(fn);
4083    }
4084
4085    /**
4086     *
4087     * @ngdoc service
4088     * @name $animate
4089     * @description The $animate service provides rudimentary DOM manipulation functions to
4090     * insert, remove and move elements within the DOM, as well as adding and removing classes.
4091     * This service is the core service used by the ngAnimate $animator service which provides
4092     * high-level animation hooks for CSS and JavaScript.
4093     *
4094     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4095     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4096     * manipulation operations.
4097     *
4098     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4099     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4100     * page}.
4101     */
4102    return {
4103
4104      /**
4105       *
4106       * @ngdoc method
4107       * @name $animate#enter
4108       * @function
4109       * @description Inserts the element into the DOM either after the `after` element or within
4110       *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4111       * @param {DOMElement} element the element which will be inserted into the DOM
4112       * @param {DOMElement} parent the parent element which will append the element as
4113       *   a child (if the after element is not present)
4114       * @param {DOMElement} after the sibling element which will append the element
4115       *   after itself
4116       * @param {Function=} done callback function that will be called after the element has been
4117       *   inserted into the DOM
4118       */
4119      enter : function(element, parent, after, done) {
4120        if (after) {
4121          after.after(element);
4122        } else {
4123          if (!parent || !parent[0]) {
4124            parent = after.parent();
4125          }
4126          parent.append(element);
4127        }
4128        async(done);
4129      },
4130
4131      /**
4132       *
4133       * @ngdoc method
4134       * @name $animate#leave
4135       * @function
4136       * @description Removes the element from the DOM. Once complete, the done() callback will be
4137       *   fired (if provided).
4138       * @param {DOMElement} element the element which will be removed from the DOM
4139       * @param {Function=} done callback function that will be called after the element has been
4140       *   removed from the DOM
4141       */
4142      leave : function(element, done) {
4143        element.remove();
4144        async(done);
4145      },
4146
4147      /**
4148       *
4149       * @ngdoc method
4150       * @name $animate#move
4151       * @function
4152       * @description Moves the position of the provided element within the DOM to be placed
4153       * either after the `after` element or inside of the `parent` element. Once complete, the
4154       * done() callback will be fired (if provided).
4155       *
4156       * @param {DOMElement} element the element which will be moved around within the
4157       *   DOM
4158       * @param {DOMElement} parent the parent element where the element will be
4159       *   inserted into (if the after element is not present)
4160       * @param {DOMElement} after the sibling element where the element will be
4161       *   positioned next to
4162       * @param {Function=} done the callback function (if provided) that will be fired after the
4163       *   element has been moved to its new position
4164       */
4165      move : function(element, parent, after, done) {
4166        // Do not remove element before insert. Removing will cause data associated with the
4167        // element to be dropped. Insert will implicitly do the remove.
4168        this.enter(element, parent, after, done);
4169      },
4170
4171      /**
4172       *
4173       * @ngdoc method
4174       * @name $animate#addClass
4175       * @function
4176       * @description Adds the provided className CSS class value to the provided element. Once
4177       * complete, the done() callback will be fired (if provided).
4178       * @param {DOMElement} element the element which will have the className value
4179       *   added to it
4180       * @param {string} className the CSS class which will be added to the element
4181       * @param {Function=} done the callback function (if provided) that will be fired after the
4182       *   className value has been added to the element
4183       */
4184      addClass : function(element, className, done) {
4185        className = isString(className) ?
4186                      className :
4187                      isArray(className) ? className.join(' ') : '';
4188        forEach(element, function (element) {
4189          jqLiteAddClass(element, className);
4190        });
4191        async(done);
4192      },
4193
4194      /**
4195       *
4196       * @ngdoc method
4197       * @name $animate#removeClass
4198       * @function
4199       * @description Removes the provided className CSS class value from the provided element.
4200       * Once complete, the done() callback will be fired (if provided).
4201       * @param {DOMElement} element the element which will have the className value
4202       *   removed from it
4203       * @param {string} className the CSS class which will be removed from the element
4204       * @param {Function=} done the callback function (if provided) that will be fired after the
4205       *   className value has been removed from the element
4206       */
4207      removeClass : function(element, className, done) {
4208        className = isString(className) ?
4209                      className :
4210                      isArray(className) ? className.join(' ') : '';
4211        forEach(element, function (element) {
4212          jqLiteRemoveClass(element, className);
4213        });
4214        async(done);
4215      },
4216
4217      /**
4218       *
4219       * @ngdoc method
4220       * @name $animate#setClass
4221       * @function
4222       * @description Adds and/or removes the given CSS classes to and from the element.
4223       * Once complete, the done() callback will be fired (if provided).
4224       * @param {DOMElement} element the element which will it's CSS classes changed
4225       *   removed from it
4226       * @param {string} add the CSS classes which will be added to the element
4227       * @param {string} remove the CSS class which will be removed from the element
4228       * @param {Function=} done the callback function (if provided) that will be fired after the
4229       *   CSS classes have been set on the element
4230       */
4231      setClass : function(element, add, remove, done) {
4232        forEach(element, function (element) {
4233          jqLiteAddClass(element, add);
4234          jqLiteRemoveClass(element, remove);
4235        });
4236        async(done);
4237      },
4238
4239      enabled : noop
4240    };
4241  }];
4242}];
4243
4244function $$AsyncCallbackProvider(){
4245  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4246    return $$rAF.supported
4247      ? function(fn) { return $$rAF(fn); }
4248      : function(fn) {
4249        return $timeout(fn, 0, false);
4250      };
4251  }];
4252}
4253
4254/**
4255 * ! This is a private undocumented service !
4256 *
4257 * @name $browser
4258 * @requires $log
4259 * @description
4260 * This object has two goals:
4261 *
4262 * - hide all the global state in the browser caused by the window object
4263 * - abstract away all the browser specific features and inconsistencies
4264 *
4265 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4266 * service, which can be used for convenient testing of the application without the interaction with
4267 * the real browser apis.
4268 */
4269/**
4270 * @param {object} window The global window object.
4271 * @param {object} document jQuery wrapped document.
4272 * @param {function()} XHR XMLHttpRequest constructor.
4273 * @param {object} $log console.log or an object with the same interface.
4274 * @param {object} $sniffer $sniffer service
4275 */
4276function Browser(window, document, $log, $sniffer) {
4277  var self = this,
4278      rawDocument = document[0],
4279      location = window.location,
4280      history = window.history,
4281      setTimeout = window.setTimeout,
4282      clearTimeout = window.clearTimeout,
4283      pendingDeferIds = {};
4284
4285  self.isMock = false;
4286
4287  var outstandingRequestCount = 0;
4288  var outstandingRequestCallbacks = [];
4289
4290  // TODO(vojta): remove this temporary api
4291  self.$$completeOutstandingRequest = completeOutstandingRequest;
4292  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4293
4294  /**
4295   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4296   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4297   */
4298  function completeOutstandingRequest(fn) {
4299    try {
4300      fn.apply(null, sliceArgs(arguments, 1));
4301    } finally {
4302      outstandingRequestCount--;
4303      if (outstandingRequestCount === 0) {
4304        while(outstandingRequestCallbacks.length) {
4305          try {
4306            outstandingRequestCallbacks.pop()();
4307          } catch (e) {
4308            $log.error(e);
4309          }
4310        }
4311      }
4312    }
4313  }
4314
4315  /**
4316   * @private
4317   * Note: this method is used only by scenario runner
4318   * TODO(vojta): prefix this method with $$ ?
4319   * @param {function()} callback Function that will be called when no outstanding request
4320   */
4321  self.notifyWhenNoOutstandingRequests = function(callback) {
4322    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4323    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4324    // regular poller would result in flaky tests.
4325    forEach(pollFns, function(pollFn){ pollFn(); });
4326
4327    if (outstandingRequestCount === 0) {
4328      callback();
4329    } else {
4330      outstandingRequestCallbacks.push(callback);
4331    }
4332  };
4333
4334  //////////////////////////////////////////////////////////////
4335  // Poll Watcher API
4336  //////////////////////////////////////////////////////////////
4337  var pollFns = [],
4338      pollTimeout;
4339
4340  /**
4341   * @name $browser#addPollFn
4342   *
4343   * @param {function()} fn Poll function to add
4344   *
4345   * @description
4346   * Adds a function to the list of functions that poller periodically executes,
4347   * and starts polling if not started yet.
4348   *
4349   * @returns {function()} the added function
4350   */
4351  self.addPollFn = function(fn) {
4352    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4353    pollFns.push(fn);
4354    return fn;
4355  };
4356
4357  /**
4358   * @param {number} interval How often should browser call poll functions (ms)
4359   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4360   *
4361   * @description
4362   * Configures the poller to run in the specified intervals, using the specified
4363   * setTimeout fn and kicks it off.
4364   */
4365  function startPoller(interval, setTimeout) {
4366    (function check() {
4367      forEach(pollFns, function(pollFn){ pollFn(); });
4368      pollTimeout = setTimeout(check, interval);
4369    })();
4370  }
4371
4372  //////////////////////////////////////////////////////////////
4373  // URL API
4374  //////////////////////////////////////////////////////////////
4375
4376  var lastBrowserUrl = location.href,
4377      baseElement = document.find('base'),
4378      newLocation = null;
4379
4380  /**
4381   * @name $browser#url
4382   *
4383   * @description
4384   * GETTER:
4385   * Without any argument, this method just returns current value of location.href.
4386   *
4387   * SETTER:
4388   * With at least one argument, this method sets url to new value.
4389   * If html5 history api supported, pushState/replaceState is used, otherwise
4390   * location.href/location.replace is used.
4391   * Returns its own instance to allow chaining
4392   *
4393   * NOTE: this api is intended for use only by the $location service. Please use the
4394   * {@link ng.$location $location service} to change url.
4395   *
4396   * @param {string} url New url (when used as setter)
4397   * @param {boolean=} replace Should new url replace current history record ?
4398   */
4399  self.url = function(url, replace) {
4400    // Android Browser BFCache causes location, history reference to become stale.
4401    if (location !== window.location) location = window.location;
4402    if (history !== window.history) history = window.history;
4403
4404    // setter
4405    if (url) {
4406      if (lastBrowserUrl == url) return;
4407      lastBrowserUrl = url;
4408      if ($sniffer.history) {
4409        if (replace) history.replaceState(null, '', url);
4410        else {
4411          history.pushState(null, '', url);
4412          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4413          baseElement.attr('href', baseElement.attr('href'));
4414        }
4415      } else {
4416        newLocation = url;
4417        if (replace) {
4418          location.replace(url);
4419        } else {
4420          location.href = url;
4421        }
4422      }
4423      return self;
4424    // getter
4425    } else {
4426      // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4427      //   methods not updating location.href synchronously.
4428      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4429      return newLocation || location.href.replace(/%27/g,"'");
4430    }
4431  };
4432
4433  var urlChangeListeners = [],
4434      urlChangeInit = false;
4435
4436  function fireUrlChange() {
4437    newLocation = null;
4438    if (lastBrowserUrl == self.url()) return;
4439
4440    lastBrowserUrl = self.url();
4441    forEach(urlChangeListeners, function(listener) {
4442      listener(self.url());
4443    });
4444  }
4445
4446  /**
4447   * @name $browser#onUrlChange
4448   *
4449   * @description
4450   * Register callback function that will be called, when url changes.
4451   *
4452   * It's only called when the url is changed from outside of angular:
4453   * - user types different url into address bar
4454   * - user clicks on history (forward/back) button
4455   * - user clicks on a link
4456   *
4457   * It's not called when url is changed by $browser.url() method
4458   *
4459   * The listener gets called with new url as parameter.
4460   *
4461   * NOTE: this api is intended for use only by the $location service. Please use the
4462   * {@link ng.$location $location service} to monitor url changes in angular apps.
4463   *
4464   * @param {function(string)} listener Listener function to be called when url changes.
4465   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4466   */
4467  self.onUrlChange = function(callback) {
4468    // TODO(vojta): refactor to use node's syntax for events
4469    if (!urlChangeInit) {
4470      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4471      // don't fire popstate when user change the address bar and don't fire hashchange when url
4472      // changed by push/replaceState
4473
4474      // html5 history api - popstate event
4475      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4476      // hashchange event
4477      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4478      // polling
4479      else self.addPollFn(fireUrlChange);
4480
4481      urlChangeInit = true;
4482    }
4483
4484    urlChangeListeners.push(callback);
4485    return callback;
4486  };
4487
4488  //////////////////////////////////////////////////////////////
4489  // Misc API
4490  //////////////////////////////////////////////////////////////
4491
4492  /**
4493   * @name $browser#baseHref
4494   *
4495   * @description
4496   * Returns current <base href>
4497   * (always relative - without domain)
4498   *
4499   * @returns {string} The current base href
4500   */
4501  self.baseHref = function() {
4502    var href = baseElement.attr('href');
4503    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4504  };
4505
4506  //////////////////////////////////////////////////////////////
4507  // Cookies API
4508  //////////////////////////////////////////////////////////////
4509  var lastCookies = {};
4510  var lastCookieString = '';
4511  var cookiePath = self.baseHref();
4512
4513  /**
4514   * @name $browser#cookies
4515   *
4516   * @param {string=} name Cookie name
4517   * @param {string=} value Cookie value
4518   *
4519   * @description
4520   * The cookies method provides a 'private' low level access to browser cookies.
4521   * It is not meant to be used directly, use the $cookie service instead.
4522   *
4523   * The return values vary depending on the arguments that the method was called with as follows:
4524   *
4525   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4526   *   it
4527   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4528   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4529   *   way)
4530   *
4531   * @returns {Object} Hash of all cookies (if called without any parameter)
4532   */
4533  self.cookies = function(name, value) {
4534    /* global escape: false, unescape: false */
4535    var cookieLength, cookieArray, cookie, i, index;
4536
4537    if (name) {
4538      if (value === undefined) {
4539        rawDocument.cookie = escape(name) + "=;
4539path=" + cookiePath +
4540                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4541      } else {
4542        if (isString(value)) {
4543          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4544                                ';path=' + cookiePath).length + 1;
4545
4546          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4547          // - 300 cookies
4548          // - 20 cookies per unique domain
4549          // - 4096 bytes per cookie
4550          if (cookieLength > 4096) {
4551            $log.warn("Cookie '"+ name +
4552              "' possibly not set or overflowed because it was too large ("+
4553              cookieLength + " > 4096 bytes)!");
4554          }
4555        }
4556      }
4557    } else {
4558      if (rawDocument.cookie !== lastCookieString) {
4559        lastCookieString = rawDocument.cookie;
4560        cookieArray = lastCookieString.split("; ");
4561        lastCookies = {};
4562
4563        for (i = 0; i < cookieArray.length; i++) {
4564          cookie = cookieArray[i];
4565          index = cookie.indexOf('=');
4566          if (index > 0) { //ignore nameless cookies
4567            name = unescape(cookie.substring(0, index));
4568            // the first value that is seen for a cookie is the most
4569            // specific one.  values for the same cookie name that
4570            // follow are for less specific paths.
4571            if (lastCookies[name] === undefined) {
4572              lastCookies[name] = unescape(cookie.substring(index + 1));
4573            }
4574          }
4575        }
4576      }
4577      return lastCookies;
4578    }
4579  };
4580
4581
4582  /**
4583   * @name $browser#defer
4584   * @param {function()} fn A function, who's execution should be deferred.
4585   * @param {number=} [delay=0] of milliseconds to defer the function execution.
4586   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4587   *
4588   * @description
4589   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4590   *
4591   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4592   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4593   * via `$browser.defer.flush()`.
4594   *
4595   */
4596  self.defer = function(fn, delay) {
4597    var timeoutId;
4598    outstandingRequestCount++;
4599    timeoutId = setTimeout(function() {
4600      delete pendingDeferIds[timeoutId];
4601      completeOutstandingRequest(fn);
4602    }, delay || 0);
4603    pendingDeferIds[timeoutId] = true;
4604    return timeoutId;
4605  };
4606
4607
4608  /**
4609   * @name $browser#defer.cancel
4610   *
4611   * @description
4612   * Cancels a deferred task identified with `deferId`.
4613   *
4614   * @param {*} deferId Token returned by the `$browser.defer` function.
4615   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4616   *                    canceled.
4617   */
4618  self.defer.cancel = function(deferId) {
4619    if (pendingDeferIds[deferId]) {
4620      delete pendingDeferIds[deferId];
4621      clearTimeout(deferId);
4622      completeOutstandingRequest(noop);
4623      return true;
4624    }
4625    return false;
4626  };
4627
4628}
4629
4630function $BrowserProvider(){
4631  this.$get = ['$window', '$log', '$sniffer', '$document',
4632      function( $window,   $log,   $sniffer,   $document){
4633        return new Browser($window, $document, $log, $sniffer);
4634      }];
4635}
4636
4637/**
4638 * @ngdoc service
4639 * @name $cacheFactory
4640 *
4641 * @description
4642 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4643 * them.
4644 *
4645 * ```js
4646 *
4647 *  var cache = $cacheFactory('cacheId');
4648 *  expect($cacheFactory.get('cacheId')).toBe(cache);
4649 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4650 *
4651 *  cache.put("key", "value");
4652 *  cache.put("another key", "another value");
4653 *
4654 *  // We've specified no options on creation
4655 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4656 *
4657 * ```
4658 *
4659 *
4660 * @param {string} cacheId Name or id of the newly created cache.
4661 * @param {object=} options Options object that specifies the cache behavior. Properties:
4662 *
4663 *   - `{number=}` `capacity` — turns the cache into LRU cache.
4664 *
4665 * @returns {object} Newly created cache object with the following set of methods:
4666 *
4667 * - `{object}` `info()` — Returns id, size, and options of cache.
4668 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4669 *   it.
4670 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4671 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4672 * - `{void}` `removeAll()` — Removes all cached values.
4673 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4674 *
4675 * @example
4676   <example module="cacheExampleApp">
4677     <file name="index.html">
4678       <div ng-controller="CacheController">
4679         <input ng-model="newCacheKey" placeholder="Key">
4680         <input ng-model="newCacheValue" placeholder="Value">
4681         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4682
4683         <p ng-if="keys.length">Cached Values</p>
4684         <div ng-repeat="key in keys">
4685           <span ng-bind="key"></span>
4686           <span>: </span>
4687           <b ng-bind="cache.get(key)"></b>
4688         </div>
4689
4690         <p>Cache Info</p>
4691         <div ng-repeat="(key, value) in cache.info()">
4692           <span ng-bind="key"></span>
4693           <span>: </span>
4694           <b ng-bind="value"></b>
4695         </div>
4696       </div>
4697     </file>
4698     <file name="script.js">
4699       angular.module('cacheExampleApp', []).
4700         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4701           $scope.keys = [];
4702           $scope.cache = $cacheFactory('cacheId');
4703           $scope.put = function(key, value) {
4704             $scope.cache.put(key, value);
4705             $scope.keys.push(key);
4706           };
4707         }]);
4708     </file>
4709     <file name="style.css">
4710       p {
4711         margin: 10px 0 3px;
4712       }
4713     </file>
4714   </example>
4715 */
4716function $CacheFactoryProvider() {
4717
4718  this.$get = function() {
4719    var caches = {};
4720
4721    function cacheFactory(cacheId, options) {
4722      if (cacheId in caches) {
4723        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4724      }
4725
4726      var size = 0,
4727          stats = extend({}, options, {id: cacheId}),
4728          data = {},
4729          capacity = (options && options.capacity) || Number.MAX_VALUE,
4730          lruHash = {},
4731          freshEnd = null,
4732          staleEnd = null;
4733
4734      /**
4735       * @ngdoc type
4736       * @name $cacheFactory.Cache
4737       *
4738       * @description
4739       * A cache object used to store and retrieve data, primarily used by
4740       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4741       * templates and other data.
4742       *
4743       * ```js
4744       *  angular.module('superCache')
4745       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4746       *      return $cacheFactory('super-cache');
4747       *    }]);
4748       * ```
4749       *
4750       * Example test:
4751       *
4752       * ```js
4753       *  it('should behave like a cache', inject(function(superCache) {
4754       *    superCache.put('key', 'value');
4755       *    superCache.put('another key', 'another value');
4756       *
4757       *    expect(superCache.info()).toEqual({
4758       *      id: 'super-cache',
4759       *      size: 2
4760       *    });
4761       *
4762       *    superCache.remove('another key');
4763       *    expect(superCache.get('another key')).toBeUndefined();
4764       *
4765       *    superCache.removeAll();
4766       *    expect(superCache.info()).toEqual({
4767       *      id: 'super-cache',
4768       *      size: 0
4769       *    });
4770       *  }));
4771       * ```
4772       */
4773      return caches[cacheId] = {
4774
4775        /**
4776         * @ngdoc method
4777         * @name $cacheFactory.Cache#put
4778         * @function
4779         *
4780         * @description
4781         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4782         * retrieved later, and incrementing the size of the cache if the key was not already
4783         * present in the cache. If behaving like an LRU cache, it will also remove stale
4784         * entries from the set.
4785         *
4786         * It will not insert undefined values into the cache.
4787         *
4788         * @param {string} key the key under which the cached data is stored.
4789         * @param {*} value the value to store alongside the key. If it is undefined, the key
4790         *    will not be stored.
4791         * @returns {*} the value stored.
4792         */
4793        put: function(key, value) {
4794          if (capacity < Number.MAX_VALUE) {
4795            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4796
4797            refresh(lruEntry);
4798          }
4799
4800          if (isUndefined(value)) return;
4801          if (!(key in data)) size++;
4802          data[key] = value;
4803
4804          if (size > capacity) {
4805            this.remove(staleEnd.key);
4806          }
4807
4808          return value;
4809        },
4810
4811        /**
4812         * @ngdoc method
4813         * @name $cacheFactory.Cache#get
4814         * @function
4815         *
4816         * @description
4817         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4818         *
4819         * @param {string} key the key of the data to be retrieved
4820         * @returns {*} the value stored.
4821         */
4822        get: function(key) {
4823          if (capacity < Number.MAX_VALUE) {
4824            var lruEntry = lruHash[key];
4825
4826            if (!lruEntry) return;
4827
4828            refresh(lruEntry);
4829          }
4830
4831          return data[key];
4832        },
4833
4834
4835        /**
4836         * @ngdoc method
4837         * @name $cacheFactory.Cache#remove
4838         * @function
4839         *
4840         * @description
4841         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4842         *
4843         * @param {string} key the key of the entry to be removed
4844         */
4845        remove: function(key) {
4846          if (capacity < Number.MAX_VALUE) {
4847            var lruEntry = lruHash[key];
4848
4849            if (!lruEntry) return;
4850
4851            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4852            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4853            link(lruEntry.n,lruEntry.p);
4854
4855            delete lruHash[key];
4856          }
4857
4858          delete data[key];
4859          size--;
4860        },
4861
4862
4863        /**
4864         * @ngdoc method
4865         * @name $cacheFactory.Cache#removeAll
4866         * @function
4867         *
4868         * @description
4869         * Clears the cache object of any entries.
4870         */
4871        removeAll: function() {
4872          data = {};
4873          size = 0;
4874          lruHash = {};
4875          freshEnd = staleEnd = null;
4876        },
4877
4878
4879        /**
4880         * @ngdoc method
4881         * @name $cacheFactory.Cache#destroy
4882         * @function
4883         *
4884         * @description
4885         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
4886         * removing it from the {@link $cacheFactory $cacheFactory} set.
4887         */
4888        destroy: function() {
4889          data = null;
4890          stats = null;
4891          lruHash = null;
4892          delete caches[cacheId];
4893        },
4894
4895
4896        /**
4897         * @ngdoc method
4898         * @name $cacheFactory.Cache#info
4899         * @function
4900         *
4901         * @description
4902         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
4903         *
4904         * @returns {object} an object with the following properties:
4905         *   <ul>
4906         *     <li>**id**: the id of the cache instance</li>
4907         *     <li>**size**: the number of entries kept in the cache instance</li>
4908         *     <li>**...**: any additional properties from the options object when creating the
4909         *       cache.</li>
4910         *   </ul>
4911         */
4912        info: function() {
4913          return extend({}, stats, {size: size});
4914        }
4915      };
4916
4917
4918      /**
4919       * makes the `entry` the freshEnd of the LRU linked list
4920       */
4921      function refresh(entry) {
4922        if (entry != freshEnd) {
4923          if (!staleEnd) {
4924            staleEnd = entry;
4925          } else if (staleEnd == entry) {
4926            staleEnd = entry.n;
vendor: 4,907 bytes, lines 4927-5090
4927          }
4928
4929          link(entry.n, entry.p);
4930          link(entry, freshEnd);
4931          freshEnd = entry;
4932          freshEnd.n = null;
4933        }
4934      }
4935
4936
4937      /**
4938       * bidirectionally links two entries of the LRU linked list
4939       */
4940      function link(nextEntry, prevEntry) {
4941        if (nextEntry != prevEntry) {
4942          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
4943          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
4944        }
4945      }
4946    }
4947
4948
4949  /**
4950   * @ngdoc method
4951   * @name $cacheFactory#info
4952   *
4953   * @description
4954   * Get information about all the of the caches that have been created
4955   *
4956   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
4957   */
4958    cacheFactory.info = function() {
4959      var info = {};
4960      forEach(caches, function(cache, cacheId) {
4961        info[cacheId] = cache.info();
4962      });
4963      return info;
4964    };
4965
4966
4967  /**
4968   * @ngdoc method
4969   * @name $cacheFactory#get
4970   *
4971   * @description
4972   * Get access to a cache object by the `cacheId` used when it was created.
4973   *
4974   * @param {string} cacheId Name or id of a cache to access.
4975   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
4976   */
4977    cacheFactory.get = function(cacheId) {
4978      return caches[cacheId];
4979    };
4980
4981
4982    return cacheFactory;
4983  };
4984}
4985
4986/**
4987 * @ngdoc service
4988 * @name $templateCache
4989 *
4990 * @description
4991 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
4992 * can load templates directly into the cache in a `script` tag, or by consuming the
4993 * `$templateCache` service directly.
4994 *
4995 * Adding via the `script` tag:
4996 *
4997 * ```html
4998 *   <script type="text/ng-template" id="templateId.html">
4999 *     <p>This is the content of the template</p>
5000 *   </script>
5001 * ```
5002 *
5003 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5004 * the document, but it must be below the `ng-app` definition.
5005 *
5006 * Adding via the $templateCache service:
5007 *
5008 * ```js
5009 * var myApp = angular.module('myApp', []);
5010 * myApp.run(function($templateCache) {
5011 *   $templateCache.put('templateId.html', 'This is the content of the template');
5012 * });
5013 * ```
5014 *
5015 * To retrieve the template later, simply use it in your HTML:
5016 * ```html
5017 * <div ng-include=" 'templateId.html' "></div>
5018 * ```
5019 *
5020 * or get it via Javascript:
5021 * ```js
5022 * $templateCache.get('templateId.html')
5023 * ```
5024 *
5025 * See {@link ng.$cacheFactory $cacheFactory}.
5026 *
5027 */
5028function $TemplateCacheProvider() {
5029  this.$get = ['$cacheFactory', function($cacheFactory) {
5030    return $cacheFactory('templates');
5031  }];
5032}
5033
5034/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5035 *
5036 * DOM-related variables:
5037 *
5038 * - "node" - DOM Node
5039 * - "element" - DOM Element or Node
5040 * - "$node" or "$element" - jqLite-wrapped node or element
5041 *
5042 *
5043 * Compiler related stuff:
5044 *
5045 * - "linkFn" - linking fn of a single directive
5046 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5047 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5048 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5049 */
5050
5051
5052/**
5053 * @ngdoc service
5054 * @name $compile
5055 * @function
5056 *
5057 * @description
5058 * Compiles an HTML string or DOM into a template and produces a template function, which
5059 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5060 *
5061 * The compilation is a process of walking the DOM tree and matching DOM elements to
5062 * {@link ng.$compileProvider#directive directives}.
5063 *
5064 * <div class="alert alert-warning">
5065 * **Note:** This document is an in-depth reference of all directive options.
5066 * For a gentle introduction to directives with examples of common use cases,
5067 * see the {@link guide/directive directive guide}.
5068 * </div>
5069 *
5070 * ## Comprehensive Directive API
5071 *
5072 * There are many different options for a directive.
5073 *
5074 * The difference resides in the return value of the factory function.
5075 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5076 * or just the `postLink` function (all other properties will have the default values).
5077 *
5078 * <div class="alert alert-success">
5079 * **Best Practice:** It's recommended to use the "directive definition object" form.
5080 * </div>
5081 *
5082 * Here's an example directive declared with a Directive Definition Object:
5083 *
5084 * ```js
5085 *   var myModule = angular.module(...);
5086 *
5087 *   myModule.directive('directiveName', function factory(injectables) {
5088 *     var directiveDefinitionObject = {
5089 *       priority: 0,
5090 *       template: '<div></div>
5090', // or // function(tElement, tAttrs) { ... },
5091 *       // or
5092 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5093 *       replace: false,
5094 *       transclude: false,
5095 *       restrict: 'A',
5096 *       scope: false,
5097 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5098 *       controllerAs: 'stringAlias',
5099 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5100 *       compile: function compile(tElement, tAttrs, transclude) {
5101 *         return {
5102 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5103 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5104 *         }
5105 *         // or
5106 *         // return function postLink( ... ) { ... }
5107 *       },
5108 *       // or
5109 *       // link: {
5110 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5111 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5112 *       // }
5113 *       // or
5114 *       // link: function postLink( ... ) { ... }
5115 *     };
5116 *     return directiveDefinitionObject;
5117 *   });
5118 * ```
5119 *
5120 * <div class="alert alert-warning">
5121 * **Note:** Any unspecified options will use the default value. You can see the default values below.
5122 * </div>
5123 *
5124 * Therefore the above can be simplified as:
5125 *
5126 * ```js
5127 *   var myModule = angular.module(...);
5128 *
5129 *   myModule.directive('directiveName', function factory(injectables) {
5130 *     var directiveDefinitionObject = {
5131 *       link: function postLink(scope, iElement, iAttrs) { ... }
5132 *     };
5133 *     return directiveDefinitionObject;
5134 *     // or
5135 *     // return function postLink(scope, iElement, iAttrs) { ... }
5136 *   });
5137 * ```
5138 *
5139 *
5140 *
5141 * ### Directive Definition Object
5142 *
5143 * The directive definition object provides instructions to the {@link ng.$compile
5144 * compiler}. The attributes are:
5145 *
5146 * #### `priority`
5147 * When there are multiple directives defined on a single DOM element, sometimes it
5148 * is necessary to specify the order in which the directives are applied. The `priority` is used
5149 * to sort the directives before their `compile` functions get called. Priority is defined as a
5150 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5151 * are also run in priority order, but post-link functions are run in reverse order. The order
5152 * of directives with the same priority is undefined. The default priority is `0`.
5153 *
5154 * #### `terminal`
5155 * If set to true then the current `priority` will be the last set of directives
5156 * which will execute (any directives at the current priority will still execute
5157 * as the order of execution on same `priority` is undefined).
5158 *
5159 * #### `scope`
5160 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5161 * same element request a new scope, only one new scope is created. The new scope rule does not
5162 * apply for the root of the template since the root of the template always gets a new scope.
5163 *
5164 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5165 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5166 * when creating reusable components, which should not accidentally read or modify data in the
5167 * parent scope.
5168 *
5169 * The 'isolate' scope takes an object hash which defines a set of local scope properties
5170 * derived from the parent scope. These local properties are useful for aliasing values for
5171 * templates. Locals definition is a hash of local scope property to its source:
5172 *
5173 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5174 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5175 *   attribute name is assumed to be the same as the local name.
5176 *   Given `<widget my-attr="hello {{name}}">` and widget definition
5177 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5178 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5179 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5180 *   component scope).
5181 *
5182 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5183 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5184 *   name is specified then the attribute name is assumed to be the same as the local name.
5185 *   Given `<widget my-attr="parentModel">` and widget definition of
5186 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5187 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5188 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5189 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5190 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5191 *
5192 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5193 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5194 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5195 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5196 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5197 *   pass data from the isolated scope via an expression and to the parent scope, this can be
5198 *   done by passing a map of local variable names and values into the expression wrapper fn.
5199 *   For example, if the expression is `increment(amount)` then we can specify the amount value
5200 *   by calling the `localFn` as `localFn({amount: 22})`.
5201 *
5202 *
5203 *
5204 * #### `controller`
5205 * Controller constructor function. The controller is instantiated before the
5206 * pre-linking phase and it is shared with other directives (see
5207 * `require` attribute). This allows the directives to communicate with each other and augment
5208 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5209 *
5210 * * `$scope` - Current scope associated with the element
5211 * * `$element` - Current element
5212 * * `$attrs` - Current attributes object for the element
5213 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5214 *    The scope can be overridden by an optional first argument.
5215 *   `function([scope], cloneLinkingFn)`.
5216 *
5217 *
5218 * #### `require`
5219 * Require another directive and inject its controller as the fourth argument to the linking function. The
5220 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5221 * injected argument will be an array in corresponding order. If no such directive can be
5222 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5223 *
5224 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5225 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5226 * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5227 * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
5228 *   `link` fn if not found.
5229 *
5230 *
5231 * #### `controllerAs`
5232 * Controller alias at the directive scope. An alias for the controller so it
5233 * can be referenced at the directive template. The directive needs to define a scope for this
5234 * configuration to be used. Useful in the case when directive is used as component.
5235 *
5236 *
5237 * #### `restrict`
5238 * String of subset of `EACM` which restricts the directive to a specific directive
5239 * declaration style. If omitted, the default (attributes only) is used.
5240 *
5241 * * `E` - Element name: `<my-directive></my-directive>`
5242 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5243 * * `C` - Class: `<div class="my-directive: exp;"></div>`
5244 * * `M` - Comment: `<!-- directive: my-directive exp -->`
5245 *
5246 *
5247 * #### `template`
5248 * replace the current element with the contents of the HTML. The replacement process
5249 * migrates all of the attributes / classes from the old element to the new one. See the
5250 * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5251 * Directives Guide} for an example.
5252 *
5253 * You can specify `template` as a string representing the template or as a function which takes
5254 * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
5255 * returns a string value representing the template.
5256 *
5257 *
5258 * #### `templateUrl`
5259 * Same as `template` but the template is loaded from the specified URL. Because
5260 * the template loading is asynchronous the compilation/linking is suspended until the template
5261 * is loaded.
5262 *
5263 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5264 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5265 * a string value representing the url.  In either case, the template URL is passed through {@link
5266 * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5267 *
5268 *
5269 * #### `replace`
5270 * specify where the template should be inserted. Defaults to `false`.
5271 *
5272 * * `true` - the template will replace the current element.
5273 * * `false` - the template will replace the contents of the current element.
5274 *
5275 *
5276 * #### `transclude`
5277 * compile the content of the element and make it available to the directive.
5278 * Typically used with {@link ng.directive:ngTransclude
5279 * ngTransclude}. The advantage of transclusion is that the linking function receives a
5280 * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5281 * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5282 * scope. This makes it possible for the widget to have private state, and the transclusion to
5283 * be bound to the parent (pre-`isolate`) scope.
5284 *
5285 * * `true` - transclude the content of the directive.
5286 * * `'element'` - transclude the whole element including any directives defined at lower priority.
5287 *
5288 *
5289 * #### `compile`
5290 *
5291 * ```js
5292 *   function compile(tElement, tAttrs, transclude) { ... }
5293 * ```
5294 *
5295 * The compile function deals with transforming the template DOM. Since most directives do not do
5296 * template transformation, it is not used often. Examples that require compile functions are
5297 * directives that transform template DOM, such as {@link
5298 * api/ng.directive:ngRepeat ngRepeat}, or load the contents
5299 * asynchronously, such as {@link ngRoute.directive:ngView ngView}. The
5300 * compile function takes the following arguments.
5301 *
5302 *   * `tElement` - template element - The element where the directive has been declared. It is
5303 *     safe to do template transformation on the element and child elements only.
5304 *
5305 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5306 *     between all directive compile functions.
5307 *
5308 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5309 *
5310 * <div class="alert alert-warning">
5311 * **Note:** The template instance and the link instance may be different objects if the template has
5312 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5313 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5314 * should be done in a linking function rather than in a compile function.
5315 * </div>
5316
5317 * <div class="alert alert-warning">
5318 * **Note:** The compile function cannot handle directives that recursively use themselves in their
5319 * own templates or compile functions. Compiling these directives results in an infinite loop and a
5320 * stack overflow errors.
5321 *
5322 * This can be avoided by manually using $compile in the postLink function to imperatively compile
5323 * a directive's template instead of relying on automatic template compilation via `template` or
5324 * `templateUrl` declaration or manual compilation inside the compile function.
5325 * </div>
5326 *
5327 * <div class="alert alert-error">
5328 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5329 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5330 *   to the link function instead.
5331 * </div>
5332
5333 * A compile function can have a return value which can be either a function or an object.
5334 *
5335 * * returning a (post-link) function - is equivalent to registering the linking function via the
5336 *   `link` property of the config object when the compile function is empty.
5337 *
5338 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5339 *   control when a linking function should be called during the linking phase. See info about
5340 *   pre-linking and post-linking functions below.
5341 *
5342 *
5343 * #### `link`
5344 * This property is used only if the `compile` property is not defined.
5345 *
5346 * ```js
5347 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5348 * ```
5349 *
5350 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5351 * executed after the template has been cloned. This is where most of the directive logic will be
5352 * put.
5353 *
5354 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5355 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5356 *
5357 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5358 *     manipulate the children of the element only in `postLink` function since the children have
5359 *     already been linked.
5360 *
5361 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5362 *     between all directive linking functions.
5363 *
5364 *   * `controller` - a controller instance - A controller instance if at least one directive on the
5365 *     element defines a controller. The controller is shared among all the directives, which allows
5366 *     the directives to use the controllers as a communication channel.
5367 *
5368 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5369 *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5370 *     parameter of directive controllers.
5371 *     `function([scope], cloneLinkingFn)`.
5372 *
5373 *
5374 * #### Pre-linking function
5375 *
5376 * Executed before the child elements are linked. Not safe to do DOM transformation since the
5377 * compiler linking function will fail to locate the correct elements for linking.
5378 *
5379 * #### Post-linking function
5380 *
5381 * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5382 *
5383 * <a name="Attributes"></a>
5384 * ### Attributes
5385 *
5386 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5387 * `link()` or `compile()` functions. It has a variety of uses.
5388 *
5389 * accessing *Normalized attribute names:*
5390 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5391 * the attributes object allows for normalized access to
5392 *   the attributes.
5393 *
5394 * * *Directive inter-communication:* All directives share the same instance of the attributes
5395 *   object which allows the directives to use the attributes object as inter directive
5396 *   communication.
5397 *
5398 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5399 *   allowing other directives to read the interpolated value.
5400 *
5401 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5402 *   that contain interpolation (e.g. `src="{{bar}}
5402"`). Not only is this very efficient but it's also
5403 *   the only way to easily get the actual value because during the linking phase the interpolation
5404 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5405 *
5406 * ```js
5407 * function linkingFn(scope, elm, attrs, ctrl) {
5408 *   // get the attribute value
5409 *   console.log(attrs.ngModel);
5410 *
5411 *   // change the attribute
5412 *   attrs.$set('ngModel', 'new value');
5413 *
5414 *   // observe changes to interpolated attribute
5415 *   attrs.$observe('ngModel', function(value) {
5416 *     console.log('ngModel has changed value to ' + value);
5417 *   });
5418 * }
5419 * ```
5420 *
5421 * Below is an example using `$compileProvider`.
5422 *
5423 * <div class="alert alert-warning">
5424 * **Note**: Typically directives are registered with `module.directive`. The example below is
5425 * to illustrate how `$compile` works.
5426 * </div>
5427 *
5428 <example module="compile">
5429   <file name="index.html">
5430    <script>
5431      angular.module('compile', [], function($compileProvider) {
5432        // configure new 'compile' directive by passing a directive
5433        // factory function. The factory function injects the '$compile'
5434        $compileProvider.directive('compile', function($compile) {
5435          // directive factory creates a link function
5436          return function(scope, element, attrs) {
5437            scope.$watch(
5438              function(scope) {
5439                 // watch the 'compile' expression for changes
5440                return scope.$eval(attrs.compile);
5441              },
5442              function(value) {
5443                // when the 'compile' expression changes
5444                // assign it into the current DOM
5445                element.html(value);
5446
5447                // compile the new DOM and link it to the current
5448                // scope.
5449                // NOTE: we only compile .childNodes so that
5450                // we don't get into infinite loop compiling ourselves
5451                $compile(element.contents())(scope);
5452              }
5453            );
5454          };
5455        })
5456      });
5457
5458      function Ctrl($scope) {
5459        $scope.name = 'Angular';
5460        $scope.html = 'Hello {{name}}';
5461      }
5462    </script>
5463    <div ng-controller="Ctrl">
5464      <input ng-model="name"> <br>
5465      <textarea ng-model="html"></textarea> <br>
5466      <div compile="html"></div>
5467    </div>
5468   </file>
5469   <file name="protractor.js" type="protractor">
5470     it('should auto compile', function() {
5471       var textarea = $('textarea');
5472       var output = $('div[compile]');
5473       // The initial state reads 'Hello Angular'.
5474       expect(output.getText()).toBe('Hello Angular');
5475       textarea.clear();
5476       textarea.sendKeys('{{name}}!');
5477       expect(output.getText()).toBe('Angular!');
5478     });
5479   </file>
5480 </example>
5481
5482 *
5483 *
5484 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5485 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5486 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5487 *                 root element(s), not their children)
5488 * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5489 * (a DOM element/tree) to a scope. Where:
5490 *
5491 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5492 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5493 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5494 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5495 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5496 *
5497 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5498 *      * `scope` - is the current scope with which the linking function is working with.
5499 *
5500 * Calling the linking function returns the element of the template. It is either the original
5501 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5502 *
5503 * After linking the view is not updated until after a call to $digest which typically is done by
5504 * Angular automatically.
5505 *
5506 * If you need access to the bound view, there are two ways to do it:
5507 *
5508 * - If you are not asking the linking function to clone the template, create the DOM element(s)
5509 *   before you send them to the compiler and keep this reference around.
5510 *   ```js
5511 *     var element = $compile('<p>{{total}}</p>')(scope);
5512 *   ```
5513 *
5514 * - if on the other hand, you need the element to be cloned, the view reference from the original
5515 *   example would not point to the clone, but rather to the original template that was cloned. In
5516 *   this case, you can access the clone via the cloneAttachFn:
5517 *   ```js
5518 *     var templateElement = angular.element('<p>{{total}}</p>'),
5519 *         scope = ....;
5520 *
5521 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5522 *       //attach the clone to DOM document at the right place
5523 *     });
5524 *
5525 *     //now we have reference to the cloned DOM via `clonedElement`
5526 *   ```
5527 *
5528 *
5529 * For information on how the compiler works, see the
5530 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5531 */
5532
5533var $compileMinErr = minErr('$compile');
5534
5535/**
5536 * @ngdoc provider
5537 * @name $compileProvider
5538 * @function
5539 *
5540 * @description
5541 */
vendor: 4,653 bytes, lines 5542-5650
5542$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5543function $CompileProvider($provide, $$sanitizeUriProvider) {
5544  var hasDirectives = {},
5545      Suffix = 'Directive',
5546      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5547      CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5548
5549  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5550  // The assumption is that future DOM event attribute names will begin with
5551  // 'on' and be composed of only English letters.
5552  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5553
5554  /**
5555   * @ngdoc method
5556   * @name $compileProvider#directive
5557   * @function
5558   *
5559   * @description
5560   * Register a new directive with the compiler.
5561   *
5562   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5563   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5564   *    names and the values are the factories.
5565   * @param {Function|Array} directiveFactory An injectable directive factory function. See
5566   *    {@link guide/directive} for more info.
5567   * @returns {ng.$compileProvider} Self for chaining.
5568   */
5569   this.directive = function registerDirective(name, directiveFactory) {
5570    assertNotHasOwnProperty(name, 'directive');
5571    if (isString(name)) {
5572      assertArg(directiveFactory, 'directiveFactory');
5573      if (!hasDirectives.hasOwnProperty(name)) {
5574        hasDirectives[name] = [];
5575        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5576          function($injector, $exceptionHandler) {
5577            var directives = [];
5578            forEach(hasDirectives[name], function(directiveFactory, index) {
5579              try {
5580                var directive = $injector.invoke(directiveFactory);
5581                if (isFunction(directive)) {
5582                  directive = { compile: valueFn(directive) };
5583                } else if (!directive.compile && directive.link) {
5584                  directive.compile = valueFn(directive.link);
5585                }
5586                directive.priority = directive.priority || 0;
5587                directive.index = index;
5588                directive.name = directive.name || name;
5589                directive.require = directive.require || (directive.controller && directive.name);
5590                directive.restrict = directive.restrict || 'A';
5591                directives.push(directive);
5592              } catch (e) {
5593                $exceptionHandler(e);
5594              }
5595            });
5596            return directives;
5597          }]);
5598      }
5599      hasDirectives[name].push(directiveFactory);
5600    } else {
5601      forEach(name, reverseParams(registerDirective));
5602    }
5603    return this;
5604  };
5605
5606
5607  /**
5608   * @ngdoc method
5609   * @name $compileProvider#aHrefSanitizationWhitelist
5610   * @function
5611   *
5612   * @description
5613   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5614   * urls during a[href] sanitization.
5615   *
5616   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5617   *
5618   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5619   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5620   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5621   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5622   *
5623   * @param {RegExp=} regexp New regexp to whitelist urls with.
5624   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5625   *    chaining otherwise.
5626   */
5627  this.aHrefSanitizationWhitelist = function(regexp) {
5628    if (isDefined(regexp)) {
5629      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5630      return this;
5631    } else {
5632      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5633    }
5634  };
5635
5636
5637  /**
5638   * @ngdoc method
5639   * @name $compileProvider#imgSrcSanitizationWhitelist
5640   * @function
5641   *
5642   * @description
5643   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5644   * urls during img[src] sanitization.
5645   *
5646   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5647   *
5648   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5649   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5650   * regular expression. If a match is found, the original url is 
5650written into the dom. Otherwise,
5651   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5652   *
5653   * @param {RegExp=} regexp New regexp to whitelist urls with.
5654   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5655   *    chaining otherwise.
5656   */
5657  this.imgSrcSanitizationWhitelist = function(regexp) {
5658    if (isDefined(regexp)) {
5659      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5660      return this;
5661    } else {
5662      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5663    }
5664  };
5665
5666  this.$get = [
5667            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5668            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5669    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
5670             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
5671
5672    var Attributes = function(element, attr) {
5673      this.$$element = element;
5674      this.$attr = attr || {};
5675    };
5676
5677    Attributes.prototype = {
5678      $normalize: directiveNormalize,
5679
5680
5681      /**
5682       * @ngdoc method
5683       * @name $compile.directive.Attributes#$addClass
5684       * @function
5685       *
5686       * @description
5687       * Adds the CSS class value specified by the classVal parameter to the element. If animations
5688       * are enabled then an animation will be triggered for the class addition.
5689       *
5690       * @param {string} classVal The className value that will be added to the element
5691       */
5692      $addClass : function(classVal) {
5693        if(classVal && classVal.length > 0) {
5694          $animate.addClass(this.$$element, classVal);
5695        }
5696      },
5697
5698      /**
5699       * @ngdoc method
5700       * @name $compile.directive.Attributes#$removeClass
5701       * @function
5702       *
5703       * @description
5704       * Removes the CSS class value specified by the classVal parameter from the element. If
5705       * animations are enabled then an animation will be triggered for the class removal.
5706       *
5707       * @param {string} classVal The className value that will be removed from the element
5708       */
5709      $removeClass : function(classVal) {
5710        if(classVal && classVal.length > 0) {
5711          $animate.removeClass(this.$$element, classVal);
5712        }
5713      },
5714
5715      /**
5716       * @ngdoc method
5717       * @name $compile.directive.Attributes#$updateClass
5718       * @function
5719       *
5720       * @description
5721       * Adds and removes the appropriate CSS class values to the element based on the difference
5722       * between the new and old CSS class values (specified as newClasses and oldClasses).
5723       *
5724       * @param {string} newClasses The current CSS className value
5725       * @param {string} oldClasses The former CSS className value
5726       */
5727      $updateClass : function(newClasses, oldClasses) {
5728        var toAdd = tokenDifference(newClasses, oldClasses);
5729        var toRemove = tokenDifference(oldClasses, newClasses);
5730
5731        if(toAdd.length === 0) {
5732          $animate.removeClass(this.$$element, toRemove);
5733        } else if(toRemove.length === 0) {
5734          $animate.addClass(this.$$element, toAdd);
5735        } else {
5736          $animate.setClass(this.$$element, toAdd, toRemove);
5737        }
5738      },
5739
5740      /**
5741       * Set a normalized attribute on the element in a way such that all directives
5742       * can share the attribute. This function properly handles boolean attributes.
5743       * @param {string} key Normalized key. (ie ngAttribute)
5744       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5745       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5746       *     Defaults to true.
5747       * @param {string=} attrName Optional none normalized name. Defaults to key.
5748       */
5749      $set: function(key, value, writeAttr, attrName) {
5750        // TODO: decide whether or not to throw an error if "class"
5751        //is set through this function since it may cause $updateClass to
5752        //become unstable.
5753
5754        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5755            normalizedVal,
5756            nodeName;
5757
5758        if (booleanKey) {
5759          this.$$element.prop(key, value);
5760          attrName = booleanKey;
5761        }
5762
5763        this[key] = value;
5764
5765        // translate normalized key to actual key
5766        if (attrName) {
5767          this.$attr[key] = attrName;
5768        } else {
5769          attrName = this.$attr[key];
5770          if (!attrName) {
5771            this.$attr[key] = attrName = snake_case(key, '-');
5772          }
5773        }
5774
5775        nodeName = nodeName_(this.$$element);
5776
5777        // sanitize a[href] and img[src] values
5778        if ((nodeName === 'A' && key === 'href') ||
5779            (nodeName === 'IMG' && key === 'src')) {
5780          this[key] = value = $$sanitizeUri(value, key === 'src');
5781        }
5782
5783        if (writeAttr !== false) {
5784          if (value === null || value === undefined) {
5785            this.$$element.removeAttr(attrName);
5786          } else {
5787            this.$$element.attr(attrName, value);
5788          }
5789        }
5790
5791        // fire observers
5792        var $$observers = this.$$observers;
5793        $$observers && forEach($$observers[key], function(fn) {
5794          try {
5795            fn(value);
5796          } catch (e) {
5797            $exceptionHandler(e);
5798          }
5799        });
5800      },
5801
5802
5803      /**
5804       * @ngdoc method
5805       * @name $compile.directive.Attributes#$observe
5806       * @function
5807       *
5808       * @description
5809       * Observes an interpolated attribute.
5810       *
5811       * The observer function will be invoked once during the next `$digest` following
5812       * compilation. The observer is then invoked whenever the interpolated value
5813       * changes.
5814       *
5815       * @param {string} key Normalized key. (ie ngAttribute) .
5816       * @param {function(interpolatedValue)} fn Function that will be called whenever
5817                the interpolated value of the attribute changes.
5818       *        See the {@link guide/directive#Attributes Directives} guide for more info.
5819       * @returns {function()} the `fn` parameter.
5820       */
5821      $observe: function(key, fn) {
5822        var attrs = this,
5823            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5824            listeners = ($$observers[key] || ($$observers[key] = []));
5825
5826        listeners.push(fn);
5827        $rootScope.$evalAsync(function() {
5828          if (!listeners.$$inter) {
5829            // no one registered attribute interpolation function, so lets call it manually
5830            fn(attrs[key]);
5831          }
5832        });
5833        return fn;
5834      }
5835    };
5836
5837    var startSymbol = $interpolate.startSymbol(),
5838        endSymbol = $interpolate.endSymbol(),
5839        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
5840            ? identity
5841            : function denormalizeTemplate(template) {
5842              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5843        },
5844        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5845
5846
5847    return compile;
5848
5849    //================================
5850
5851    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
5852                        previousCompileContext) {
5853      if (!($compileNodes instanceof jqLite)) {
5854        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5855        // modify it.
5856        $compileNodes = jqLite($compileNodes);
5857      }
5858      // We can not compile top level text elements since text nodes can be merged and we will
5859      // not be able to attach scope data to them, so we will wrap them in <span>
5860      forEach($compileNodes, function(node, index){
5861        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
5862          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5863        }
5864      });
5865      var compositeLinkFn =
5866              compileNodes($compileNodes, transcludeFn, $compileNodes,
5867                           maxPriority, ignoreDirective, previousCompileContext);
5868      safeAddClass($compileNodes, 'ng-scope');
5869      return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
5870        assertArg(scope, 'scope');
5871        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5872        // and sometimes changes the structure of the DOM.
5873        var $linkNode = cloneConnectFn
5874          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5875          : $compileNodes;
5876
5877        forEach(transcludeControllers, function(instance, name) {
5878          $linkNode.data('$' + name + 'Controller', instance);
5879        });
5880
5881        // Attach scope only to non-text nodes.
5882        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
5883          var node = $linkNode[i],
5884              nodeType = node.nodeType;
5885          if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5886            $linkNode.eq(i).data('$scope', scope);
5887          }
5888        }
5889
5890        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5891        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
5892        return $linkNode;
5893      };
5894    }
5895
5896    function safeAddClass($element, className) {
5897      try {
5898        $element.addClass(className);
5899      } catch(e) {
5900        // ignore, since it means that we are trying to set class on
5901        // SVG element, where class name is read-only.
5902      }
5903    }
5904
5905    /**
5906     * Compile function matches each node in nodeList against the directives. Once all directives
5907     * for a particular node are collected their compile functions are executed. The compile
5908     * functions return values - the linking functions - are combined into a composite linking
5909     * function, which is the a linking function for the node.
5910     *
5911     * @param {NodeList} nodeList an array of nodes or NodeList to compile
5912     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
5913     *        scope argument is auto-generated to the new child of the transcluded parent scope.
5914     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
5915     *        the rootElement must be set the jqLite collection of the compile root. This is
5916     *        needed so that the jqLite collection items can be replaced with widgets.
5917     * @param {number=} maxPriority Max directive priority.
5918     * @returns {Function} A composite linking function of all of the matched directives or null.
5919     */
5920    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
5921                            previousCompileContext) {
5922      var linkFns = [],
5923          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
5924
5925      for (var i = 0; i < nodeList.length; i++) {
5926        attrs = new Attributes();
5927
5928        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
5929        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
5930                                        ignoreDirective);
5931
5932        nodeLinkFn = (directives.length)
5933            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
5934                                      null, [], [], previousCompileContext)
5935            : null;
5936
5937        if (nodeLinkFn && nodeLinkFn.scope) {
5938          safeAddClass(jqLite(nodeList[i]), 'ng-scope');
5939        }
5940
5941        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
5942                      !(childNodes = nodeList[i].childNodes) ||
5943                      !childNodes.length)
5944            ? null
5945            : compileNodes(childNodes,
5946                 nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
5947
5948        linkFns.push(nodeLinkFn, childLinkFn);
5949        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
5950        //use the previous context only for the first element in the virtual group
5951        previousCompileContext = null;
5952      }
5953
5954      // return a linking function if we have found anything, null otherwise
5955      return linkFnFound ? compositeLinkFn : null;
5956
5957      function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
5958        var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
5959
5960        // copy nodeList so that linking doesn't break due to live list updates.
5961        var nodeListLength = nodeList.length,
5962            stableNodeList = new Array(nodeListLength);
5963        for (i = 0; i < nodeListLength; i++) {
5964          stableNodeList[i] = nodeList[i];
5965        }
5966
5967        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
5968          node = stableNodeList[n];
5969          nodeLinkFn = linkFns[i++];
5970          childLinkFn = linkFns[i++];
5971          $node = jqLite(node);
5972
5973          if (nodeLinkFn) {
5974            if (nodeLinkFn.scope) {
5975              childScope = scope.$new();
5976              $node.data('$scope', childScope);
5977            } else {
5978              childScope = scope;
5979            }
5980            childTranscludeFn = nodeLinkFn.transclude;
5981            if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
5982              nodeLinkFn(childLinkFn, childScope, node, $rootElement,
5983                createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5984              );
5985            } else {
5986              nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
5987            }
5988          } else if (childLinkFn) {
5989            childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
5990          }
5991        }
5992      }
5993    }
5994
5995    function createBoundTranscludeFn(scope, transcludeFn) {
5996      return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
5997        var scopeCreated = false;
5998
5999        if (!transcludedScope) {
6000          transcludedScope = scope.$new();
6001          transcludedScope.$$transcluded = true;
6002          scopeCreated = true;
6003        }
6004
6005        var clone = transcludeFn(transcludedScope, cloneFn, controllers);
6006        if (scopeCreated) {
6007          clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
6008        }
6009        return clone;
6010      };
6011    }
6012
6013    /**
6014     * Looks for directives on the given node and adds them to the directive collection which is
6015     * sorted.
6016     *
6017     * @param node Node to search.
6018     * @param directives An array to which the directives are added to. This array is sorted before
6019     *        the function returns.
6020     * @param attrs The shared attrs object which is used to populate the normalized attributes.
6021     * @param {number=} maxPriority Max directive priority.
6022     */
6023    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6024      var nodeType = node.nodeType,
6025          attrsMap = attrs.$attr,
6026          match,
6027          className;
6028
6029      switch(nodeType) {
6030        case 1: /* Element */
6031          // use the node name: <directive>
6032          addDirective(directives,
6033              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6034
6035          // iterate over the attributes
6036          for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
6037                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6038            var attrStartName = false;
6039            var attrEndName = false;
6040
6041            attr = nAttrs[j];
6042            if (!msie || msie >= 8 || attr.specified) {
6043              name = attr.name;
6044              // support ngAttr attribute binding
6045              ngAttrName = directiveNormalize(name);
6046              if (NG_ATTR_BINDING.test(ngAttrName)) {
6047                name = snake_case(ngAttrName.substr(6), '-');
6048              }
6049
6050              var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6051              if (ngAttrName === directiveNName + 'Start') {
6052                attrStartName = name;
6053                attrEndName = name.substr(0, name.length - 5) + 'end';
6054                name = name.substr(0, name.length - 6);
6055              }
6056
6057              nName = directiveNormalize(name.toLowerCase());
6058              attrsMap[nName] = name;
6059              attrs[nName] = value = trim(attr.value);
6060              if (getBooleanAttrName(node, nName)) {
6061                attrs[nName] = true; // presence means true
6062              }
6063              addAttrInterpolateDirective(node, directives, value, nName);
6064              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6065                            attrEndName);
6066            }
6067          }
6068
6069          // use class as directive
6070          className = node.className;
6071          if (isString(className) && className !== '') {
6072            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6073              nName = directiveNormalize(match[2]);
6074              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6075                attrs[nName] = trim(match[3]);
6076              }
6077              className = className.substr(match.index + match[0].length);
6078            }
6079          }
6080          break;
6081        case 3: /* Text Node */
6082          addTextInterpolateDirective(directives, node.nodeValue);
6083          break;
6084        case 8: /* Comment */
6085          try {
6086            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6087            if (match) {
6088              nName = directiveNormalize(match[1]);
6089              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6090                attrs[nName] = trim(match[2]);
6091              }
6092            }
6093          } catch (e) {
6094            // turns out that under some circumstances IE9 throws errors when one attempts to read
6095            // comment's node value.
6096            // Just ignore it and continue. (Can't seem to reproduce in test case.)
6097          }
6098          break;
6099      }
6100
6101      directives.sort(byPriority);
6102      return directives;
6103    }
6104
6105    /**
6106     * Given a node with an directive-start it collects all of the siblings until it finds
6107     * directive-end.
6108     * @param node
6109     * @param attrStart
6110     * @param attrEnd
6111     * @returns {*}
6112     */
6113    function groupScan(node, attrStart, attrEnd) {
6114      var nodes = [];
6115      var depth = 0;
6116      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6117        var startNode = node;
6118        do {
6119          if (!node) {
6120            throw $compileMinErr('uterdir',
6121                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6122                      attrStart, attrEnd);
6123          }
6124          if (node.nodeType == 1 /** Element **/) {
6125            if (node.hasAttribute(attrStart)) depth++;
6126            if (node.hasAttribute(attrEnd)) depth--;
6127          }
6128          nodes.push(node);
6129          node = node.nextSibling;
6130        } while (depth > 0);
6131      } else {
6132        nodes.push(node);
6133      }
6134
6135      return jqLite(nodes);
6136    }
6137
6138    /**
6139     * Wrapper for linking function which converts normal linking function into a grouped
6140     * linking function.
6141     * @param linkFn
6142     * @param attrStart
6143     * @param attrEnd
6144     * @returns {Function}
6145     */
6146    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6147      return function(scope, element, attrs, controllers, transcludeFn) {
6148        element = groupScan(element[0], attrStart, attrEnd);
6149        return linkFn(scope, element, attrs, controllers, transcludeFn);
6150      };
6151    }
6152
6153    /**
6154     * Once the directives have been collected, their compile functions are executed. This method
6155     * is responsible for inlining directive templates as well as terminating the application
6156     * of the directives if the terminal directive has been reached.
6157     *
6158     * @param {Array} directives Array of collected directives to execute their compile function.
6159     *        this needs to be pre-sorted by priority order.
6160     * @param {Node} compileNode The raw DOM node to apply the compile functions to
6161     * @param {Object} templateAttrs The shared attribute function
6162     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6163     *                                                  scope argument is auto-generated to the new
6164     *                                                  child of the transcluded parent scope.
6165     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6166     *                              argument has the root jqLite array so that we can replace nodes
6167     *                              on it.
6168     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6169     *                                           compiling the transclusion.
6170     * @param {Array.<Function>} preLinkFns
6171     * @param {Array.<Function>} postLinkFns
6172     * @param {Object} previousCompileContext Context used for previous compilation of the current
6173     *                                        node
6174     * @returns {Function} linkFn
6175     */
6176    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
6177                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
6178                                   previousCompileContext) {
6179      previousCompileContext = previousCompileContext || {};
6180
6181      var terminalPriority = -Number.MAX_VALUE,
6182          newScopeDirective,
6183          controllerDirectives = previousCompileContext.controllerDirectives,
6184          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6185          templateDirective = previousCompileContext.templateDirective,
6186          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6187          hasTranscludeDirective = false,
6188          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6189          $compileNode = templateAttrs.$$element = jqLite(compileNode),
6190          directive,
6191          directiveName,
6192          $template,
6193          replaceDirective = originalReplaceDirective,
6194          childTranscludeFn = transcludeFn,
6195          linkFn,
6196          directiveValue;
6197
6198      // executes all directives on the current element
6199      for(var i = 0, ii = directives.length; i < ii; i++) {
6200        directive = directives[i];
6201        var attrStart = directive.$$start;
6202        var attrEnd = directive.$$end;
6203
6204        // collect multiblock sections
6205        if (attrStart) {
6206          $compileNode = groupScan(compileNode, attrStart, attrEnd);
6207        }
6208        $template = undefined;
6209
6210        if (terminalPriority > directive.priority) {
6211          break; // prevent further processing of directives
6212        }
6213
6214        if (directiveValue = directive.scope) {
6215          newScopeDirective = newScopeDirective || directive;
6216
6217          // skip the check for directives with async templates, we'll check the derived sync
6218          // directive when the template arrives
6219          if (!directive.templateUrl) {
6220            assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6221                              $compileNode);
6222            if (isObject(directiveValue)) {
6223              newIsolateScopeDirective = directive;
6224            }
6225          }
6226        }
6227
6228        directiveName = directive.name;
6229
6230        if (!directive.templateUrl && directive.controller) {
6231          directiveValue = directive.controller;
6232          controllerDirectives = controllerDirectives || {};
6233          assertNoDuplicate("'" + directiveName + "' controller",
6234              controllerDirectives[directiveName], directive, $compileNode);
6235          controllerDirectives[directiveName] = directive;
6236        }
6237
6238        if (directiveValue = directive.transclude) {
6239          hasTranscludeDirective = true;
6240
6241          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6242          // This option should only be used by directives that know how to safely handle element transclusion,
6243          // where the transcluded nodes are added or replaced after linking.
6244          if (!directive.$$tlb) {
6245            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6246            nonTlbTranscludeDirective = directive;
6247          }
6248
6249          if (directiveValue == 'element') {
6250            hasElementTranscludeDirective = true;
6251            terminalPriority = directive.priority;
6252            $template = groupScan(compileNode, attrStart, attrEnd);
6253            $compileNode = templateAttrs.$$element =
6254                jqLite(document.createComment(' ' + directiveName + ': ' +
6255                                              templateAttrs[directiveName] + ' '));
6256            compileNode = $compileNode[0];
6257            replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
6258
6259            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6260                                        replaceDirective && replaceDirective.name, {
6261                                          // Don't pass in:
6262                                          // - controllerDirectives - otherwise we'll create duplicates controllers
6263                                          // - newIsolateScopeDirective or templateDirective - comb
6263ining templates with
6264                                          //   element transclusion doesn't make sense.
6265                                          //
6266                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6267                                          // on the same element more than once.
6268                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
6269                                        });
6270          } else {
6271            $template = jqLite(jqLiteClone(compileNode)).contents();
6272            $compileNode.empty(); // clear contents
6273            childTranscludeFn = compile($template, transcludeFn);
6274          }
6275        }
6276
6277        if (directive.template) {
6278          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6279          templateDirective = directive;
6280
6281          directiveValue = (isFunction(directive.template))
6282              ? directive.template($compileNode, templateAttrs)
6283              : directive.template;
6284
6285          directiveValue = denormalizeTemplate(directiveValue);
6286
6287          if (directive.replace) {
6288            replaceDirective = directive;
6289            if (jqLiteIsTextNode(directiveValue)) {
6290              $template = [];
6291            } else {
6292              $template = jqLite(directiveValue);
6293            }
6294            compileNode = $template[0];
6295
6296            if ($template.length != 1 || compileNode.nodeType !== 1) {
6297              throw $compileMinErr('tplrt',
6298                  "Template for directive '{0}' must have exactly one root element. {1}",
6299                  directiveName, '');
6300            }
6301
6302            replaceWith(jqCollection, $compileNode, compileNode);
6303
6304            var newTemplateAttrs = {$attr: {}};
6305
6306            // combine directives from the original node and from the template:
6307            // - take the array of directives for this element
6308            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6309            // - collect directives from the template and sort them by priority
6310            // - combine directives as: processed + template + unprocessed
6311            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6312            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6313
6314            if (newIsolateScopeDirective) {
6315              markDirectivesAsIsolate(templateDirectives);
6316            }
6317            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6318            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6319
6320            ii = directives.length;
6321          } else {
6322            $compileNode.html(directiveValue);
6323          }
6324        }
6325
6326        if (directive.templateUrl) {
6327          assertNoDuplicate('template', templateDirective, directive, $compileNode);
6328          templateDirective = directive;
6329
6330          if (directive.replace) {
6331            replaceDirective = directive;
6332          }
6333
6334          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6335              templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
6336                controllerDirectives: controllerDirectives,
6337                newIsolateScopeDirective: newIsolateScopeDirective,
6338                templateDirective: templateDirective,
6339                nonTlbTranscludeDirective: nonTlbTranscludeDirective
6340              });
6341          ii = directives.length;
6342        } else if (directive.compile) {
6343          try {
6344            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6345            if (isFunction(linkFn)) {
6346              addLinkFns(null, linkFn, attrStart, attrEnd);
6347            } else if (linkFn) {
6348              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6349            }
6350          } catch (e) {
6351            $exceptionHandler(e, startingTag($compileNode));
6352          }
6353        }
6354
6355        if (directive.terminal) {
6356          nodeLinkFn.terminal = true;
6357          terminalPriority = Math.max(terminalPriority, directive.priority);
6358        }
6359
6360      }
6361
6362      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6363      nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6364      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6365
6366      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6367      return nodeLinkFn;
6368
6369      ////////////////////
6370
6371      function addLinkFns(pre, post, attrStart, attrEnd) {
6372        if (pre) {
6373          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6374          pre.require = directive.require;
6375          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6376            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6377          }
6378          preLinkFns.push(pre);
6379        }
6380        if (post) {
6381          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6382          post.require = directive.require;
6383          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6384            post = cloneAndAnnotateFn(post, {isolateScope: true});
6385          }
6386          postLinkFns.push(post);
6387        }
6388      }
6389
6390
6391      function getControllers(require, $element, elementControllers) {
6392        var value, retrievalMethod = 'data', optional = false;
6393        if (isString(require)) {
6394          while((value = require.charAt(0)) == '^' || value == '?') {
6395            require = require.substr(1);
6396            if (value == '^') {
6397              retrievalMethod = 'inheritedData';
6398            }
6399            optional = optional || value == '?';
6400          }
6401          value = null;
6402
6403          if (elementControllers && retrievalMethod === 'data') {
6404            value = elementControllers[require];
6405          }
6406          value = value || $element[retrievalMethod]('$' + require + 'Controller');
6407
6408          if (!value && !optional) {
6409            throw $compileMinErr('ctreq',
6410                "Controller '{0}', required by directive '{1}', can't be found!",
6411                require, directiveName);
6412          }
6413          return value;
6414        } else if (isArray(require)) {
6415          value = [];
6416          forEach(require, function(require) {
6417            value.push(getControllers(require, $element, elementControllers));
6418          });
6419        }
6420        return value;
6421      }
6422
6423
6424      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6425        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6426
6427        if (compileNode === linkNode) {
6428          attrs = templateAttrs;
6429        } else {
6430          attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6431        }
6432        $element = attrs.$$element;
6433
6434        if (newIsolateScopeDirective) {
6435          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6436          var $linkNode = jqLite(linkNode);
6437
6438          isolateScope = scope.$new(true);
6439
6440          if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6441            $linkNode.data('$isolateScope', isolateScope) ;
6442          } else {
6443            $linkNode.data('$isolateScopeNoTemplate', isolateScope);
6444          }
6445
6446
6447
6448          safeAddClass($linkNode, 'ng-isolate-scope');
6449
6450          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
6451            var match = definition.match(LOCAL_REGEXP) || [],
6452                attrName = match[3] || scopeName,
6453                optional = (match[2] == '?'),
6454                mode = match[1], // @, =, or &
6455                lastValue,
6456                parentGet, parentSet, compare;
6457
6458            isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6459
6460            switch (mode) {
6461
6462              case '@':
6463                attrs.$observe(attrName, function(value) {
6464                  isolateScope[scopeName] = value;
6465                });
6466                attrs.$$observers[attrName].$$scope = scope;
6467                if( attrs[attrName] ) {
6468                  // If the attribute has been provided then we trigger an interpolation to ensure
6469                  // the value is there for use in the link fn
6470                  isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6471                }
6472                break;
6473
6474              case '=':
6475                if (optional && !attrs[attrName]) {
6476                  return;
6477                }
6478                parentGet = $parse(attrs[attrName]);
6479                if (parentGet.literal) {
6480                  compare = equals;
6481                } else {
6482                  compare = function(a,b) { return a === b; };
6483                }
6484                parentSet = parentGet.assign || function() {
6485                  // reset the change, or we will throw this exception on every $digest
6486                  lastValue = isolateScope[scopeName] = parentGet(scope);
6487                  throw $compileMinErr('nonassign',
6488                      "Expression '{0}' used with directive '{1}' is non-assignable!",
6489                      attrs[attrName], newIsolateScopeDirective.name);
6490                };
6491                lastValue = isolateScope[scopeName] = parentGet(scope);
6492                isolateScope.$watch(function parentValueWatch() {
6493                  var parentValue = parentGet(scope);
6494                  if (!compare(parentValue, isolateScope[scopeName])) {
6495                    // we are out of sync and need to copy
6496                    if (!compare(parentValue, lastValue)) {
6497                      // parent changed and it has precedence
6498                      isolateScope[scopeName] = parentValue;
6499                    } else {
6500                      // if the parent can be assigned then do so
6501                      parentSet(scope, parentValue = isolateScope[scopeName]);
6502                    }
6503                  }
6504                  return lastValue = parentValue;
6505                }, null, parentGet.literal);
6506                break;
6507
6508              case '&':
6509                parentGet = $parse(attrs[attrName]);
6510                isolateScope[scopeName] = function(locals) {
6511                  return parentGet(scope, locals);
6512                };
6513                break;
6514
6515              default:
6516                throw $compileMinErr('iscp',
6517                    "Invalid isolate scope definition for directive '{0}'." +
6518                    " Definition: {... {1}: '{2}' ...}",
6519                    newIsolateScopeDirective.name, scopeName, definition);
6520            }
6521          });
6522        }
6523        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6524        if (controllerDirectives) {
6525          forEach(controllerDirectives, function(directive) {
6526            var locals = {
6527              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6528              $element: $element,
6529              $attrs: attrs,
6530              $transclude: transcludeFn
6531            }, controllerInstance;
6532
6533            controller = directive.controller;
6534            if (controller == '@') {
6535              controller = attrs[directive.name];
6536            }
6537
6538            controllerInstance = $controller(controller, locals);
6539            // For directives with element transclusion the element is a comment,
6540            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6541            // clean up (http://bugs.jquery.com/ticket/8335).
6542            // Instead, we save the controllers for the element in a local hash and attach to .data
6543            // later, once we have the actual element.
6544            elementControllers[directive.name] = controllerInstance;
6545            if (!hasElementTranscludeDirective) {
6546              $element.data('$' + directive.name + 'Controller', controllerInstance);
6547            }
6548
6549            if (directive.controllerAs) {
6550              locals.$scope[directive.controllerAs] = controllerInstance;
6551            }
6552          });
6553        }
6554
6555        // PRELINKING
6556        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
6557          try {
6558            linkFn = preLinkFns[i];
6559            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6560                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6561          } catch (e) {
6562            $exceptionHandler(e, startingTag($element));
6563          }
6564        }
6565
6566        // RECURSION
6567        // We only pass the isolate scope, if the isolate directive has a template,
6568        // otherwise the child elements do not belong to the isolate directive.
6569        var scopeToChild = scope;
6570        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6571          scopeToChild = isolateScope;
6572        }
6573        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6574
6575        // POSTLINKING
6576        for(i = postLinkFns.length - 1; i >= 0; i--) {
6577          try {
6578            linkFn = postLinkFns[i];
6579            linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6580                linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6581          } catch (e) {
6582            $exceptionHandler(e, startingTag($element));
6583          }
6584        }
6585
6586        // This is the function that is injected as `$transclude`.
6587        function controllersBoundTransclude(scope, cloneAttachFn) {
6588          var transcludeControllers;
6589
6590          // no scope passed
6591          if (arguments.length < 2) {
6592            cloneAttachFn = scope;
6593            scope = undefined;
6594          }
6595
6596          if (hasElementTranscludeDirective) {
6597            transcludeControllers = elementControllers;
6598          }
6599
6600          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6601        }
6602      }
6603    }
6604
6605    function markDirectivesAsIsolate(directives) {
6606      // mark all directives as needing isolate scope.
6607      for (var j = 0, jj = directives.length; j < jj; j++) {
6608        directives[j] = inherit(directives[j], {$$isolateScope: true});
6609      }
6610    }
6611
6612    /**
6613     * looks up the directive and decorates it with exception handling and proper parameters. We
6614     * call this the boundDirective.
6615     *
6616     * @param {string} name name of the directive to look up.
6617     * @param {string} location The directive must be found in specific format.
6618     *   String containing any of theses characters:
6619     *
6620     *   * `E`: element name
6621     *   * `A': attribute
6622     *   * `C`: class
6623     *   * `M`: comment
6624     * @returns {boolean} true if directive was added.
6625     */
6626    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
6627                          endAttrName) {
6628      if (name === ignoreDirective) return null;
6629      var match = null;
6630      if (hasDirectives.hasOwnProperty(name)) {
6631        for(var directive, directives = $injector.get(name + Suffix),
6632            i = 0, ii = directives.length; i<ii; i++) {
6633          try {
6634            directive = directives[i];
6635            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
6636                 directive.restrict.indexOf(location) != -1) {
6637              if (startAttrName) {
6638                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6639              }
6640              tDirectives.push(directive);
6641              match = directive;
6642            }
6643          } catch(e) { $exceptionHandler(e); }
6644        }
6645      }
6646      return match;
6647    }
6648
6649
6650    /**
6651     * When the element is replaced with HTML template then the new attributes
6652     * on the template need to be merged with the existing attributes in the DOM.
6653     * The desired effect is to have both of the attributes present.
6654     *
6655     * @param {object} dst destination attributes (original DOM)
6656     * @param {object} src source attributes (from the directive template)
6657     */
6658    function mergeTemplateAttributes(dst, src) {
6659      var srcAttr = src.$attr,
6660          dstAttr = dst.$attr,
6661          $element = dst.$$element;
6662
6663      // reapply the old attributes to the new element
6664      forEach(dst, function(value, key) {
6665        if (key.charAt(0) != '$') {
6666          if (src[key]) {
6667            value += (key === 'style' ? ';' : ' ') + src[key];
6668          }
6669          dst.$set(key, value, true, srcAttr[key]);
6670        }
6671      });
6672
6673      // copy the new attributes on the old attrs object
6674      forEach(src, function(value, key) {
6675        if (key == 'class') {
6676          safeAddClass($element, value);
6677          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6678        } else if (key == 'style') {
6679          $element.attr('style', $element.attr('style') + ';' + value);
6680          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6681          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6682          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6683          // have an attribute like "has-own-property" or "data-has-own-property", etc.
6684        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6685          dst[key] = value;
6686          dstAttr[key] = srcAttr[key];
6687        }
6688      });
6689    }
6690
6691
6692    function compileTemplateUrl(directives, $compileNode, tAttrs,
6693        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6694      var linkQueue = [],
6695          afterTemplateNodeLinkFn,
6696          afterTemplateChildLinkFn,
6697          beforeTemplateCompileNode = $compileNode[0],
6698          origAsyncDirective = directives.shift(),
6699          // The fact that we have to copy and patch the directive seems wrong!
6700          derivedSyncDirective = extend({}, origAsyncDirective, {
6701            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6702          }),
6703          templateUrl = (isFunction(origAsyncDirective.templateUrl))
6704              ? origAsyncDirective.templateUrl($compileNode, tAttrs
6704)
6705              : origAsyncDirective.templateUrl;
6706
6707      $compileNode.empty();
6708
6709      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6710        success(function(content) {
6711          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6712
6713          content = denormalizeTemplate(content);
6714
6715          if (origAsyncDirective.replace) {
6716            if (jqLiteIsTextNode(content)) {
6717              $template = [];
6718            } else {
6719              $template = jqLite(content);
6720            }
6721            compileNode = $template[0];
6722
6723            if ($template.length != 1 || compileNode.nodeType !== 1) {
6724              throw $compileMinErr('tplrt',
6725                  "Template for directive '{0}' must have exactly one root element. {1}",
6726                  origAsyncDirective.name, templateUrl);
6727            }
6728
6729            tempTemplateAttrs = {$attr: {}};
6730            replaceWith($rootElement, $compileNode, compileNode);
6731            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6732
6733            if (isObject(origAsyncDirective.scope)) {
6734              markDirectivesAsIsolate(templateDirectives);
6735            }
6736            directives = templateDirectives.concat(directives);
6737            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6738          } else {
6739            compileNode = beforeTemplateCompileNode;
6740            $compileNode.html(content);
6741          }
6742
6743          directives.unshift(derivedSyncDirective);
6744
6745          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6746              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6747              previousCompileContext);
6748          forEach($rootElement, function(node, i) {
6749            if (node == compileNode) {
6750              $rootElement[i] = $compileNode[0];
6751            }
6752          });
6753          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6754
6755
6756          while(linkQueue.length) {
6757            var scope = linkQueue.shift(),
6758                beforeTemplateLinkNode = linkQueue.shift(),
6759                linkRootElement = linkQueue.shift(),
6760                boundTranscludeFn = linkQueue.shift(),
6761                linkNode = $compileNode[0];
6762
6763            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6764              var oldClasses = beforeTemplateLinkNode.className;
6765
6766              if (!(previousCompileContext.hasElementTranscludeDirective &&
6767                  origAsyncDirective.replace)) {
6768                // it was cloned therefore we have to clone as well.
6769                linkNode = jqLiteClone(compileNode);
6770              }
6771
6772              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6773
6774              // Copy in CSS classes from original node
6775              safeAddClass(jqLite(linkNode), oldClasses);
6776            }
6777            if (afterTemplateNodeLinkFn.transclude) {
6778              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6779            } else {
6780              childBoundTranscludeFn = boundTranscludeFn;
6781            }
6782            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6783              childBoundTranscludeFn);
6784          }
6785          linkQueue = null;
6786        }).
6787        error(function(response, code, headers, config) {
6788          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6789        });
6790
6791      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6792        if (linkQueue) {
6793          linkQueue.push(scope);
6794          linkQueue.push(node);
6795          linkQueue.push(rootElement);
6796          linkQueue.push(boundTranscludeFn);
6797        } else {
6798          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6799        }
6800      };
6801    }
6802
6803
6804    /**
6805     * Sorting function for bound directives.
6806     */
6807    function byPriority(a, b) {
6808      var diff = b.priority - a.priority;
6809      if (diff !== 0) return diff;
6810      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6811      return a.index - b.index;
6812    }
6813
6814
6815    function assertNoDuplicate(what, previousDirective, directive, element) {
6816      if (previousDirective) {
6817        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6818            previousDirective.name, directive.name, what, startingTag(element));
6819      }
6820    }
6821
6822
6823    function addTextInterpolateDirective(directives, text) {
6824      var interpolateFn = $interpolate(text, true);
6825      if (interpolateFn) {
6826        directives.push({
6827          priority: 0,
6828          compile: valueFn(function textInterpolateLinkFn(scope, node) {
6829            var parent = node.parent(),
6830                bindings = parent.data('$binding') || [];
6831            bindings.push(interpolateFn);
6832            safeAddClass(parent.data('$binding', bindings), 'ng-binding');
6833            scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6834              node[0].nodeValue = value;
6835            });
6836          })
6837        });
6838      }
6839    }
6840
6841
6842    function getTrustedContext(node, attrNormalizedName) {
6843      if (attrNormalizedName == "srcdoc") {
6844        return $sce.HTML;
6845      }
6846      var tag = nodeName_(node);
6847      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6848      if (attrNormalizedName == "xlinkHref" ||
6849          (tag == "FORM" && attrNormalizedName == "action") ||
6850          (tag != "IMG" && (attrNormalizedName == "src" ||
6851                            attrNormalizedName == "ngSrc"))) {
6852        return $sce.RESOURCE_URL;
6853      }
6854    }
6855
6856
6857    function addAttrInterpolateDirective(node, directives, value, name) {
6858      var interpolateFn = $interpolate(value, true);
6859
6860      // no interpolation found -> ignore
6861      if (!interpolateFn) return;
6862
6863
6864      if (name === "multiple" && nodeName_(node) === "SELECT") {
6865        throw $compileMinErr("selmulti",
6866            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6867            startingTag(node));
6868      }
6869
6870      directives.push({
6871        priority: 100,
6872        compile: function() {
6873            return {
6874              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6875                var $$observers = (attr.$$observers || (attr.$$observers = {}));
6876
6877                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
6878                  throw $compileMinErr('nodomevents',
6879                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
6880                          "ng- versions (such as ng-click instead of onclick) instead.");
6881                }
6882
6883                // we need to interpolate again, in case the attribute value has been updated
6884                // (e.g. by another directive's compile function)
6885                interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
6886
6887                // if attribute was updated so that there is no interpolation going on we don't want to
6888                // register any observers
6889                if (!interpolateFn) return;
6890
6891                // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
6892                // actual attr value
6893                attr[name] = interpolateFn(scope);
6894                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6895                (attr.$$observers && attr.$$observers[name].$$scope || scope).
6896                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6897                    //special case for class attribute addition + removal
6898                    //so that class changes can tap into the animation
6899                    //hooks provided by the $animate service. Be sure to
6900                    //skip animations when the first digest occurs (when
6901                    //both the new and the old values are the same) since
6902                    //the CSS classes are the non-interpolated values
6903                    if(name === 'class' && newValue != oldValue) {
6904                      attr.$updateClass(newValue, oldValue);
6905                    } else {
6906                      attr.$set(name, newValue);
6907                    }
6908                  });
6909              }
6910            };
6911          }
6912      });
6913    }
6914
6915
6916    /**
6917     * This is a special jqLite.replaceWith, which can replace items which
6918     * have no parents, provided that the containing jqLite collection is provided.
6919     *
6920     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
6921     *                               in the root of the tree.
6922     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
6923     *                                  the shell, but replace its DOM node reference.
6924     * @param {Node} newNode The new DOM node.
6925     */
6926    function replaceWith($rootElement, elementsToRemove, newNode) {
6927      var firstElementToRemove = elementsToRemove[0],
6928          removeCount = elementsToRemove.length,
6929          parent = firstElementToRemove.parentNode,
6930          i, ii;
6931
6932      if ($rootElement) {
6933        for(i = 0, ii = $rootElement.length; i < ii; i++) {
6934          if ($rootElement[i] == firstElementToRemove) {
6935            $rootElement[i++] = newNode;
6936            for (var j = i, j2 = j + removeCount - 1,
6937                     jj = $rootElement.length;
6938                 j < jj; j++, j2++) {
6939              if (j2 < jj) {
6940                $rootElement[j] = $rootElement[j2];
6941              } else {
6942                delete $rootElement[j];
6943              }
6944            }
6945            $rootElement.length -= removeCount - 1;
6946            break;
6947          }
6948        }
6949      }
6950
6951      if (parent) {
6952        parent.replaceChild(newNode, firstElementToRemove);
6953      }
6954      var fragment = document.createDocumentFragment();
6955      fragment.appendChild(firstElementToRemove);
6956      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
6957      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
6958        var element = elementsToRemove[k];
6959        jqLite(element).remove(); // must do this way to clean up expando
6960        fragment.appendChild(element);
6961        delete elementsToRemove[k];
6962      }
6963
6964      elementsToRemove[0] = newNode;
6965      elementsToRemove.length = 1;
6966    }
6967
6968
6969    function cloneAndAnnotateFn(fn, annotation) {
6970      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
6971    }
6972  }];
6973}
6974
6975var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
6976/**
6977 * Converts all accepted directives format into proper directive name.
6978 * All of these will become 'myDirective':
6979 *   my:Directive
6980 *   my-directive
6981 *   x-my-directive
6982 *   data-my:directive
6983 *
6984 * Also there is special case for Moz prefix starting with upper case letter.
6985 * @param name Name to normalize
6986 */
6987function directiveNormalize(name) {
6988  return camelCase(name.replace(PREFIX_REGEXP, ''));
6989}
6990
6991/**
6992 * @ngdoc type
6993 * @name $compile.directive.Attributes
6994 *
6995 * @description
6996 * A shared object between directive compile / linking functions which contains 
6996normalized DOM
6997 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
6998 * needed since all of these are treated as equivalent in Angular:
6999 *
7000 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7001 */
7002
7003/**
7004 * @ngdoc property
7005 * @name $compile.directive.Attributes#$attr
7006 * @returns {object} A map of DOM element attribute names to the normalized name. This is
7007 *                   needed to do reverse lookup from normalized name back to actual name.
7008 */
7009
7010
7011/**
7012 * @ngdoc method
7013 * @name $compile.directive.Attributes#$set
7014 * @function
7015 *
7016 * @description
7017 * Set DOM element attribute value.
7018 *
7019 *
7020 * @param {string} name Normalized element attribute name of the property to modify. The name is
7021 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7022 *          property to the original name.
7023 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7024 */
7025
7026
7027
7028/**
7029 * Closure compiler type information
7030 */
7031
7032function nodesetLinkingFn(
7033  /* angular.Scope */ scope,
7034  /* NodeList */ nodeList,
7035  /* Element */ rootElement,
7036  /* function(Function) */ boundTranscludeFn
7037){}
7038
7039function directiveLinkingFn(
7040  /* nodesetLinkingFn */ nodesetLinkingFn,
7041  /* angular.Scope */ scope,
7042  /* Node */ node,
7043  /* Element */ rootElement,
7044  /* function(Function) */ boundTranscludeFn
7045){}
7046
7047function tokenDifference(str1, str2) {
7048  var values = '',
7049      tokens1 = str1.split(/\s+/),
7050      tokens2 = str2.split(/\s+/);
7051
7052  outer:
7053  for(var i = 0; i < tokens1.length; i++) {
7054    var token = tokens1[i];
7055    for(var j = 0; j < tokens2.length; j++) {
7056      if(token == tokens2[j]) continue outer;
7057    }
7058    values += (values.length > 0 ? ' ' : '') + token;
7059  }
7060  return values;
7061}
7062
7063/**
7064 * @ngdoc provider
7065 * @name $controllerProvider
7066 * @description
7067 * The {@link ng.$controller $controller service} is used by Angular to create new
7068 * controllers.
7069 *
7070 * This provider allows controller registration via the
7071 * {@link ng.$controllerProvider#register register} method.
7072 */
7073function $ControllerProvider() {
7074  var controllers = {},
7075      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7076
7077
7078  /**
7079   * @ngdoc method
7080   * @name $controllerProvider#register
7081   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7082   *    the names and the values are the constructors.
7083   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7084   *    annotations in the array notation).
7085   */
7086  this.register = function(name, constructor) {
7087    assertNotHasOwnProperty(name, 'controller');
7088    if (isObject(name)) {
7089      extend(controllers, name);
7090    } else {
7091      controllers[name] = constructor;
7092    }
7093  };
7094
7095
7096  this.$get = ['$injector', '$window', function($injector, $window) {
7097
7098    /**
7099     * @ngdoc service
7100     * @name $controller
7101     * @requires $injector
7102     *
7103     * @param {Function|string} constructor If called with a function then it's considered to be the
7104     *    controller constructor function. Otherwise it's considered to be a string which is used
7105     *    to retrieve the controller constructor using the following steps:
7106     *
7107     *    * check if a controller with given name is registered via `$controllerProvider`
7108     *    * check if evaluating the string on the current scope returns a constructor
7109     *    * check `window[constructor]` on the global `window` object
7110     *
7111     * @param {Object} locals Injection locals for Controller.
7112     * @return {Object} Instance of given controller.
7113     *
7114     * @description
7115     * `$controller` service is responsible for instantiating controllers.
7116     *
7117     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7118     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7119     */
7120    return function(expression, locals) {
7121      var instance, match, constructor, identifier;
7122
7123      if(isString(expression)) {
7124        match = expression.match(CNTRL_REG),
7125        constructor = match[1],
7126        identifier = match[3];
7127        expression = controllers.hasOwnProperty(constructor)
7128            ? controllers[constructor]
7129            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7130
7131        assertArgFn(expression, constructor, true);
7132      }
7133
7134      instance = $injector.instantiate(expression, locals);
7135
7136      if (identifier) {
7137        if (!(locals && typeof locals.$scope == 'object')) {
7138          throw minErr('$controller')('noscp',
7139              "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7140              constructor || expression.name, identifier);
7141        }
7142
7143        locals.$scope[identifier] = instance;
7144      }
7145
7146      return instance;
7147    };
7148  }];
7149}
7150
7151/**
7152 * @ngdoc service
7153 * @name $document
7154 * @requires $window
7155 *
7156 * @description
7157 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7158 *
7159 * @example
7160   <example>
7161     <file name="index.html">
7162       <div ng-controller="MainCtrl">
7163         <p>$document title: <b ng-bind="title"></b></p>
7164         <p>window.document title: <b ng-bind="windowTitle"></b></p>
7165       </div>
7166     </file>
7167     <file name="script.js">
7168       function MainCtrl($scope, $document) {
7169         $scope.title = $document[0].title;
7170         $scope.windowTitle = angular.element(window.document)[0].title;
7171       }
7172     </file>
7173   </example>
7174 */
7175function $DocumentProvider(){
7176  this.$get = ['$window', function(window){
7177    return jqLite(window.document);
7178  }];
7179}
7180
7181/**
7182 * @ngdoc service
7183 * @name $exceptionHandler
7184 * @requires ng.$log
7185 *
7186 * @description
7187 * Any uncaught exception in angular expressions is delegated to this service.
7188 * The default implementation simply delegates to `$log.error` which logs it into
7189 * the browser console.
7190 *
7191 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7192 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7193 *
7194 * ## Example:
7195 *
7196 * ```js
7197 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7198 *     return function (exception, cause) {
7199 *       exception.message += ' (caused by "' + cause + '")';
7200 *       throw exception;
7201 *     };
7202 *   });
7203 * ```
7204 *
7205 * This example will override the normal action of `$exceptionHandler`, to make angular
7206 * exceptions fail hard when they happen, instead of just logging to the console.
7207 *
7208 * @param {Error} exception Exception associated with the error.
7209 * @param {string=} cause optional information about the context in which
7210 *       the error was thrown.
7211 *
7212 */
7213function $ExceptionHandlerProvider() {
7214  this.$get = ['$log', function($log) {
7215    return function(exception, cause) {
7216      $log.error.apply($log, arguments);
7217    };
7218  }];
7219}
7220
7221/**
7222 * Parse headers into key value object
7223 *
7224 * @param {string} headers Raw headers as a string
7225 * @returns {Object} Parsed headers as key value object
7226 */
7227function parseHeaders(headers) {
7228  var parsed = {}, key, val, i;
7229
7230  if (!headers) return parsed;
7231
7232  forEach(headers.split('\n'), function(line) {
7233    i = line.indexOf(':');
7234    key = lowercase(trim(line.substr(0, i)));
7235    val = trim(line.substr(i + 1));
7236
7237    if (key) {
7238      if (parsed[key]) {
7239        parsed[key] += ', ' + val;
7240      } else {
7241        parsed[key] = val;
7242      }
7243    }
7244  });
7245
7246  return parsed;
7247}
7248
7249
7250/**
7251 * Returns a function that provides access to parsed headers.
7252 *
7253 * Headers are lazy parsed when first requested.
7254 * @see parseHeaders
7255 *
7256 * @param {(string|Object)} headers Headers to provide access to.
7257 * @returns {function(string=)} Returns a getter function which if called with:
7258 *
7259 *   - if called with single an argument returns a single header value or null
7260 *   - if called with no arguments returns an object containing all headers.
7261 */
7262function headersGetter(headers) {
7263  var headersObj = isObject(headers) ? headers : undefined;
7264
7265  return function(name) {
7266    if (!headersObj) headersObj =  parseHeaders(headers);
7267
7268    if (name) {
7269      return headersObj[lowercase(name)] || null;
7270    }
7271
7272    return headersObj;
7273  };
7274}
7275
7276
7277/**
7278 * Chain all given functions
7279 *
7280 * This function is used for both request and response transforming
7281 *
7282 * @param {*} data Data to transform.
7283 * @param {function(string=)} headers Http headers getter fn.
7284 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7285 * @returns {*} Transformed data.
7286 */
7287function transformData(data, headers, fns) {
7288  if (isFunction(fns))
7289    return fns(data, headers);
7290
7291  forEach(fns, function(fn) {
7292    data = fn(data, headers);
7293  });
7294
7295  return data;
7296}
7297
7298
7299function isSuccess(status) {
7300  return 200 <= status && status < 300;
7301}
7302
7303
7304function $HttpProvider() {
7305  var JSON_START = /^\s*(\[|\{[^\{])/,
7306      JSON_END = /[\}\]]\s*$/,
7307      PROTECTION_PREFIX = /^\)\]\}',?\n/,
7308      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7309
7310  var defaults = this.defaults = {
7311    // transform incoming response data
7312    transformResponse: [function(data) {
7313      if (isString(data)) {
7314        // strip json vulnerability protection prefix
7315        data = data.replace(PROTECTION_PREFIX, '');
7316        if (JSON_START.test(data) && JSON_END.test(data))
7317          data = fromJson(data);
7318      }
7319      return data;
7320    }],
7321
7322    // transform outgoing request data
7323    transformRequest: [function(d) {
7324      return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7325    }],
7326
7327    // default headers
7328    headers: {
7329      common: {
7330        'Accept': 'application/json, text/plain, */*'
7331      },
7332      post:   copy(CONTENT_TYPE_APPLICATION_JSON),
7333      put:    copy(CONTENT_TYPE_APPLICATION_JSON),
7334      patch:  copy(CONTENT_TYPE_APPLICATION_JSON)
7335    },
7336
7337    xsrfCookieName: 'XSRF-TOKEN',
7338    xsrfHeaderName: 'X-XSRF-TOKEN'
7339  };
7340
7341  /**
7342   * Are ordered by request, i.e. they are applied in the same order as the
7343   * array, on request, but reverse order, on response.
7344   */
7345  var interceptorFactories = this.interceptors = [];
7346
7347  /**
7348   * For historical reasons, response interceptors are ordered by the order in which
7349   * they are applied to the response. (This is the opposite of interceptorFactories)
7350   */
7351  var responseInterceptorFactories = this.responseInterceptors = [];
7352
7353  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7354      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7355
7356    var defaultCache = $cacheFactory('$http');
7357
7358    /**
7359     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7360     * The reversal is needed so that we can build up the interception chain around the
7361     * server request.
7362     */
7363    var reversedInterceptors = [];
7364
7365    forEach(interceptorFactories, function(interceptorFactory) {
7366      reversedInterceptors.unshift(isString(interceptorFactory)
7367          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7368    });
7369
7370    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
7371      var responseFn = isString(interceptorFactory)
7372          ? $injector.get(interceptorFactory)
7373          : $injector.invoke(interceptorFactory);
7374
7375      /**
7376       * Response interceptors go before "around" interceptors (no real reason, just
7377       * had to pick one.) But they are already reversed, so we can't use unshift, hence
7378       * the splice.
7379       */
7380      reversedInterceptors.splice(index, 0, {
7381        response: function(response) {
7382          return responseFn($q.when(response));
7383        },
7384        responseError: function(response) {
7385          return responseFn($q.reject(response));
7386        }
7387      });
7388    });
7389
7390
7391    /**
7392     * @ngdoc service
7393     * @kind function
7394     * @name $http
7395     * @requires ng.$httpBackend
7396     * @requires $cacheFactory
7397     * @requires $rootScope
7398     * @requires $q
7399     * @requires $injector
7400     *
7401     * @description
7402     * The `$http` service is a core Angular service that facilitates communication with the remote
7403     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7404     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7405     *
7406     * For unit testing applications that use `$http` service, see
7407     * {@link ngMock.$httpBackend $httpBackend mock}.
7408     *
7409     * For a higher level of abstraction, please check out the {@link ngResource.$resource
7410     * $resource} service.
7411     *
7412     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7413     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7414     * it is important to familiarize yourself with these APIs and the guarantees they provide.
7415     *
7416     *
7417     * # General usage
7418     * The `$http` service is a function which takes a single argument — a configuration object —
7419     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7420     * with two $http specific methods: `success` and `error`.
7421     *
7422     * ```js
7423     *   $http({method: 'GET', url: '/someUrl'}).
7424     *     success(function(data, status, headers, config) {
7425     *       // this callback will be called asynchronously
7426     *       // when the response is available
7427     *     }).
7428     *     error(function(data, status, headers, config) {
7429     *       // called asynchronously if an error occurs
7430     *       // or server returns response with an error status.
7431     *     });
7432     * ```
7433     *
7434     * Since the returned value of calling the $http function is a `promise`, you can also use
7435     * the `then` method to register callbacks, and these callbacks will receive a single argument –
7436     * an object representing the response. See the API signature and type info below for more
7437     * details.
7438     *
7439     * A response status code between 200 and 299 is considered a success status and
7440     * will result in the success callback being called. Note that if the response is a redirect,
7441     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7442     * called for such responses.
7443     *
7444     * # Writing Unit Tests that use $http
7445     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7446     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7447     * request using trained responses.
7448     *
7449     * ```
7450     * $httpBackend.expectGET(...);
7451     * $http.get(...);
7452     * $httpBackend.flush();
7453     * ```
7454     *
7455     * # Shortcut methods
7456     *
7457     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7458     * request data must be passed in for POST/PUT requests.
7459     *
7460     * ```js
7461     *   $http.get('/someUrl').success(successCallback);
7462     *   $http.post('/someUrl', data).success(successCallback);
7463     * ```
7464     *
7465     * Complete list of shortcut methods:
7466     *
7467     * - {@link ng.$http#get $http.get}
7468     * - {@link ng.$http#head $http.head}
7469     * - {@link ng.$http#post $http.post}
7470     * - {@link ng.$http#put $http.put}
7471     * - {@link ng.$http#delete $http.delete}
7472     * - {@link ng.$http#jsonp $http.jsonp}
7473     *
7474     *
7475     * # Setting HTTP Headers
7476     *
7477     * The $http service will automatically add certain HTTP headers to all requests. These defaults
7478     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7479     * object, which currently contains this default configuration:
7480     *
7481     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7482     *   - `Accept: application/json, text/plain, * / *`
7483     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7484     *   - `Content-Type: application/json`
7485     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7486     *   - `Content-Type: application/json`
7487     *
7488     * To add or overwrite these defaults, simply add or remove a property from these configuration
7489     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7490     * with the lowercased HTTP method name as the key, e.g.
7491     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7492     *
7493     * The defaults can also be set at runtime via the `$http.defaults` object in the same
7494     * fashion. For example:
7495     *
7496     * ```
7497     * module.run(function($http) {
7498     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7499     * });
7500     * ```
7501     *
7502     * In addition, you can supply a `headers` property in the config object passed when
7503     * calling `$http(config)`, which overrides the defaults without changing them globally.
7504     *
7505     *
7506     * # Transforming Requests and Responses
7507     *
7508     * Both requests and responses can be transformed using transform functions. By default, Angular
7509     * applies these transformations:
7510     *
7511     * Request transformations:
7512     *
7513     * - If the `data` property of the request configuration object contains an object, serialize it
7514     *   into JSON format.
7515     *
7516     * Response transformations:
7517     *
7518     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7519     *  - If JSON response is detected, deserialize it using a JSON parser.
7520     *
7521     * To globally augment or override the default transforms, modify the
7522     * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7523     * properties. These properties are by default an array of transform functions, which allows you
7524     * to `push` or `unshift` a new transformation function into the transformation chain. You can
7525     * also decide to completely override any default transformations by assigning your
7526     * transformation functions to these properties directly without the array wrapper.  These defaults
7527     * are again available on the $http factory at run-time, which may be useful if you have run-time
7528     * services you wish to be involved in your transformations.
7529     *
7530     * Similarly, to locally override the request/response transforms, augment the
7531     * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7532     * into `$http`.
7533     *
7534     *
7535     * # Caching
7536     *
7537     * To enable caching, set the request configuration `cache` property to `true` (to use default
7538     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7539     * When the cache is enabled, `$http` stores the response from the server in the specified
7540     * cache. The next time the same request is made, the response is served from the cache without
7541     * sending a request to the server.
7542     *
7543     * Note that even if the response is served from cache, delivery of the data is asynchronous in
7544     * the same way that real requests are.
7545     *
7546     * If there are multiple GET requests for the same URL that should be cached using the same
7547     * cache, but the cache is not populated yet, only one request to the server will be made and
7548     * the remaining requests will be fulfilled using the response from the first request.
7549     *
7550     * You can change the default cache to a new object (built with
7551     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7552     * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7553     * their `cache` property to `true` will now use this cache object.
7554     *
7555     * If you set the default cache to `false` then only requests that specify their own custom
7556     * cache object will be cached.
7557     *
7558     * # Interceptors
7559     *
7560     * Before you start creating interceptors, be sure to understand the
7561     * {@link ng.$q $q and deferred/promise APIs}.
7562     *
7563     * For purposes of global error handling, authentication, or any kind of synchronous or
7564     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7565     * able to intercept requests before they are handed to the server and
7566     * responses before they are handed over to the application code that
7567     * initiated these requests. The interceptors leverage the {@link ng.$q
7568     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7569     *
7570     * The interceptors are service factories that are registered with the `$httpProvider` by
7571     * adding them to the `$httpProvider.interceptors` array. The factory is called and
7572     * injected with dependencies (if specified) and returns the interceptor.
7573     *
7574     * There are two kinds of interceptors (and two kinds of rejection interceptors):
7575     *
7576     *   * `request`: interceptors get called with http `config` object. The function is free to
7577     *     modify the `config` or create a new one. The function needs to return the `config`
7578     *     directly or as a promise.
7579     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7580     *     resolved with a rejection.
7581     *   * `response`: interceptors get called with http `response` object. The function is free to
7582     *     modify the `response` or create a new one. The function needs to return the `response`
7583     *     directly or as a promise.
7584     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7585     *     resolved with a rejection.
7586     *
7587     *
7588     * ```js
7589     *   // register the interceptor as a service
7590     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7591     *     return {
7592     *       // optional method
7593     *       'request': function(config) {
7594     *         // do something on success
7595     *         return config || $q.when(config);
7596     *       },
7597     *
7598     *       // optional method
7599     *      'requestError': function(rejection) {
7600     *         // do something on error
7601     *         if (canRecover(rejection)) {
7602     *           return responseOrNewPromise
7603     *         }
7604     *         return $q.reject(rejection);
7605     *       },
7606     *
7607     *
7608     *
7609     *       // optional method
7610     *       'response': function(response) {
7611     *         // do something on success
7612     *         return response || $q.when(response);
7613     *       },
7614     *
7615     *       // optional method
7616     *      'responseError': function(rejection) {
7617     *         // do something on error
7618     *         if (canRecover(rejection)) {
7619     *           return responseOrNewPromise
7620     *         }
7621     *         return $q.reject(rejection);
7622     *       }
7623     *     };
7624     *   });
7625     *
7626     *   $httpProvider.interceptors.push('myHttpInterceptor');
7627     *
7628     *
7629     *   // alternatively, register the interceptor via an anonymous factory
7630     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7631     *     return {
7632     *      'request': function(config) {
7633     *          // same as above
7634     *       },
7635     *
7636     *       'response': function(response) {
7637     *          // same as above
7638     *       }
7639     *     };
7640     *   });
7641     * ```
7642     *
7643     * # Response interceptors (DEPRECATED)
7644     *
7645     * Before you start creating interceptors, be sure to understand the
7646     * {@link ng.$q $q and deferred/promise APIs}.
7647     *
7648     * For purposes of global error handling, authentication or any kind of synchronous or
7649     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7650     * responses for http requests before they are handed over to the application code that
7651     * initiated these requests. The response interceptors leverage the {@link ng.$q
7652     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7653     *
7654     * The interceptors are service factories that are registered with the $httpProvider by
7655     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7656     * injected with dependencies (if specified) and returns the interceptor  — a function that
7657     * takes a {@link ng.$q promise} and returns the original or a new promise.
7658     *
7659     * ```js
7660     *   // register the interceptor as a service
7661     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7662     *     return function(promise) {
7663     *       return promise.then(function(response) {
7664     *         // do something on success
7665     *         return response;
7666     *       }, function(response) {
7667     *         // do something on error
7668     *         if (canRecover(response)) {
7669     *           return responseOrNewPromise
7670     *         }
7671     *         return $q.reject(response);
7672     *       });
7673     *     }
7674     *   });
7675     *
7676     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7677     *
7678     *
7679     *   // register the interceptor via an anonymous factory
7680     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7681     *     return function(promise) {
7682     *       // same as above
7683     *     }
7684     *   });
7685     * ```
7686     *
7687     *
7688     * # Security Considerations
7689     *
7690     * When designing web applications, consider security threats from:
7691     *
7692     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7693     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7694     *
7695     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7696     * pre-configured with strategies that address these issues, but for this to work backend server
7697     * cooperation is required.
7698     *
7699     * ## JSON Vulnerability Protection
7700     *
7701     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7702     * allows third party website to turn your JSON resource URL into
7703     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7704     * counter this your server can prefix all JSON requests with following str
7704ing `")]}',\n"`.
7705     * Angular will automatically strip the prefix before processing it as JSON.
7706     *
7707     * For example if your server needs to return:
7708     * ```js
7709     * ['one','two']
7710     * ```
7711     *
7712     * which is vulnerable to attack, your server can return:
7713     * ```js
7714     * )]}',
7715     * ['one','two']
7716     * ```
7717     *
7718     * Angular will strip the prefix, before processing the JSON.
7719     *
7720     *
7721     * ## Cross Site Request Forgery (XSRF) Protection
7722     *
7723     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7724     * an unauthorized site can gain your user's private data. Angular provides a mechanism
7725     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7726     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7727     * JavaScript that runs on your domain could read the cookie, your server can be assured that
7728     * the XHR came from JavaScript running on your domain. The header will not be set for
7729     * cross-domain requests.
7730     *
7731     * To take advantage of this, your server needs to set a token in a JavaScript readable session
7732     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7733     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7734     * that only JavaScript running on your domain could have sent the request. The token must be
7735     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7736     * making up its own tokens). We recommend that the token is a digest of your site's
7737     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
7738     * for added security.
7739     *
7740     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7741     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7742     * or the per-request config object.
7743     *
7744     *
7745     * @param {object} config Object describing the request to be made and how it should be
7746     *    processed. The object has following properties:
7747     *
7748     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7749     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7750     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7751     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7752     *      JSONified.
7753     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7754     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7755     *      HTTP headers to send to the server. If the return value of a function is null, the
7756     *      header will not be sent.
7757     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7758     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7759     *    - **transformRequest** –
7760     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7761     *      transform function or an array of such functions. The transform function takes the http
7762     *      request body and headers and returns its transformed (typically serialized) version.
7763     *    - **transformResponse** –
7764     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7765     *      transform function or an array of such functions. The transform function takes the http
7766     *      response body and headers and returns its transformed (typically deserialized) version.
7767     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7768     *      GET request, otherwise if a cache instance built with
7769     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7770     *      caching.
7771     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7772     *      that should abort the request when resolved.
7773     *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
7774     *      XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5
7775     *      for more information.
7776     *    - **responseType** - `{string}` - see
7777     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
7778     *
7779     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7780     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7781     *   method takes two arguments a success and an error callback which will be called with a
7782     *   response object. The `success` and `error` methods take a single argument - a function that
7783     *   will be called when the request succeeds or fails respectively. The arguments passed into
7784     *   these functions are destructured representation of the response object passed into the
7785     *   `then` method. The response object has these properties:
7786     *
7787     *   - **data** – `{string|Object}` – The response body transformed with the transform
7788     *     functions.
7789     *   - **status** – `{number}` – HTTP status code of the response.
7790     *   - **headers** – `{function([headerName])}` – Header getter function.
7791     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7792     *   - **statusText** – `{string}` – HTTP status text of the response.
7793     *
7794     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7795     *   requests. This is primarily meant to be used for debugging purposes.
7796     *
7797     *
7798     * @example
7799<example>
7800<file name="index.html">
7801  <div ng-controller="FetchCtrl">
7802    <select ng-model="method">
7803      <option>GET</option>
7804      <option>JSONP</option>
7805    </select>
7806    <input type="text" ng-model="url" size="80"/>
7807    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7808    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7809    <button id="samplejsonpbtn"
7810      ng-click="updateModel('JSONP',
7811                    'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7812      Sample JSONP
7813    </button>
7814    <button id="invalidjsonpbtn"
7815      ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7816        Invalid JSONP
7817      </button>
7818    <pre>http status code: {{status}}</pre>
7819    <pre>http response data: {{data}}</pre>
7820  </div>
7821</file>
7822<file name="script.js">
7823  function FetchCtrl($scope, $http, $templateCache) {
7824    $scope.method = 'GET';
7825    $scope.url = 'http-hello.html';
7826
7827    $scope.fetch = function() {
7828      $scope.code = null;
7829      $scope.response = null;
7830
7831      $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7832        success(function(data, status) {
7833          $scope.status = status;
7834          $scope.data = data;
7835        }).
7836        error(function(data, status) {
7837          $scope.data = data || "Request failed";
7838          $scope.status = status;
7839      });
7840    };
7841
7842    $scope.updateModel = function(method, url) {
7843      $scope.method = method;
7844      $scope.url = url;
7845    };
7846  }
7847</file>
7848<file name="http-hello.html">
7849  Hello, $http!
7850</file>
7851<file name="protractor.js" type="protractor">
7852  var status = element(by.binding('status'));
7853  var data = element(by.binding('data'));
7854  var fetchBtn = element(by.id('fetchbtn'));
7855  var sampleGetBtn = element(by.id('samplegetbtn'));
7856  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
7857  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
7858
7859  it('should make an xhr GET request', function() {
7860    sampleGetBtn.click();
7861    fetchBtn.click();
7862    expect(status.getText()).toMatch('200');
7863    expect(data.getText()).toMatch(/Hello, \$http!/);
7864  });
7865
7866  it('should make a JSONP request to angularjs.org', function() {
7867    sampleJsonpBtn.click();
7868    fetchBtn.click();
7869    expect(status.getText()).toMatch('200');
7870    expect(data.getText()).toMatch(/Super Hero!/);
7871  });
7872
7873  it('should make JSONP request to invalid URL and invoke the error handler',
7874      function() {
7875    invalidJsonpBtn.click();
7876    fetchBtn.click();
7877    expect(status.getText()).toMatch('0');
7878    expect(data.getText()).toMatch('Request failed');
7879  });
7880</file>
7881</example>
7882     */
7883    function $http(requestConfig) {
7884      var config = {
7885        method: 'get',
7886        transformRequest: defaults.transformRequest,
7887        transformResponse: defaults.transformResponse
7888      };
7889      var headers = mergeHeaders(requestConfig);
7890
7891      extend(config, requestConfig);
7892      config.headers = headers;
7893      config.method = uppercase(config.method);
7894
7895      var xsrfValue = urlIsSameOrigin(config.url)
7896          ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
7897          : undefined;
7898      if (xsrfValue) {
7899        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
7900      }
7901
7902
7903      var serverRequest = function(config) {
7904        headers = config.headers;
7905        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
7906
7907        // strip content-type if data is undefined
7908        if (isUndefined(config.data)) {
7909          forEach(headers, function(value, header) {
7910            if (lowercase(header) === 'content-type') {
7911                delete headers[header];
7912            }
7913          });
7914        }
7915
7916        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
7917          config.withCredentials = defaults.withCredentials;
7918        }
7919
7920        // send request
7921        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
7922      };
7923
7924      var chain = [serverRequest, undefined];
7925      var promise = $q.when(config);
7926
7927      // apply interceptors
7928      forEach(reversedInterceptors, function(interceptor) {
7929        if (interceptor.request || interceptor.requestError) {
7930          chain.unshift(interceptor.request, interceptor.requestError);
7931        }
7932        if (interceptor.response || interceptor.responseError) {
7933          chain.push(interceptor.response, interceptor.responseError);
7934        }
7935      });
7936
7937      while(chain.length) {
7938        var thenFn = chain.shift();
7939        var rejectFn = chain.shift();
7940
7941        promise = promise.then(thenFn, rejectFn);
7942      }
7943
7944      promise.success = function(fn) {
7945        promise.then(function(response) {
7946          fn(response.data, response.status, response.headers, config);
7947        });
7948        return promise;
7949      };
7950
7951      promise.error = function(fn) {
7952        promise.then(null, function(response) {
7953          fn(response.data, response.status, response.headers, config);
7954        });
7955        return promise;
7956      };
7957
7958      return promise;
7959
7960      function transformResponse(response) {
7961        // make a copy since the response must be cacheable
7962        var resp = extend({}, response, {
7963          data: transformData(response.data, response.headers, config.transformResponse)
7964        });
7965        return (isSuccess(response.status))
7966          ? resp
7967          : $q.reject(resp);
7968      }
7969
7970      function mergeHeaders(config) {
7971        var defHeaders = defaults.headers,
7972            reqHeaders = extend({}, config.headers),
7973            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
7974
7975        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
7976
7977        // execute if header value is function
7978        execHeaders(defHeaders);
7979        execHeaders(reqHeaders);
7980
7981        // using for-in instead of forEach to avoid unecessary iteration after header has been found
7982        defaultHeadersIteration:
7983        for (defHeaderName in defHeaders) {
7984          lowercaseDefHeaderName = lowercase(defHeaderName);
7985
7986          for (reqHeaderName in reqHeaders) {
7987            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
7988              continue defaultHeadersIteration;
7989            }
7990          }
7991
7992          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
7993        }
7994
7995        return reqHeaders;
7996
7997        function execHeaders(headers) {
7998          var headerContent;
7999
8000          forEach(headers, function(headerFn, header) {
8001            if (isFunction(headerFn)) {
8002              headerContent = headerFn();
8003              if (headerContent != null) {
8004                headers[header] = headerContent;
8005              } else {
8006                delete headers[header];
8007              }
8008            }
8009          });
8010        }
8011      }
8012    }
8013
8014    $http.pendingRequests = [];
8015
8016    /**
8017     * @ngdoc method
8018     * @name $http#get
8019     *
8020     * @description
8021     * Shortcut method to perform `GET` request.
8022     *
8023     * @param {string} url Relative or absolute URL specifying the destination of the request
8024     * @param {Object=} config Optional configuration object
8025     * @returns {HttpPromise} Future object
8026     */
8027
8028    /**
8029     * @ngdoc method
8030     * @name $http#delete
8031     *
8032     * @description
8033     * Shortcut method to perform `DELETE` request.
8034     *
8035     * @param {string} url Relative or absolute URL specifying the destination of the request
8036     * @param {Object=} config Optional configuration object
8037     * @returns {HttpPromise} Future object
8038     */
8039
8040    /**
8041     * @ngdoc method
8042     * @name $http#head
8043     *
8044     * @description
8045     * Shortcut method to perform `HEAD` request.
8046     *
8047     * @param {string} url Relative or absolute URL specifying the destination of the request
8048     * @param {Object=} config Optional configuration object
8049     * @returns {HttpPromise} Future object
8050     */
8051
8052    /**
8053     * @ngdoc method
8054     * @name $http#jsonp
8055     *
8056     * @description
8057     * Shortcut method to perform `JSONP` request.
8058     *
8059     * @param {string} url Relative or absolute URL specifying the destination of the request.
8060     *                     Should contain `JSON_CALLBACK` string.
8061     * @param {Object=} config Optional configuration object
8062     * @returns {HttpPromise} Future object
8063     */
8064    createShortMethods('get', 'delete', 'head', 'jsonp');
8065
8066    /**
8067     * @ngdoc method
8068     * @name $http#post
8069     *
8070     * @description
8071     * Shortcut method to perform `POST` request.
8072     *
8073     * @param {string} url Relative or absolute URL specifying the destination of the request
8074     * @param {*} data Request content
8075     * @param {Object=} config Optional configuration object
8076     * @returns {HttpPromise} Future object
8077     */
8078
8079    /**
8080     * @ngdoc method
8081     * @name $http#put
8082     *
8083     * @description
8084     * Shortcut method to perform `PUT` request.
8085     *
8086     * @param {string} url Relative or absolute URL specifying the destination of the request
8087     * @param {*} data Request content
8088     * @param {Object=} config Optional configuration object
8089     * @returns {HttpPromise} Future object
8090     */
8091    createShortMethodsWithData('post', 'put');
8092
8093        /**
8094         * @ngdoc property
8095         * @name $http#defaults
8096         *
8097         * @description
8098         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8099         * default headers, withCredentials as well as request and response transformations.
8100         *
8101         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8102         */
8103    $http.defaults = defaults;
8104
8105
8106    return $http;
8107
8108
8109    function createShortMethods(names) {
8110      forEach(arguments, function(name) {
8111        $http[name] = function(url, config) {
8112          return $http(extend(config || {}, {
8113            method: name,
8114            url: url
8115          }));
8116        };
8117      });
8118    }
8119
8120
8121    function createShortMethodsWithData(name) {
8122      forEach(arguments, function(name) {
8123        $http[name] = function(url, data, config) {
8124          return $http(extend(config || {}, {
8125            method: name,
8126            url: url,
8127            data: data
8128          }));
8129        };
8130      });
8131    }
8132
8133
8134    /**
8135     * Makes the request.
8136     *
8137     * !!! ACCESSES CLOSURE VARS:
8138     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8139     */
8140    function sendReq(config, reqData, reqHeaders) {
8141      var deferred = $q.defer(),
8142          promise = deferred.promise,
8143          cache,
8144          cachedResp,
8145          url = buildUrl(config.url, config.params);
8146
8147      $http.pendingRequests.push(config);
8148      promise.then(removePendingReq, removePendingReq);
8149
8150
8151      if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
8152        cache = isObject(config.cache) ? config.cache
8153              : isObject(defaults.cache) ? defaults.cache
8154              : defaultCache;
8155      }
8156
8157      if (cache) {
8158        cachedResp = cache.get(url);
8159        if (isDefined(cachedResp)) {
8160          if (cachedResp.then) {
8161            // cached request has already been sent, but there is no response yet
8162            cachedResp.then(removePendingReq, removePendingReq);
8163            return cachedResp;
8164          } else {
8165            // serving from cache
8166            if (isArray(cachedResp)) {
8167              resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]);
8168            } else {
8169              resolvePromise(cachedResp, 200, {}, 'OK');
8170            }
8171          }
8172        } else {
8173          // put the promise for the non-transformed response into cache as a placeholder
8174          cache.put(url, promise);
8175        }
8176      }
8177
8178      // if we won't have the response in cache, send the request to the backend
8179      if (isUndefined(cachedResp)) {
8180        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8181            config.withCredentials, config.responseType);
8182      }
8183
8184      return promise;
8185
8186
8187      /**
8188       * Callback registered to $httpBackend():
8189       *  - caches the response if desired
8190       *  - resolves the raw $http promise
8191       *  - calls $apply
8192       */
8193      function done(status, response, headersString, statusText) {
8194        if (cache) {
8195          if (isSuccess(status)) {
8196            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8197          } else {
8198            // remove promise from the cache
8199            cache.remove(url);
8200          }
8201        }
8202
8203        resolvePromise(response, status, headersString, statusText);
8204        if (!$rootScope.$$phase) $rootScope.$apply();
8205      }
8206
8207
8208      /**
8209       * Resolves the raw $http promise.
8210       */
8211      function resolvePromise(response, status, headers, statusText) {
8212        // normalize internal statuses to 0
8213        status = Math.max(status, 0);
8214
8215        (isSuccess(status) ? deferred.resolve : deferred.reject)({
8216          data: response,
8217          status: status,
8218          headers: headersGetter(headers),
8219          config: config,
8220          statusText : statusText
8221        });
8222      }
8223
8224
8225      function removePendingReq() {
8226        var idx = indexOf($http.pendingRequests, config);
8227        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8228      }
8229    }
8230
8231
8232    function buildUrl(url, params) {
8233          if (!params) return url;
8234          var parts = [];
8235          forEachSorted(params, function(value, key) {
8236            if (value === null || isUndefined(value)) return;
8237            if (!isArray(value)) value = [value];
8238
8239            forEach(value, function(v) {
8240              if (isObject(v)) {
8241                v = toJson(v);
8242              }
8243              parts.push(encodeUriQuery(key) + '=' +
8244                         encodeUriQuery(v));
8245            });
8246          });
8247          if(parts.length > 0) {
8248            url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8249          }
8250          return url;
8251        }
8252
8253
8254  }];
8255}
8256
8257function createXhr(method) {
8258    //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8259    //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8260    //if it is available
8261    if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) ||
8262      !window.XMLHttpRequest)) {
8263      return new window.ActiveXObject("Microsoft.XMLHTTP");
8264    } else if (window.XMLHttpRequest) {
8265      return new window.XMLHttpRequest();
8266    }
8267
8268    throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8269}
8270
8271/**
8272 * @ngdoc service
8273 * @name $httpBackend
8274 * @requires $window
8275 * @requires $document
8276 *
8277 * @description
8278 * HTTP backend used by the {@link ng.$http service} that delegates to
8279 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8280 *
8281 * You should never need to use this service directly, instead use the higher-level abstractions:
8282 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8283 *
8284 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8285 * $httpBackend} which can be trained with responses.
8286 */
8287function $HttpBackendProvider() {
8288  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
8289    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8290  }];
8291}
8292
8293function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8294  var ABORTED = -1;
8295
8296  // TODO(vojta): fix the signature
8297  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
8298    var status;
8299    $browser.$$incOutstandingRequestCount();
8300    url = url || $browser.url();
8301
8302    if (lowercase(method) == 'jsonp') {
8303      var callbackId = '_' + (callbacks.counter++).toString(36);
8304      callbacks[callbackId] = function(data) {
8305        callbacks[callbackId].data = data;
8306      };
8307
8308      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8309          function() {
8310        if (callbacks[callbackId].data) {
8311          completeRequest(callback, 200, callbacks[callbackId].data);
8312        } else {
8313          completeRequest(callback, status || -2);
8314        }
8315        callbacks[callbackId] = angular.noop;
8316      });
8317    } else {
8318
8319      var xhr = createXhr(method);
8320
8321      xhr.open(method, url, true);
8322      forEach(headers, function(value, key) {
8323        if (isDefined(value)) {
8324            xhr.setRequestHeader(key, value);
8325        }
8326      });
8327
8328      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8329      // response is in the cache. the promise api will ensure that to the app code the api is
8330      // always async
8331      xhr.onreadystatechange = function() {
8332        // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8333        // xhrs that are resolved while the app is in the background (see #5426).
8334        // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8335        // continuing
8336        //
8337        // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8338        // Safari respectively.
8339        if (xhr && xhr.readyState == 4) {
8340          var responseHeaders = null,
8341              response = null;
8342
8343          if(status !== ABORTED) {
8344            responseHeaders = xhr.getAllResponseHeaders();
8345
8346            // responseText is the old-school way of retrieving response 
8346(supported by IE8 & 9)
8347            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8348            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8349          }
8350
8351          completeRequest(callback,
8352              status || xhr.status,
8353              response,
8354              responseHeaders,
8355              xhr.statusText || '');
8356        }
8357      };
8358
8359      if (withCredentials) {
8360        xhr.withCredentials = true;
8361      }
8362
8363      if (responseType) {
8364        try {
8365          xhr.responseType = responseType;
8366        } catch (e) {
8367          // WebKit added support for the json responseType value on 09/03/2013
8368          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8369          // known to throw when setting the value "json" as the response type. Other older
8370          // browsers implementing the responseType
8371          //
8372          // The json response type can be ignored if not supported, because JSON payloads are
8373          // parsed on the client-side regardless.
8374          if (responseType !== 'json') {
8375            throw e;
8376          }
8377        }
8378      }
8379
8380      xhr.send(post || null);
8381    }
8382
8383    if (timeout > 0) {
8384      var timeoutId = $browserDefer(timeoutRequest, timeout);
8385    } else if (timeout && timeout.then) {
8386      timeout.then(timeoutRequest);
8387    }
8388
8389
8390    function timeoutRequest() {
8391      status = ABORTED;
8392      jsonpDone && jsonpDone();
8393      xhr && xhr.abort();
8394    }
8395
8396    function completeRequest(callback, status, response, headersString, statusText) {
8397      // cancel timeout and subsequent timeout promise resolution
8398      timeoutId && $browserDefer.cancel(timeoutId);
8399      jsonpDone = xhr = null;
8400
8401      // fix status code when it is 0 (0 status is undocumented).
8402      // Occurs when accessing file resources or on Android 4.1 stock browser
8403      // while retrieving files from application cache.
8404      if (status === 0) {
8405        status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8406      }
8407
8408      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8409      status = status === 1223 ? 204 : status;
8410      statusText = statusText || '';
8411
8412      callback(status, response, headersString, statusText);
8413      $browser.$$completeOutstandingRequest(noop);
8414    }
8415  };
8416
8417  function jsonpReq(url, done) {
8418    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8419    // - fetches local scripts via XHR and evals them
8420    // - adds and immediately removes script elements from the document
8421    var script = rawDocument.createElement('script'),
8422        doneWrapper = function() {
8423          script.onreadystatechange = script.onload = script.onerror = null;
8424          rawDocument.body.removeChild(script);
8425          if (done) done();
8426        };
8427
8428    script.type = 'text/javascript';
8429    script.src = url;
8430
8431    if (msie && msie <= 8) {
8432      script.onreadystatechange = function() {
8433        if (/loaded|complete/.test(script.readyState)) {
8434          doneWrapper();
8435        }
8436      };
8437    } else {
8438      script.onload = script.onerror = function() {
8439        doneWrapper();
8440      };
8441    }
8442
8443    rawDocument.body.appendChild(script);
8444    return doneWrapper;
8445  }
8446}
8447
8448var $interpolateMinErr = minErr('$interpolate');
8449
8450/**
8451 * @ngdoc provider
8452 * @name $interpolateProvider
8453 * @function
8454 *
8455 * @description
8456 *
8457 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8458 *
8459 * @example
8460<example module="customInterpolationApp">
8461<file name="index.html">
8462<script>
8463  var customInterpolationApp = angular.module('customInterpolationApp', []);
8464
8465  customInterpolationApp.config(function($interpolateProvider) {
8466    $interpolateProvider.startSymbol('//');
8467    $interpolateProvider.endSymbol('//');
8468  });
8469
8470
8471  customInterpolationApp.controller('DemoController', function DemoController() {
8472      this.label = "This binding is brought you by // interpolation symbols.";
8473  });
8474</script>
8475<div ng-app="App" ng-controller="DemoController as demo">
8476    //demo.label//
8477</div>
8478</file>
8479<file name="protractor.js" type="protractor">
8480  it('should interpolate binding with custom symbols', function() {
8481    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8482  });
8483</file>
8484</example>
8485 */
8486function $InterpolateProvider() {
8487  var startSymbol = '{{';
8488  var endSymbol = '}}';
8489
8490  /**
8491   * @ngdoc method
8492   * @name $interpolateProvider#startSymbol
8493   * @description
8494   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8495   *
8496   * @param {string=} value new value to set the starting symbol to.
8497   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8498   */
8499  this.startSymbol = function(value){
8500    if (value) {
8501      startSymbol = value;
8502      return this;
8503    } else {
8504      return startSymbol;
8505    }
8506  };
8507
8508  /**
8509   * @ngdoc method
8510   * @name $interpolateProvider#endSymbol
8511   * @description
8512   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8513   *
8514   * @param {string=} value new value to set the ending symbol to.
8515   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8516   */
8517  this.endSymbol = function(value){
8518    if (value) {
8519      endSymbol = value;
8520      return this;
8521    } else {
8522      return endSymbol;
8523    }
8524  };
8525
8526
8527  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
8528    var startSymbolLength = startSymbol.length,
8529        endSymbolLength = endSymbol.length;
8530
8531    /**
8532     * @ngdoc service
8533     * @name $interpolate
8534     * @function
8535     *
8536     * @requires $parse
8537     * @requires $sce
8538     *
8539     * @description
8540     *
8541     * Compiles a string with markup into an interpolation function. This service is used by the
8542     * HTML {@link ng.$compile $compile} service for data binding. See
8543     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8544     * interpolation markup.
8545     *
8546     *
8547     * ```js
8548     *   var $interpolate = ...; // injected
8549     *   var exp = $interpolate('Hello {{name | uppercase}}!');
8550     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8551     * ```
8552     *
8553     *
8554     * @param {string} text The text with markup to interpolate.
8555     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8556     *    embedded expression in order to return an interpolation function. Strings with no
8557     *    embedded expression will return null for the interpolation function.
8558     * @param {string=} trustedContext when provided, the returned function passes the interpolated
8559     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8560     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8561     *    provides Strict Contextual Escaping for details.
8562     * @returns {function(context)} an interpolation function which is used to compute the
8563     *    interpolated string. The function has these parameters:
8564     *
8565     *    * `context`: an object against which any expressions embedded in the strings are evaluated
8566     *      against.
8567     *
8568     */
8569    function $interpolate(text, mustHaveExpression, trustedContext) {
8570      var startIndex,
8571          endIndex,
8572          index = 0,
8573          parts = [],
8574          length = text.length,
8575          hasInterpolation = false,
8576          fn,
8577          exp,
8578          concat = [];
8579
8580      while(index < length) {
8581        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8582             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
8583          (index != startIndex) && parts.push(text.substring(index, startIndex));
8584          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8585          fn.exp = exp;
8586          index = endIndex + endSymbolLength;
8587          hasInterpolation = true;
8588        } else {
8589          // we did not find anything, so we have to add the remainder to the parts array
8590          (index != length) && parts.push(text.substring(index));
8591          index = length;
8592        }
8593      }
8594
8595      if (!(length = parts.length)) {
8596        // we added, nothing, must have been an empty string.
8597        parts.push('');
8598        length = 1;
8599      }
8600
8601      // Concatenating expressions makes it hard to reason about whether some combination of
8602      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8603      // single expression be used for iframe[src], object[src], etc., we ensure that the value
8604      // that's used is assigned or constructed by some JS code somewhere that is more testable or
8605      // make it obvious that you bound the value to some user controlled value.  This helps reduce
8606      // the load when auditing for XSS issues.
8607      if (trustedContext && parts.length > 1) {
8608          throw $interpolateMinErr('noconcat',
8609              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8610              "interpolations that concatenate multiple expressions when a trusted value is " +
8611              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8612      }
8613
8614      if (!mustHaveExpression  || hasInterpolation) {
8615        concat.length = length;
8616        fn = function(context) {
8617          try {
8618            for(var i = 0, ii = length, part; i<ii; i++) {
8619              if (typeof (part = parts[i]) == 'function') {
8620                part = part(context);
8621                if (trustedContext) {
8622                  part = $sce.getTrusted(trustedContext, part);
8623                } else {
8624                  part = $sce.valueOf(part);
8625                }
8626                if (part === null || isUndefined(part)) {
8627                  part = '';
8628                } else if (typeof part != 'string') {
8629                  part = toJson(part);
8630                }
8631              }
8632              concat[i] = part;
8633            }
8634            return concat.join('');
8635          }
8636          catch(err) {
8637            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8638                err.toString());
8639            $exceptionHandler(newErr);
8640          }
8641        };
8642        fn.exp = text;
8643        fn.parts = parts;
8644        return fn;
8645      }
8646    }
8647
8648
8649    /**
8650     * @ngdoc method
8651     * @name $interpolate#startSymbol
8652     * @description
8653     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8654     *
8655     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8656     * the symbol.
8657     *
8658     * @returns {string} start symbol.
8659     */
8660    $interpolate.startSymbol = function() {
8661      return startSymbol;
8662    };
8663
8664
8665    /**
8666     * @ngdoc method
8667     * @name $interpolate#endSymbol
8668     * @description
8669     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8670     *
8671     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8672     * the symbol.
8673     *
8674     * @returns {string} end symbol.
8675     */
8676    $interpolate.endSymbol = function() {
8677      return endSymbol;
8678    };
8679
8680    return $interpolate;
8681  }];
8682}
8683
8684function $IntervalProvider() {
8685  this.$get = ['$rootScope', '$window', '$q',
8686       function($rootScope,   $window,   $q) {
8687    var intervals = {};
8688
8689
8690     /**
8691      * @ngdoc service
8692      * @name $interval
8693      *
8694      * @description
8695      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8696      * milliseconds.
8697      *
8698      * The return value of registering an interval function is a promise. This promise will be
8699      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8700      * run indefinitely if `count` is not defined. The value of the notification will be the
8701      * number of iterations that have run.
8702      * To cancel an interval, call `$interval.cancel(promise)`.
8703      *
8704      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
8705      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8706      * time.
8707      *
8708      * <div class="alert alert-warning">
8709      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8710      * with them.  In particular they are not automatically destroyed when a controller's scope or a
8711      * directive's element are destroyed.
8712      * You should take this into consideration and make sure to always cancel the interval at the
8713      * appropriate moment.  See the example below for more details on how and when to do this.
8714      * </div>
8715      *
8716      * @param {function()} fn A function that should be called repeatedly.
8717      * @param {number} delay Number of milliseconds between each function call.
8718      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8719      *   indefinitely.
8720      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8721      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
8722      * @returns {promise} A promise which will be notified on each iteration.
8723      *
8724      * @example
8725      * <example module="time">
8726      *   <file name="index.html">
8727      *     <script>
8728      *       function Ctrl2($scope,$interval) {
8729      *         $scope.format = 'M/d/yy h:mm:ss a';
8730      *         $scope.blood_1 = 100;
8731      *         $scope.blood_2 = 120;
8732      *
8733      *         var stop;
8734      *         $scope.fight = function() {
8735      *           // Don't start a new fight if we are already fighting
8736      *           if ( angular.isDefined(stop) ) return;
8737      *
8738      *           stop = $interval(function() {
8739      *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8740      *                 $scope.blood_1 = $scope.blood_1 - 3;
8741      *                 $scope.blood_2 = $scope.blood_2 - 4;
8742      *             } else {
8743      *                 $scope.stopFight();
8744      *             }
8745      *           }, 100);
8746      *         };
8747      *
8748      *         $scope.stopFight = function() {
8749      *           if (angular.isDefined(stop)) {
8750      *             $interval.cancel(stop);
8751      *             stop = undefined;
8752      *           }
8753      *         };
8754      *
8755      *         $scope.resetFight = function() {
8756      *           $scope.blood_1 = 100;
8757      *           $scope.blood_2 = 120;
8758      *         }
8759      *
8760      *         $scope.$on('$destroy', function() {
8761      *           // Make sure that the interval is destroyed too
8762      *           $scope.stopFight();
8763      *         });
8764      *       }
8765      *
8766      *       angular.module('time', [])
8767      *         // Register the 'myCurrentTime' directive factory method.
8768      *         // We inject $interval and dateFilter service since the factory method is DI.
8769      *         .directive('myCurrentTime', function($interval, dateFilter) {
8770      *           // return the directive link function. (compile function not needed)
8771      *           return function(scope, element, attrs) {
8772      *             var format,  // date format
8773      *             stopTime; // so that we can cancel the time updates
8774      *
8775      *             // used to update the UI
8776      *             function updateTime() {
8777      *               element.text(dateFilter(new Date(), format));
8778      *             }
8779      *
8780      *             // watch the expression, and update the UI on change.
8781      *             scope.$watch(attrs.myCurrentTime, function(value) {
8782      *               format = value;
8783      *               updateTime();
8784      *             });
8785      *
8786      *             stopTime = $interval(updateTime, 1000);
8787      *
8788      *             // listen on DOM destroy (removal) event, and cancel the next UI update
8789      *             // to prevent updating time ofter the DOM element was removed.
8790      *             element.bind('$destroy', function() {
8791      *               $interval.cancel(stopTime);
8792      *             });
8793      *           }
8794      *         });
8795      *     </script>
8796      *
8797      *     <div>
8798      *       <div ng-controller="Ctrl2">
8799      *         Date format: <input ng-model="format"> <hr/>
8800      *         Current time is: <span my-current-time="format"></span>
8801      *         <hr/>
8802      *         Blood 1 : <font color='red'>{{blood_1}}</font>
8803      *         Blood 2 : <font color='red'>{{blood_2}}</font>
8804      *         <button type="button" data-ng-click="fight()">Fight</button>
8805      *         <button type="button" data-ng-click="stopFight()">StopFight</button>
8806      *         <button type="button" data-ng-click="resetFight()">resetFight</button>
8807      *       </div>
8808      *     </div>
8809      *
8810      *   </file>
8811      * </example>
8812      */
8813    function interval(fn, delay, count, invokeApply) {
8814      var setInterval = $window.setInterval,
8815          clearInterval = $window.clearInterval,
8816          deferred = $q.defer(),
8817          promise = deferred.promise,
8818          iteration = 0,
8819          skipApply = (isDefined(invokeApply) && !invokeApply);
8820
8821      count = isDefined(count) ? count : 0;
8822
8823      promise.then(null, null, fn);
8824
8825      promise.$$intervalId = setInterval(function tick() {
8826        deferred.notify(iteration++);
8827
8828        if (count > 0 && iteration >= count) {
8829          deferred.resolve(iteration);
8830          clearInterval(promise.$$intervalId);
8831          delete intervals[promise.$$intervalId];
8832        }
8833
8834        if (!skipApply) $rootScope.$apply();
8835
8836      }, delay);
8837
8838      intervals[promise.$$intervalId] = deferred;
8839
8840      return promise;
8841    }
8842
8843
8844     /**
8845      * @ngdoc method
8846      * @name $interval#cancel
8847      *
8848      * @description
8849      * Cancels a task associated with the `promise`.
8850      *
8851      * @param {promise} promise returned by the `$interval` function.
8852      * @returns {boolean} Returns `true` if the task was successfully canceled.
8853      */
8854    interval.cancel = function(promise) {
8855      if (promise && promise.$$intervalId in intervals) {
8856        intervals[promise.$$intervalId].reject('canceled');
8857        clearInterval(promise.$$intervalId);
8858        delete intervals[promise.$$intervalId];
8859        return true;
8860      }
8861      return false;
8862    };
8863
8864    return interval;
8865  }];
8866}
8867
8868/**
8869 * @ngdoc service
8870 * @name $locale
8871 *
8872 * @description
8873 * $locale service provides localization rules for various Angular components. As of right now the
8874 * only public api is:
8875 *
8876 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
8877 */
8878function $LocaleProvider(){
8879  this.$get = function() {
8880    return {
8881      id: 'en-us',
8882
8883      NUMBER_FORMATS: {
8884        DECIMAL_SEP: '.',
8885        GROUP_SEP: ',',
8886        PATTERNS: [
8887          { // Decimal Pattern
8888            minInt: 1,
8889            minFrac: 0,
8890            maxFrac: 3,
8891            posPre: '',
8892            posSuf: '',
8893            negPre: '-',
8894            negSuf: '',
8895            gSize: 3,
8896            lgSize: 3
8897          },{ //Currency Pattern
8898            minInt: 1,
8899            minFrac: 2,
8900            maxFrac: 2,
8901            posPre: '\u00A4',
8902            posSuf: '',
8903            negPre: '(\u00A4',
8904            negSuf: ')',
8905            gSize: 3,
8906            lgSize: 3
8907          }
8908        ],
8909        CURRENCY_SYM: '$'
8910      },
8911
8912      DATETIME_FORMATS: {
8913        MONTH:
8914            'January,February,March,April,May,June,July,August,September,October,November,December'
8915            .split(','),
8916        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
8917        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
8918        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
8919        AMPMS: ['AM','PM'],
8920        medium: 'MMM d, y h:mm:ss a',
8921        short: 'M/d/yy h:mm a',
8922        fullDate: 'EEEE, MMMM d, y',
8923        longDate: 'MMMM d, y',
8924        mediumDate: 'MMM d, y',
8925        shortDate: 'M/d/yy',
8926        mediumTime: 'h:mm:ss a',
8927        shortTime: 'h:mm a'
8928      },
8929
8930      pluralCat: function(num) {
8931        if (num === 1) {
8932          return 'one';
8933        }
8934        return 'other';
8935      }
8936    };
8937  };
8938}
8939
8940var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
8941    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
8942var $locationMinErr = minErr('$location');
8943
8944
8945/**
8946 * Encode path using encodeUriSegment, ignoring forward slashes
8947 *
8948 * @param {string} path Path to encode
8949 * @returns {string}
8950 */
8951function encodePath(path) {
8952  var segments = path.split('/'),
8953      i = segments.length;
8954
8955  while (i--) {
8956    segments[i] = encodeUriSegment(segments[i]);
8957  }
8958
8959  return segments.join('/');
8960}
8961
8962function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
8963  var parsedUrl = urlResolve(absoluteUrl, appBase);
8964
8965  locationObj.$$protocol = parsedUrl.protocol;
8966  locationObj.$$host = parsedUrl.hostname;
8967  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
8968}
8969
8970
8971function parseAppUrl(relativeUrl, locationObj, appBase) {
8972  var prefixed = (relativeUrl.charAt(0) !== '/');
8973  if (prefixed) {
8974    relativeUrl = '/' + relativeUrl;
8975  }
8976  var match = urlResolve(relativeUrl, appBase);
8977  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
8978      match.pathname.substring(1) : match.pathname);
8979  locationObj.$$search = parseKeyValue(match.search);
8980  locationObj.$$hash = decodeURIComponent(match.hash);
8981
8982  // make sure path starts with '/';
8983  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
8984    locationObj.$$path = '/' + locationObj.$$path;
8985  }
8986}
8987
8988
8989/**
8990 *
8991 * @param {string} begin
8992 * @param {string} whole
8993 * @returns {string} returns text from whole after begin or undefined if it does not begin with
8994 *                   expected string.
8995 */
8996function beginsWith(begin, whole) {
8997  if (whole.indexOf(begin) === 0) {
8998    return whole.substr(begin.length);
8999  }
9000}
9001
9002
9003function stripHash(url) {
9004  var index = url.indexOf('#');
9005  return index == -1 ? url : url.substr(0, index);
9006}
9007
9008
9009function stripFile(url) {
9010  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9011}
9012
9013/* return the server only (scheme://host:port) */
9014function serverBase(url) {
9015  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9016}
9017
9018
9019/**
9020 * LocationHtml5Url represents an url
9021 * This object is exposed as $location service when HTML5 mode is enabled and supported
9022 *
9023 * @constructor
9024 * @param {string} appBase application base URL
9025 * @param {string} basePrefix url path prefix
9026 */
9027function LocationHtml5Url(appBase, basePrefix) {
9028  this.$$html5 = true;
9029  basePrefix = basePrefix || '';
9030  var appBaseNoFile = stripFile(appBase);
9031  parseAbsoluteUrl(appBase, this, appBase);
9032
9033
9034  /**
9035   * Parse given html5 (regular) url string into properties
9036   * @param {string} newAbsoluteUrl HTML5 url
9037   * @private
9038   */
9039  this.$$parse = function(url) {
9040    var pathUrl = beginsWith(appBaseNoFile, url);
9041    if (!isString(pathUrl)) {
9042      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9043          appBaseNoFile);
9044    }
9045
9046    parseAppUrl(pathUrl, this, appBase);
9047
9048    if (!this.$$path) {
9049      this.$$path = '/';
9050    }
9051
9052    this.$$compose();
9053  };
9054
9055  /**
9056   * Compose url and update `absUrl` property
9057   * @private
9058   */
9059  this.$$compose = function() {
9060    var search = toKeyValue(this.$$search),
9061        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9062
9063    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9064    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9065  };
9066
9067  this.$$rewrite = function(url) {
9068    var appUrl, prevAppUrl;
9069
9070    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
9071      prevAppUrl = appUrl;
9072      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
9073        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9074      } else {
9075        return appBase + prevAppUrl;
9076      }
9077    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
9078      return appBaseNoFile + appUrl;
9079    } else if (appBaseNoFile == url + '/') {
9080      return appBaseNoFile;
9081    }
9082  };
9083}
9084
9085
9086/**
9087 * LocationHashbangUrl represents url
9088 * This object is exposed as $location service when developer doesn't opt into html5 mode.
9089 * It also serves as the base class for html5 mode fallback on legacy browsers.
9090 *
9091 * @constructor
9092 * @param {string} appBase application base URL
9093 * @param {string} hashPrefix hashbang prefix
9094 */
9095function LocationHashbangUrl(appBase, hashPrefix) {
9096  var appBaseNoFile = stripFile(appBase);
9097
9098  parseAbsoluteUrl(appBase, this, appBase);
9099
9100
9101  /**
9102   * Parse given hashbang url into properties
9103   * @param {string} url Hashbang url
9104   * @private
9105   */
9106  this.$$parse = function(url) {
9107    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9108    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9109        ? beginsWith(hashPrefix, withoutBaseUrl)
9110        : (this.$$html5)
9111          ? withoutBaseUrl
9112          : '';
9113
9114    if (!isString(withoutHashUrl)) {
9115      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9116          hashPrefix);
9117    }
9118    parseAppUrl(withoutHashUrl, this, appBase);
9119
9120    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9121
9122    this.$$compose();
9123
9124    /*
9125     * In Windows, on an anchor node on documents loaded from
9126     * the filesystem, the browser will return a pathname
9127     * prefixed with the drive name ('/C:/path') when a
9128     * pathname without a drive is set:
9129     *  * a.setAttribute('href', '/foo')
9130     *   * a.pathname === '/C:/foo' //true
9131     *
9132     * Inside of Angular, we're always using pathnames that
9133     * do not include drive names for routing.
9134     */
9135    function removeWindowsDriveName (path, url, base) {
9136      /*
9137      Matches paths for file protocol on windows,
9138      such as /C:/foo/bar, and captures only /foo/bar.
9139      */
9140      var windowsFilePathExp = /^\/?.*?:(\/.*)/;
9141
9142      var firstPathSegmentMatch;
9143
9144      //Get the relative path from the input URL.
9145      if (url.indexOf(base) === 0) {
9146        url = url.replace(base, '');
9147      }
9148
9149      /*
9150       * The input URL intentionally contains a
9151       * first path segment that ends with a colon.
9152       */
9153      if (windowsFilePathExp.exec(url)) {
9154        return path;
9155      }
9156
9157      firstPathSegmentMatch = windowsFilePathExp.exec(path);
9158      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9159    }
9160  };
9161
9162  /**
9163   * Compose hashbang url and update `absUrl` property
9164   * @private
9165   */
9166  this.$$compose = function() {
9167    var search = toKeyValue(this.$$search),
9168        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9169
9170    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9171    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9172  };
9173
9174  this.$$rewrite = function(url) {
9175    if(stripHash(appBase) == stripHash(url)) {
9176      return url;
9177    }
9178  };
9179}
9180
9181
9182/**
9183 * LocationHashbangUrl represents url
9184 * This object is exposed as $location service when html5 history api is enabled but the browser
9185 * does not support it.
9186 *
9187 * @constructor
9188 * @param {string} appBase application base URL
9189 * @param {string} hashPrefix hashbang prefix
9190 */
9191function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9192  this.$$html5 = true;
9193  LocationHashbangUrl.apply(this, arguments);
9194
9195  var appBaseNoFile = stripFile(appBase);
9196
9197  this.$$rewrite = function(url) {
9198    var appUrl;
9199
9200    if ( appBase == stripHash(url) ) {
9201      return url;
9202    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
9203      return appBase + hashPrefix + appUrl;
9204    } else if ( appBaseNoFile === url + '/') {
9205      return appBaseNoFile;
9206    }
9207  };
9208}
9209
9210
9211LocationHashbangInHtml5Url.prototype =
9212  LocationHashbangUrl.prototype =
9213  LocationHtml5Url.prototype = {
9214
9215  /**
9216   * Are we in html5 mode?
9217   * @private
9218   */
9219  $$html5: false,
9220
9221  /**
9222   * Has any change been replacing ?
9223   * @private
9224   */
9225  $$replace: false,
9226
9227  /**
9228   * @ngdoc method
9229   * @name $location#absUrl
9230   *
9231   * @description
9232   * This method is getter only.
9233   *
9234   * Return full url representation with all segments encoded according to rules specified in
9235   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9236   *
9237   * @return {string} full url
9238   */
9239  absUrl: locationGetter('$$absUrl'),
9240
9241  /**
9242   * @ngdoc method
9243   * @name $location#url
9244   *
9245   * @description
9246   * This method is getter / setter.
9247   *
9248   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9249   *
9250   * Change path, search and hash, when called with parameter and return `$location`.
9251   *
9252   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9253   * @param {string=} replace The path that will be changed
9254   * @return {string} url
9255   */
9256  url: function(url, replace) {
9257    if (isUndefined(url))
9258      return this.$$url;
9259
9260    var match = PATH_MATCH.exec(url);
9261    if (match[1]) this.path(decodeURIComponent(match[1]));
9262    if (match[2] || match[1]) this.search(match[3] || '');
9263    this.hash(match[5] || '', replace);
9264
9265    return this;
9266  },
9267
9268  /**
9269   * @ngdoc method
9270   * @name $location#protocol
9271   *
9272   * @description
9273   * This method is getter only.
9274   *
9275   * Return protocol of current url.
9276   *
9277   * @return {string} protocol of current url
9278   */
9279  protocol: locationGetter('$$protocol'),
9280
9281  /**
9282   * @ngdoc method
9283   * @name $location#host
9284   *
9285   * @description
9286   * This method is getter only.
9287   *
9288   * Return host of current url.
9289   *
9290   * @return {string} host of current url.
9291   */
9292  host: locationGetter('$$host'),
9293
9294  /**
9295   * @ngdoc method
9296   * @name $location#port
9297   *
9298   * @description
9299   * This method is getter only.
9300   *
9301   * Return port of current url.
9302   *
9303   * @return {Number} port
9304   */
9305  port: locationGetter('$$port'),
9306
9307  /**
9308   * @ngdoc method
9309   * @name $location#path
9310   *
9311   * @description
9312   * This method is getter / setter.
9313   *
9314   * Return path of current url when called without any parameter.
9315   *
9316   * Change path when called with parameter and return `$location`.
9317   *
9318   * Note: Path should always begin with forward slash (/), this method will add the forward slash
9319   * if it is missing.
9320   *
9321   * @param {string=} path New path
9322   * @return {string} path
9323   */
9324  path: locationGetterSetter('$$path', function(path) {
9325    return path.charAt(0) == '/' ? path : '/' + path;
9326  }),
9327
9328  /**
9329   * @ngdoc method
9330   * @name $location#search
9331   *
9332   * @description
9333   * This method is getter / setter.
9334   *
9335   * Return search part (as object) of current url when called without any parameter.
9336   *
9337   * Change search part when called with parameter and return `$location`.
9338   *
9339   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9340   * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
9341   * the url.
9342   *
9343   * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
9344   * single search parameter. If `paramValue` is an array, it will set the parameter as a
9345   * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
9346   *
9347   * @return {string} search
9348   */
9349  search: function(search, paramValue) {
9350    switch (arguments.length) {
9351      case 0:
9352        return this.$$search;
9353      case 1:
9354        if (isString(search)) {
9355          this.$$search = parseKeyValue(search);
9356        } else if (isObject(search)) {
9357          this.$$search = search;
9358        } else {
9359          throw $locationMinErr('isrcharg',
9360              'The first argument of the `$location#search()` call must be a string or an object.');
9361        }
9362        break;
9363      default:
9364        if (isUndefined(paramValue) || paramValue === null) {
9365          delete this.$$search[search];
vendor: 4,885 bytes, lines 9366-9534
9366        } else {
9367          this.$$search[search] = paramValue;
9368        }
9369    }
9370
9371    this.$$compose();
9372    return this;
9373  },
9374
9375  /**
9376   * @ngdoc method
9377   * @name $location#hash
9378   *
9379   * @description
9380   * This method is getter / setter.
9381   *
9382   * Return hash fragment when called without any parameter.
9383   *
9384   * Change hash fragment when called with parameter and return `$location`.
9385   *
9386   * @param {string=} hash New hash fragment
9387   * @return {string} hash
9388   */
9389  hash: locationGetterSetter('$$hash', identity),
9390
9391  /**
9392   * @ngdoc method
9393   * @name $location#replace
9394   *
9395   * @description
9396   * If called, all changes to $location during current `$digest` will be replacing current history
9397   * record, instead of adding new one.
9398   */
9399  replace: function() {
9400    this.$$replace = true;
9401    return this;
9402  }
9403};
9404
9405function locationGetter(property) {
9406  return function() {
9407    return this[property];
9408  };
9409}
9410
9411
9412function locationGetterSetter(property, preprocess) {
9413  return function(value) {
9414    if (isUndefined(value))
9415      return this[property];
9416
9417    this[property] = preprocess(value);
9418    this.$$compose();
9419
9420    return this;
9421  };
9422}
9423
9424
9425/**
9426 * @ngdoc service
9427 * @name $location
9428 *
9429 * @requires $rootElement
9430 *
9431 * @description
9432 * The $location service parses the URL in the browser address bar (based on the
9433 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9434 * available to your application. Changes to the URL in the address bar are reflected into
9435 * $location service and changes to $location are reflected into the browser address bar.
9436 *
9437 * **The $location service:**
9438 *
9439 * - Exposes the current URL in the browser address bar, so you can
9440 *   - Watch and observe the URL.
9441 *   - Change the URL.
9442 * - Synchronizes the URL with the browser when the user
9443 *   - Changes the address bar.
9444 *   - Clicks the back or forward button (or clicks a History link).
9445 *   - Clicks on a link.
9446 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9447 *
9448 * For more information see {@link guide/$location Developer Guide: Using $location}
9449 */
9450
9451/**
9452 * @ngdoc provider
9453 * @name $locationProvider
9454 * @description
9455 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9456 */
9457function $LocationProvider(){
9458  var hashPrefix = '',
9459      html5Mode = false;
9460
9461  /**
9462   * @ngdoc property
9463   * @name $locationProvider#hashPrefix
9464   * @description
9465   * @param {string=} prefix Prefix for hash part (containing path and search)
9466   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9467   */
9468  this.hashPrefix = function(prefix) {
9469    if (isDefined(prefix)) {
9470      hashPrefix = prefix;
9471      return this;
9472    } else {
9473      return hashPrefix;
9474    }
9475  };
9476
9477  /**
9478   * @ngdoc property
9479   * @name $locationProvider#html5Mode
9480   * @description
9481   * @param {boolean=} mode Use HTML5 strategy if available.
9482   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9483   */
9484  this.html5Mode = function(mode) {
9485    if (isDefined(mode)) {
9486      html5Mode = mode;
9487      return this;
9488    } else {
9489      return html5Mode;
9490    }
9491  };
9492
9493  /**
9494   * @ngdoc event
9495   * @name $location#$locationChangeStart
9496   * @eventType broadcast on root scope
9497   * @description
9498   * Broadcasted before a URL will change. This change can be prevented by calling
9499   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9500   * details about event object. Upon successful change
9501   * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9502   *
9503   * @param {Object} angularEvent Synthetic event object.
9504   * @param {string} newUrl New URL
9505   * @param {string=} oldUrl URL that was before it was changed.
9506   */
9507
9508  /**
9509   * @ngdoc event
9510   * @name $location#$locationChangeSuccess
9511   * @eventType broadcast on root scope
9512   * @description
9513   * Broadcasted after a URL was changed.
9514   *
9515   * @param {Object} angularEvent Synthetic event object.
9516   * @param {string} newUrl New URL
9517   * @param {string=} oldUrl URL that was before it was changed.
9518   */
9519
9520  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9521      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
9522    var $location,
9523        LocationMode,
9524        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9525        initialUrl = $browser.url(),
9526        appBase;
9527
9528    if (html5Mode) {
9529      appBase = serverBase(initialUrl) + (baseHref || '/');
9530      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9531    } else {
9532      appBase = stripHash(initialUrl);
9533      LocationMode = LocationHashbangUrl;
9534    }
9535    $location = new LocationMode(appBase, '#' + hashPrefix);
9536    $location.$$parse($location.$$rewrite(initialUrl));
9537
9538    $rootElement.on('click', function(event) {
9539      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9540      // currently we open nice url link and redirect then
9541
9542      if (event.ctrlKey || event.metaKey || event.which == 2) return;
9543
9544      var elm = jqLite(event.target);
9545
9546      // traverse the DOM up to find first A tag
9547      while (lowercase(elm[0].nodeName) !== 'a') {
9548        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9549        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9550      }
9551
9552      var absHref = elm.prop('href');
9553
9554      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9555        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9556        // an animation.
9557        absHref = urlResolve(absHref.animVal).href;
9558      }
9559
9560      var rewrittenUrl = $location.$$rewrite(absHref);
9561
9562      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9563        event.preventDefault();
9564        if (rewrittenUrl != $browser.url()) {
9565          // update location manually
9566          $location.$$parse(rewrittenUrl);
9567          $rootScope.$apply();
9568          // hack to work around FF6 bug 684208 when scenario runner clicks on links
9569          window.angular['ff-684208-preventDefault'] = true;
9570        }
9571      }
9572    });
9573
9574
9575    // rewrite hashbang url <> html5 url
9576    if ($location.absUrl() != initialUrl) {
9577      $browser.url($location.absUrl(), true);
9578    }
9579
9580    // update $location when $browser url changes
9581    $browser.onUrlChange(function(newUrl) {
9582      if ($location.absUrl() != newUrl) {
9583        $rootScope.$evalAsync(function() {
9584          var oldUrl = $location.absUrl();
9585
9586          $location.$$parse(newUrl);
9587          if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9588                                    oldUrl).defaultPrevented) {
9589            $location.$$parse(oldUrl);
9590            $browser.url(oldUrl);
9591          } else {
9592            afterLocationChange(oldUrl);
9593          }
9594        });
9595        if (!$rootScope.$$phase) $rootScope.$digest();
9596      }
9597    });
9598
9599    // update browser
9600    var changeCounter = 0;
9601    $rootScope.$watch(function $locationWatch() {
9602      var oldUrl = $browser.url();
9603      var currentReplace = $location.$$replace;
9604
9605      if (!changeCounter || oldUrl != $location.absUrl()) {
9606        changeCounter++;
9607        $rootScope.$evalAsync(function() {
9608          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9609              defaultPrevented) {
9610            $location.$$parse(oldUrl);
9611          } else {
9612            $browser.url($location.absUrl(), currentReplace);
9613            afterLocationChange(oldUrl);
9614          }
9615        });
9616      }
9617      $location.$$replace = false;
9618
9619      return changeCounter;
9620    });
9621
9622    return $location;
9623
9624    function afterLocationChange(oldUrl) {
9625      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9626    }
9627}];
9628}
9629
9630/**
9631 * @ngdoc service
9632 * @name $log
9633 * @requires $window
9634 *
9635 * @description
9636 * Simple service for logging. Default implementation safely writes the message
9637 * into the browser's console (if present).
9638 *
9639 * The main purpose of this service is to simplify debugging and troubleshooting.
9640 *
9641 * The default is to log `debug` messages. You can use
9642 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9643 *
9644 * @example
9645   <example>
9646     <file name="script.js">
9647       function LogCtrl($scope, $log) {
9648         $scope.$log = $log;
9649         $scope.message = 'Hello World!';
9650       }
9651     </file>
9652     <file name="index.html">
9653       <div ng-controller="LogCtrl">
9654         <p>Reload this page with open console, enter text and hit the log button...</p>
9655         Message:
9656         <input type="text" ng-model="message"/>
9657         <button ng-click="$log.log(message)">log</button>
9658         <button ng-click="$log.warn(message)">warn</button>
9659         <button ng-click="$log.info(message)">info</button>
9660         <button ng-click="$log.error(message)">error</button>
9661       </div>
9662     </file>
9663   </example>
9664 */
9665
9666/**
9667 * @ngdoc provider
9668 * @name $logProvider
9669 * @description
9670 * Use the `$logProvider` to configure how the application logs messages
9671 */
9672function $LogProvider(){
9673  var debug = true,
9674      self = this;
9675
9676  /**
9677   * @ngdoc property
9678   * @name $logProvider#debugEnabled
9679   * @description
9680   * @param {boolean=} flag enable or disable debug level messages
9681   * @returns {*} current value if used as getter or itself (chaining) if used as setter
9682   */
9683  this.debugEnabled = function(flag) {
9684    if (isDefined(flag)) {
9685      debug = flag;
9686    return this;
9687    } else {
9688      return debug;
9689    }
9690  };
9691
9692  this.$get = ['$window', function($window){
9693    return {
9694      /**
9695       * @ngdoc method
9696       * @name $log#log
9697       *
9698       * @description
9699       * Write a log message
9700       */
9701      log: consoleLog('log'),
9702
9703      /**
9704       * @ngdoc method
9705       * @name $log#info
9706       *
9707       * @description
9708       * Write an information message
9709       */
9710      info: consoleLog('info'),
9711
9712      /**
9713       * @ngdoc method
9714       * @name $log#warn
9715       *
9716       * @description
9717       * Write a warning message
9718       */
9719      warn: consoleLog('warn'),
9720
9721      /**
9722       * @ngdoc method
9723       * @name $log#error
9724       *
9725       * @description
9726       * Write an error message
9727       */
9728      error: consoleLog('error'),
9729
9730      /**
9731       * @ngdoc method
9732       * @name $log#debug
9733       *
9734       * @description
9735       * Write a debug message
9736       */
9737      debug: (function () {
9738        var fn = consoleLog('debug');
9739
9740        return function() {
9741          if (debug) {
9742            fn.apply(self, arguments);
9743          }
9744        };
9745      }())
9746    };
9747
9748    function formatError(arg) {
9749      if (arg instanceof Error) {
9750        if (arg.stack) {
9751          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
9752              ? 'Error: ' + arg.message + '\n' + arg.stack
9753              : arg.stack;
9754        } else if (arg.sourceURL) {
9755          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
9756        }
9757      }
9758      return arg;
9759    }
9760
9761    function consoleLog(type) {
9762      var console = $window.console || {},
9763          logFn = console[type] || console.log || noop,
9764          hasApply = false;
9765
9766      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
9767      // The reason behind this is that console.log has type "object" in IE8...
9768      try {
9769        hasApply = !!logFn.apply;
9770      } catch (e) {}
9771
9772      if (hasApply) {
9773        return function() {
9774          var args = [];
9775          forEach(arguments, function(arg) {
9776            args.push(formatError(arg));
9777          });
9778          return logFn.apply(console, args);
9779        };
9780      }
9781
9782      // we are IE which either doesn't have window.console => this is noop and we do nothing,
9783      // or we are IE where console.log doesn't have apply so we log at least first 2 args
9784      return function(arg1, arg2) {
9785        logFn(arg1, arg2 == null ? '' : arg2);
9786      };
9787    }
9788  }];
9789}
9790
9791var $parseMinErr = minErr('$parse');
9792var promiseWarningCache = {};
9793var promiseWarning;
9794
9795// Sandboxing Angular Expressions
9796// ------------------------------
9797// Angular expressions are generally considered safe because these expressions only have direct
9798// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9799// obtaining a reference to native JS functions such as the Function constructor.
9800//
9801// As an example, consider the following Angular expression:
9802//
9803//   {}.toString.constructor(alert("evil JS code"))
9804//
9805// We want to prevent this type of access. For the sake of performance, during the lexing phase we
9806// disallow any "dotted" access to any member named "constructor".
9807//
9808// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
9809// while evaluating the expression, which is a stronger but more expensive test. Since reflective
9810// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
9811//
9812// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9813// against the expression language, but not to prevent exploits that were enabled by exposing
9814// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
9815// practice and therefore we are not even trying to protect against interaction with an object
9816// explicitly exposed in this way.
9817//
9818// A developer could foil the name check by aliasing the Function constructor under a different
9819// name on the scope.
9820//
9821// In general, it is not possible to access a Window object from an angular expression unless a
9822// window or some DOM object that has a reference to window is published onto a Scope.
9823
9824function ensureSafeMemberName(name, fullExpression) {
9825  if (name === "constructor") {
9826    throw $parseMinErr('isecfld',
9827        'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
9828        fullExpression);
9829  }
9830  return name;
9831}
9832
9833function ensureSafeObject(obj, fullExpression) {
9834  // nifty check if obj is Function that is fast and works across iframes and other contexts
9835  if (obj) {
9836    if (obj.constructor === obj) {
9837      throw $parseMinErr('isecfn',
9838          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9839          fullExpression);
9840    } else if (// isWindow(obj)
9841        obj.document && obj.location && obj.alert && obj.setInterval) {
9842      throw $parseMinErr('isecwindow',
9843          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9844          fullExpression);
9845    } else if (// isElement(obj)
9846        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
9847      throw $parseMinErr('isecdom',
9848          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9849          fullExpression);
9850    }
9851  }
9852  return obj;
9853}
9854
9855var OPERATORS = {
9856    /* jshint bitwise : false */
9857    'null':function(){return null;},
9858    'true':function(){return true;},
9859    'false':function(){return false;},
9860    undefined:noop,
9861    '+':function(self, locals, a,b){
9862      a=a(self, locals); b=b(self, locals);
9863      if (isDefined(a)) {
9864        if (isDefined(b)) {
9865          return a + b;
9866        }
9867        return a;
9868      }
9869      return isDefined(b)?b:undefined;},
9870    '-':function(self, locals, a,b){
9871          a=a(self, locals); b=b(self, locals);
9872          return (isDefined(a)?a:0)-(isDefined(b)?b:0);
9873        },
9874    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
9875    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
9876    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
9877    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
9878    '=':noop,
9879    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
9880    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
9881    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
9882    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
9883    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
9884    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
9885    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
9886    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
9887    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
9888    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
9889    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
9890//    '|':function(self, locals, a,b){return a|b;},
9891    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
9892    '!':function(self, locals, a){return !a(self, locals);}
9893};
9894/* jshint bitwise: true */
9895var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
9896
9897
9898/////////////////////////////////////////
9899
9900
9901/**
9902 * @constructor
9903 */
9904var Lexer = function (options) {
9905  this.options = options;
9906};
9907
9908Lexer.prototype = {
9909  constructor: Lexer,
9910
9911  lex: function (text) {
9912    this.text = text;
9913
9914    this.index = 0;
9915    this.ch = undefined;
9916    this.lastCh = ':'; // can start regexp
9917
9918    this.tokens = [];
9919
9920    var token;
9921    var json = [];
9922
9923    while (this.index < this.text.length) {
9924      this.ch = this.text.charAt(this.index);
9925      if (this.is('"\'')) {
9926        this.readString(this.ch);
9927      } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
9928        this.readNumber();
9929      } else if (this.isIdent(this.ch)) {
9930        this.readIdent();
9931        // identifiers can only be if the preceding char was a { or ,
9932        if (this.was('{,') && json[0] === '{' &&
9933            (token = this.tokens[this.tokens.length - 1])) {
9934          token.json = token.text.indexOf('.') === -1;
9935        }
9936      } else if (this.is('(){}[].,;:?')) {
9937        this.tokens.push({
9938          index: this.index,
9939          text: this.ch,
9940          json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
9941        });
9942        if (this.is('{[')) json.unshift(this.ch);
9943        if (this.is('}]')) json.shift();
9944        this.index++;
9945      } else if (this.isWhitespace(this.ch)) {
9946        this.index++;
9947        continue;
9948      } else {
9949        var ch2 = this.ch + this.peek();
9950        var ch3 = ch2 + this.peek(2);
9951        var fn = OPERATORS[this.ch];
9952        var fn2 = OPERATORS[ch2];
9953        var fn3 = OPERATORS[ch3];
9954        if (fn3) {
9955          this.tokens.push({index: this.index, text: ch3, fn: fn3});
9956          this.index += 3;
9957        } else if (fn2) {
9958          this.tokens.push({index: this.index, text: ch2, fn: fn2});
9959          this.index += 2;
9960        } else if (fn) {
9961          this.tokens.push({
9962            index: this.index,
9963            text: this.ch,
9964            fn: fn,
9965            json: (this.was('[,:') && this.is('+-'))
9966          });
9967          this.index += 1;
9968        } else {
9969          this.throwError('Unexpected next character ', this.index, this.index + 1);
9970        }
9971      }
9972      this.lastCh = this.ch;
9973    }
9974    return this.tokens;
9975  },
9976
9977  is: function(chars) {
9978    return chars.indexOf(this.ch) !== -1;
9979  },
9980
9981  was: function(chars) {
9982    return chars.indexOf(this.lastCh) !== -1;
9983  },
9984
9985  peek: function(i) {
9986    var num = i || 1;
9987    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
9988  },
9989
9990  isNumber: function(ch) {
9991    return ('0' <= ch && ch <= '9');
9992  },
9993
9994  isWhitespace: function(ch) {
9995    // IE treats non-breaking space as \u00A0
9996    return (ch === ' ' || ch === '\r' || ch === '\t' ||
9997            ch === '\n' || ch === '\v' || ch === '\u00A0');
9998  },
9999
10000  isIdent: function(ch) {
10001    return ('a' <= ch && ch <= 'z' ||
10002            'A' <= ch && ch <= 'Z' ||
10003            '_' === ch || ch === '$');
10004  },
10005
10006  isExpOperator: function(ch) {
10007    return (ch === '-' || ch === '+' || this.isNumber(ch));
10008  },
10009
10010  throwError: function(error, start, end) {
10011    end = end || this.index;
10012    var colStr = (isDefined(start)
10013            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10014            : ' ' + end);
10015    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10016        error, colStr, this.text);
10017  },
10018
10019  readNumber: function() {
10020    var number = '';
10021    var start = this.index;
10022    while (this.index < this.text.length) {
10023      var ch = lowercase(this.text.charAt(this.index));
10024      if (ch == '.' || this.isNumber(ch)) {
10025        number += ch;
10026      } else {
10027        var peekCh = this.peek();
10028        if (ch == 'e' && this.isExpOperator(peekCh)) {
10029          number += ch;
10030        } else if (this.isExpOperator(ch) &&
10031            peekCh && this.isNumber(peekCh) &&
10032            number.charAt(number.length - 1) == 'e') {
10033          number += ch;
10034        } else if (this.isExpOperator(ch) &&
10035            (!peekCh || !this.isNumber(peekCh)) &&
10036            number.charAt(number.length - 1) == 'e') {
10037          this.throwError('Invalid exponent');
10038        } else {
10039          break;
10040        }
10041      }
10042      this.index++;
10043    }
10044    number = 1 * number;
10045    this.tokens.push({
10046      index: start,
10047      text: number,
10048      json: true,
10049      fn: function() { return number; }
10050    });
10051  },
10052
10053  readIdent: function() {
10054    var parser = this;
10055
10056    var ident = '';
10057    var start = this.index;
10058
10059    var lastDot, peekIndex, methodName, ch;
10060
10061    while (this.index < this.text.length) {
10062      ch = this.text.charAt(this.index);
10063      if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10064        if (ch === '.') lastDot = this.index;
10065        ident += ch;
10066      } else {
10067        break;
10068      }
10069      this.index++;
10070    }
10071
10072    //check if this is not a method invocation and if it is back out to last dot
10073    if (lastDot) {
10074      peekIndex = this.index;
10075      while (peekIndex < this.text.length) {
10076        ch = this.text.charAt(peekIndex);
10077        if (ch === '(') {
10078          methodName = ident.substr(lastDot - start + 1);
10079          ident = ident.substr(0, lastDot - start);
10080          this.index = peekIndex;
10081          break;
10082        }
10083        if (this.isWhitespace(ch)) {
10084          peekIndex++;
10085        } else {
10086          break;
10087        }
10088      }
10089    }
10090
10091
10092    var token = {
10093      index: start,
10094      text: ident
10095    };
10096
10097    // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10098    if (OPERATORS.hasOwnProperty(ident)) {
10099      token.fn = OPERATORS[ident];
10100      token.json = OPERATORS[ident];
10101    } else {
10102      var getter = getterFn(ident, this.options, this.text);
10103      token.fn = extend(function(self, locals) {
10104        return (getter(self, locals));
10105      }, {
10106        assign: function(self, value) {
10107          return setter(self, ident, value, parser.text, parser.options);
10108        }
10109      });
10110    }
10111
10112    this.tokens.push(token);
10113
10114    if (methodName) {
10115      this.tokens.push({
10116        index:lastDot,
10117        text: '.',
10118        json: false
10119      });
10120      this.tokens.push({
10121        index: lastDot + 1,
10122        text: methodName,
10123        json: false
10124      });
10125    }
10126  },
10127
10128  readString: function(quote) {
10129    var start = this.index;
10130    this.index++;
10131    var string = '';
10132    var rawString = quote;
10133    var escape = false;
10134    while (this.index < this.text.length) {
10135      var ch = this.text.charAt(this.index);
10136      rawString += ch;
10137      if (escape) {
10138        if (ch === 'u') {
10139          var hex = this.text.substring(this.index + 1, this.index + 5);
10140          if (!hex.match(/[\da-f]{4}/i))
10141            this.throwError('Invalid unicode escape [\\u' + hex + ']');
10142          this.index += 4;
10143          string += String.fromCharCode(parseInt(hex, 16));
10144        } else {
10145          var rep = ESCAPE[ch];
10146          if (rep) {
10147            string += rep;
10148          } else {
10149            string += ch;
10150          }
10151        }
10152        escape = false;
10153      } else if (ch === '\\') {
10154        escape = true;
10155      } else if (ch === quote) {
10156        this.index++;
10157        this.tokens.push({
10158          index: start,
10159          text: rawString,
10160          string: string,
10161          json: true,
10162          fn: function() { return string; }
10163        });
10164        return;
10165      } else {
10166        string += ch;
10167      }
10168      this.index++;
10169    }
10170    this.throwError('Unterminated quote', start);
10171  }
10172};
10173
10174
10175/**
10176 * @constructor
10177 */
10178var Parser = function (lexer, $filter, options) {
10179  this.lexer = lexer;
10180  this.$filter = $filter;
10181  this.options = options;
10182};
10183
10184Parser.ZERO = extend(function () {
10185  return 0;
10186}, {
10187  constant: true
10188});
10189
10190Parser.prototype = {
10191  constructor: Parser,
10192
10193  parse: function (text, json) {
10194    this.text = text;
10195
10196    //TODO(i): strip all the obsolte json stuff from this file
10197    this.json = json;
10198
10199    this.tokens = this.lexer.lex(text);
10200
10201    if (json) {
10202      // The extra level of aliasing is here, just in case the lexer misses something, so that
10203      // we prevent any accidental execution in JSON.
10204      this.assignment = this.logicalOR;
10205
10206      this.functionCall =
10207      this.fieldAccess =
10208      this.objectIndex =
10209      this.filterChain = function() {
10210        this.throwError('is not valid json', {text: text, index: 0});
10211      };
10212    }
10213
10214    var value = json ? this.primary() : this.statements();
10215
10216    if (this.tokens.length !== 0) {
10217      this.throwError('is an unexpected token', this.tokens[0]);
10218    }
10219
10220    value.literal = !!value.literal;
10221    value.constant = !!value.constant;
10222
10223    return value;
10224  },
10225
10226  primary: function () {
10227    var primary;
10228    if (this.expect('(')) {
10229      primary = this.filterChain();
10230      this.consume(')');
10231    } else if (this.expect('[')) {
10232      primary = this.arrayDeclaration();
10233    } else if (this.expect('{')) {
10234      primary = this.object();
10235    } else {
10236      var token = this.expect();
10237      primary = token.fn;
10238      if (!primary) {
10239        this.throwError('not a primary expression', token);
10240      }
10241      if (token.json) {
10242        primary.constant = true;
10243        primary.literal = true;
10244      }
10245    }
10246
10247    var next, context;
10248    while ((next = this.expect('(', '[', '.'))) {
10249      if (next.text === '(') {
10250        primary = this.functionCall(primary, context);
10251        context = null;
10252      } else if (next.text === '[') {
10253        context = primary;
10254        primary = this.objectIndex(primary);
10255      } else if (next.text === '.') {
10256        context = primary;
10257        primary = this.fieldAccess(primary);
10258      } else {
10259        this.throwError('IMPOSSIBLE');
10260      }
10261    }
10262    return primary;
10263  },
10264
10265  throwError: function(msg, token) {
10266    throw $parseMinErr('syntax',
10267        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10268          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10269  },
10270
10271  peekToken: function() {
10272    if (this.tokens.length === 0)
10273      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10274    return this.tokens[0];
10275  },
10276
10277  peek: function(e1, e2, e3, e4) {
10278    if (this.tokens.length > 0) {
10279      var token = this.tokens[0];
10280      var t = token.text;
10281      if (t === e1 || t === e2 || t === e3 || t === e4 ||
10282          (!e1 && !e2 && !e3 && !e4)) {
10283        return token;
10284      }
10285    }
10286    return false;
10287  },
10288
10289  expect: function(e1, e2, e3, e4){
10290    var token = this.peek(e1, e2, e3, e4);
10291    if (token) {
10292      if (this.json && !token.json) {
10293        this.throwError('is not valid json', token);
10294      }
10295      this.tokens.shift();
10296      return token;
10297    }
10298    return false;
10299  },
10300
10301  consume: function(e1){
10302    if (!this.expect(e1)) {
10303      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10304    }
10305  },
10306
10307  unaryFn: function(fn, right) {
10308    return extend(function(self, locals) {
10309      return fn(self, locals, right);
10310    }, {
10311      constant:right.constant
10312    });
10313  },
10314
10315  ternaryFn: function(left, middle, right){
10316    return extend(function(self, locals){
10317      return left(self, locals) ? middle(self, locals) : right(self, locals);
10318    }, {
10319      constant: left.constant && middle.constant && right.constant
10320    });
10321  },
10322
10323  binaryFn: function(left, fn, right) {
10324    return extend(function(self, locals) {
10325      return fn(self, locals, left, right);
10326    }, {
10327      constant:left.constant && right.constant
10328    });
10329  },
10330
10331  statements: function() {
10332    var statements = [];
10333    while (true) {
10334      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10335        statements.push(this.filterChain());
10336      if (!this.expect(';')) {
10337        // optimize for the common case where there is only one statement.
10338        // TODO(size): maybe we should not support multiple statements?
10339        return (statements.length === 1)
10340            ? statements[0]
10341            : function(self, locals) {
10342                var value;
10343                for (var i = 0; i < statements.length; i++) {
10344                  var statement = statements[i];
10345                  if (statement) {
10346                    value = statement(self, locals);
10347                  }
10348                }
10349                return value;
10350              };
10351      }
10352    }
10353  },
10354
10355  filterChain: function() {
10356    var left = this.expression();
10357    var token;
10358    while (true) {
10359      if ((token = this.expect('|'))) {
10360        left = this.binaryFn(left, token.fn, this.filter());
10361      } else {
10362        return left;
10363      }
10364    }
10365  },
10366
10367  filter: function() {
10368    var token = this.expect();
10369    var fn = this.$filter(token.text);
10370    var argsFn = [];
10371    while (true) {
10372      if ((token = this.expect(':'))) {
10373        argsFn.push(this.expression());
10374      } else {
10375        var fnInvoke = function(self, locals, input) {
10376          var args = [input];
10377          for (var i = 0; i < argsFn.length; i++) {
10378            args.push(argsFn[i](self, locals));
10379          }
10380          return fn.apply(self, args);
10381        };
10382        return function() {
10383          return fnInvoke;
10384        };
10385      }
10386    }
10387  },
10388
10389  expression: function() {
10390    return this.assignment();
10391  },
10392
10393  assignment: function() {
10394    var left = this.ternary();
10395    var right;
10396    var token;
10397    if ((token = this.expect('='))) {
10398      if (!left.assign) {
10399        this.throwError('implies assignment but [' +
10400            this.text.substring(0, token.index) + '] can not be assigned to', token);
10401      }
10402      right = this.ternary();
10403      return function(scope, locals) {
10404        return left.assign(scope, right(scope, locals), locals);
10405      };
10406    }
10407    return left;
10408  },
10409
10410  ternary: function() {
10411    var left = this.logicalOR();
10412    var middle;
10413    var token;
10414    if ((token = this.expect('?'))) {
10415      middle = this.ternary();
10416      if ((token = this.expect(':'))) {
10417        return this.ternaryFn(left, middle, this.ternary());
10418      } else {
10419        this.throwError('expected :', token);
10420      }
10421    } else {
10422      return left;
10423    }
10424  },
10425
10426  logicalOR: function() {
10427    var left = this.logicalAND();
10428    var token;
10429    while (true) {
10430      if ((token = this.expect('||'))) {
10431        left = this.binaryFn(left, token.fn, this.logicalAND());
10432      } else {
10433        return left;
10434      }
10435    }
10436  },
10437
10438  logicalAND: function() {
10439    var left = this.equality();
10440    var token;
10441    if ((token = this.expect('&&'))) {
10442      left = this.binaryFn(left, token.fn, this.logicalAND());
10443    }
10444    return left;
10445  },
10446
10447  equality: function() {
10448    var left = this.relational();
10449    var token;
10450    if ((token = this.expect('==','!=','===','!=='))) {
10451      left = this.binaryFn(left, token.fn, this.equality());
10452    }
10453    return left;
10454  },
10455
10456  relational: function() {
10457    var left = this.additive();
10458    var token;
10459    if ((token = this.expect('<', '>', '<=', '>='))) {
10460      left = this.binaryFn(left, token.fn, this.relational());
10461    }
10462    return left;
10463  },
10464
10465  additive: function() {
10466    var left = this.multiplicative();
10467    var token;
10468    while ((token = this.expect('+','-'))) {
10469      left = this.binaryFn(left, token.fn, this.multiplicative());
10470    }
10471    return left;
10472  },
10473
10474  multiplicative: function() {
10475    var left = this.unary();
10476    var token;
10477    while ((token = this.expect('*','/','%'))) {
10478      left = this.binaryFn(left, token.fn, this.unary());
10479    }
10480    return left;
10481  },
10482
10483  unary: function() {
10484    var token;
10485    if (this.expect('+')) {
10486      return this.primary();
10487    } else if ((token = this.expect('-'))) {
10488      return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10489    } else if ((token = this.expect('!'))) {
10490      return this.unaryFn(token.fn, this.unary());
10491    } else {
10492      return this.primary();
10493    }
10494  },
10495
10496  fieldAccess: function(object) {
10497    var parser = this;
10498    var field = this.expect().text;
10499    var getter = getterFn(field, this.options, this.text);
10500
10501    return extend(function(scope, locals, self) {
10502      return getter(self || object(scope, locals));
10503    }, {
10504      assign: function(scope, value, locals) {
10505        return setter(object(scope, locals), field, value, parser.text, parser.options);
10506      }
10507    });
10508  },
10509
10510  objectIndex: function(obj) {
10511    var parser = this;
10512
10513    var indexFn = this.expression();
10514    this.consume(']');
10515
10516    return extend(function(self, locals) {
10517      var o = obj(self, locals),
10518          i = indexFn(self, locals),
10519          v, p;
10520
10521      if (!o) return undefined;
10522      v = ensureSafeObject(o[i], parser.text);
10523      if (v && v.then && parser.options.unwrapPromises) {
10524        p = v;
10525        if (!('$$v' in v)) {
10526          p.$$v = undefined;
10527          p.then(function(val) { p.$$v = val; });
10528        }
10529        v = v.$$v;
10530      }
10531      return v;
10532    }, {
10533      assign: function(self, value, locals) {
10534        var key = indexFn(self, locals);
10535        // prevent overwriting of Function.constructor which would break ensureSafeObject check
10536        var safe = ensureSafeObject(obj(self, locals), parser.text);
10537        return safe[key] = value;
10538      }
10539    });
10540  },
10541
10542  functionCall: function(fn, contextGetter) {
10543    var argsFn = [];
10544    if (this.peekToken().text !== ')') {
10545      do {
10546        argsFn.push(this.expression());
10547      } while (this.expect(','));
10548    }
10549    this.consume(')');
10550
10551    var parser = this;
10552
10553    return function(scope, locals) {
10554      var args = [];
10555      var context = contextGetter ? contextGetter(scope, locals) : scope;
10556
10557      for (var i = 0; i < argsFn.length; i++) {
10558        args.push(argsFn[i](scope, locals));
10559      }
10560      var fnPtr = fn(scope, locals, context) || noop;
10561
10562      ensureSafeObject(context, parser.text);
10563      ensureSafeObject(fnPtr, parser.text);
10564
10565      // IE stupidity! (IE doesn't have apply for some native functions)
10566      var v = fnPtr.apply
10567            ? fnPtr.apply(context, args)
10568            : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10569
10570      return ensureSafeObject(v, parser.text);
10571    };
10572  },
10573
10574  // This is used with json array declaration
10575  arrayDeclaration: function () {
10576    var elementFns = [];
10577    var allConstant = true;
10578    if (this.peekToken().text !== ']') {
10579      do {
10580        if (this.peek(']')) {
10581          // Support trailing commas per ES5.1.
10582          break;
10583        }
10584        var elementFn = this.expression();
10585        elementFns.push(elementFn);
10586        if (!elementFn.constant) {
10587          allConstant = false;
10588        }
10589      } while (this.expect(','));
10590    }
10591    this.consume(']');
10592
10593    return extend(function(self, locals) {
10594      var array = [];
10595      for (var i = 0; i < elementFns.length; i++) {
10596        array.push(elementFns[i](self, locals));
10597      }
10598      return array;
10599    }, {
10600      literal: true,
10601      constant: allConstant
10602    });
10603  },
10604
10605  object: function () {
10606    var keyValues = [];
10607    var allConstant = true;
10608    if (this.peekToken().text !== '}') {
10609      do {
10610        if (this.peek('}')) {
10611          // Support trailing commas per ES5.1.
10612          break;
10613        }
10614        var token = this.expect(),
10615        key = token.string || token.text;
10616        this.consume(':');
10617        var value = this.expression();
10618        keyValues.push({key: key, value: value});
10619        if (!value.constant) {
10620          allConstant = false;
10621        }
10622      } while (this.expect(','));
10623    }
10624    this.consume('}');
10625
10626    return extend(function(self, locals) {
10627      var object = {};
10628      for (var i = 0; i < keyValues.length; i++) {
10629        var keyValue = keyValues[i];
10630        object[keyValue.key] = keyValue.value(self, locals);
10631      }
10632      return object;
10633    }, {
10634      literal: true,
10635      constant: allConstant
10636    });
10637  }
10638};
10639
10640
10641//////////////////////////////////////////////////
10642// Parser helper functions
10643//////////////////////////////////////////////////
10644
10645function setter(obj, path, setValue, fullExp, options) {
10646  //needed?
10647  options = options || {};
10648
10649  var element = path.split('.'), key;
10650  for (var i = 0; element.length > 1; i++) {
10651    key = ensureSafeMemberName(element.shift(), fullExp);
10652    var propertyObj = obj[key];
10653    if (!propertyObj) {
10654      propertyObj = {};
10655      obj[key] = propertyObj;
10656    }
10657    obj = propertyObj;
10658    if (obj.then && options.unwrapPromises) {
10659      promiseWarning(fullExp);
10660      if (!("$$v" in obj)) {
10661        (function(promise) {
10662          promise.then(function(val) { promise.$$v = val; }); }
10663        )(obj);
10664      }
10665      if (obj.$$v === undefined) {
10666        obj.$$v = {};
10667      }
10668      obj = obj.$$v;
10669    }
10670  }
10671  key = ensureSafeMemberName(element.shift(), fullExp);
10672  obj[key] = setValue;
10673  return setValue;
10674}
10675
10676var getterFnCache = {};
10677
10678/**
10679 * Implementation of the "Black Hole" variant from:
10680 * - http://jsperf.com/angularjs-parse-getter/4
10681 * - http://jsperf.com/path-evaluation-simplified/7
10682 */
10683function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10684  ensureSafeMemberName(key0, fullExp);
10685  ensureSafeMemberName(key1, fullExp);
10686  ensureSafeMemberName(key2, fullExp);
10687  ensureSafeMemberName(key3, fullExp);
10688  ensureSafeMemberName(key4, fullExp);
10689
10690  return !options.unwrapPromises
10691      ? function cspSafeGetter(scope, locals) {
10692          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10693
10694          if (pathVal == null) return pathVal;
10695          pathVal = pathVal[key0];
10696
10697          if (!key1) return pathVal;
10698          if (pathVal == null) return undefined;
10699          pathVal = pathVal[key1];
10700
10701          if (!key2) return pathVal;
10702          if (pathVal == null) return undefined;
10703          pathVal = pathVal[key2];
10704
10705          if (!key3) return pathVal;
10706          if (pathVal == null) return undefined;
10707          pathVal = pathVal[key3];
10708
10709          if (!key4) return pathVal;
10710          if (pathVal == null) return undefined;
10711          pathVal = pathVal[key4];
10712
10713          return pathVal;
10714        }
10715      : function cspSafePromiseEnabledGetter(scope, locals) {
10716          var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10717              promise;
10718
10719          if (pathVal == null) return pathVal;
10720
10721          pathVal = pathVal[key0];
10722          if (pathVal && pathVal.then) {
10723            promiseWarning(fullExp);
10724            if (!("$$v" in pathVal)) {
10725              promise = pathVal;
10726              promise.$$v = undefined;
10727              promise.then(function(val) { promise.$$v = val; });
10728            }
10729            pathVal = pathVal.$$v;
10730          }
10731
10732          if (!key1) return pathVal;
10733          if (pathVal == null) return undefined;
10734          pathVal = pathVal[key1];
10735          if (pathVal && pathVal.then) {
10736            promiseWarning(fullExp);
10737            if (!("$$v" in pathVal)) {
10738              promise = pathVal;
10739              promise.$$v = undefined;
10740              promise.then(function(val) { promise.$$v = val; });
10741            }
10742            pathVal = pathVal.$$v;
10743          }
10744
10745          if (!key2) return pathVal;
10746          if (pathVal == null) return undefined;
10747          pathVal = pathVal[key2];
10748          if (pathVal && pathVal.then) {
10749            promiseWarning(fullExp);
10750            if (!("$$v" in pathVal)) {
10751              promise = pathVal;
10752              promise.$$v = undefined;
10753              promise.then(function(val) { promise.$$v = val; });
10754            }
10755            pathVal = pathVal.$$v;
10756          }
10757
10758          if (!key3) return pathVal;
10759          if (pathVal == null) return undefined;
10760          pathVal = pathVal[key3];
10761          if (pathVal && pathVal.then) {
10762            promiseWarning(fullExp);
10763            if (!("$$v" in pathVal)) {
10764              promise = pathVal;
10765              promise.$$v = undefined;
10766              promise.then(function(val) { promise.$$v = val; });
10767            }
10768            pathVal = pathVal.$$v;
10769          }
10770
10771          if (!key4) return pathVal;
10772          if (pathVal == null) return undefined;
10773          pathVal = pathVal[key4];
10774          if (pathVal && pathVal.then) {
10775            promiseWarning(fullExp);
10776            if (!("$$v" in pathVal)) {
10777              promise = pathVal;
10778              promise.$$v = undefined;
10779              promise.then(function(val) { promise.$$v = val; });
10780            }
10781            pathVal = pathVal.$$v;
10782          }
10783          return pathVal;
10784        };
10785}
10786
10787function simpleGetterFn1(key0, fullExp) {
10788  ensureSafeMemberName(key0, fullExp);
10789
10790  return function simpleGetterFn1(scope, locals) {
10791    if (scope == null) return undefined;
10792    return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10793  };
10794}
10795
10796function simpleGetterFn2(key0, key1, fullExp) {
10797  ensureSafeMemberName(key0, fullExp);
10798  ensureSafeMemberName(key1, fullExp);
10799
10800  return function simpleGetterFn2(scope, locals) {
10801    if (scope == null) return undefined;
10802    scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10803    return scope == null ? undefined : scope[key1];
10804  };
10805}
10806
10807function getterFn(path, options, fullExp) {
10808  // Check whether the cache has this getter already.
10809  // We can use hasOwnProperty directly on the cache because we ensure,
10810  // see below, that the cache never stores a path called 'hasOwnProperty'
10811  if (getterFnCache.hasOwnProperty(path)) {
10812    return getterFnCache[path];
10813  }
10814
10815  var pathKeys = path.split('.'),
10816      pathKeysLength = pathKeys.length,
10817      fn;
10818
10819  // When we have only 1 or 2 tokens, use optimized special case closures.
10820  // http://jsperf.com/angularjs-parse-getter/6
10821  if (!options.unwrapPromises && pathKeysLength === 1) {
10822    fn = simpleGetterFn1(pathKeys[0], fullExp);
10823  } else if (!options.unwrapPromises && pathKeysLength === 2) {
10824    fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
10825  } else if (options.csp) {
10826    if (pathKeysLength < 6) {
10827      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
10828                          options);
10829    } else {
10830      fn = function(scope, locals) {
10831        var i = 0, val;
10832        do {
10833          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
10834                                pathKeys[i++], fullExp, options)(scope, locals);
10835
10836          locals = undefined; // clear after first iteration
10837          scope = val;
10838        } while (i < pathKeysLength);
10839        return val;
10840      };
10841    }
10842  } else {
10843    var code = 'var p;\n';
10844    forEach(pathKeys, function(key, index) {
10845      ensureSafeMemberName(key, fullExp);
10846      code += 'if(s == null) return undefined;\n' +
10847              's='+ (index
10848                      // we simply dereference 's' on any .dot notation
10849                      ? 's'
10850                      // but if we are first then we check locals first, and if so read it first
10851                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
10852              (options.unwrapPromises
10853                ? 'if (s && s.then) {\n' +
10854                  ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
10855                  ' if (!("$$v" in s)) {\n' +
10856                    ' p=s;\n' +
10857                    ' p.$$v = undefined;\n' +
10858                    ' p.then(function(v) {p.$$v=v;});\n' +
10859                    '}\n' +
10860                  ' s=s.$$v\n' +
10861                '}\n'
10862                : '');
10863    });
10864    code += 'return s;';
10865
10866    /* jshint -W054 */
10867    var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
10868    /* jshint +W054 */
10869    evaledFnGetter.toString = valueFn(code);
10870    fn = options.unwrapPromises ? function(scope, locals) {
10871      return evaledFnGetter(scope, locals, promiseWarning);
10872    } : evaledFnGetter;
10873  }
10874
10875  // Only cache the value if it's not going to mess up the cache object
10876  // This is more performant that using Object.prototype.hasOwnProperty.call
10877  if (path !== 'hasOwnProperty') {
10878    getterFnCache[path] = fn;
10879  }
10880  return fn;
10881}
10882
10883///////////////////////////////////
10884
10885/**
10886 * @ngdoc service
10887 * @name $parse
10888 * @kind function
10889 *
10890 * @description
10891 *
10892 * Converts Angular {@link guide/expression expression} into a function.
10893 *
10894 * ```js
10895 *   var getter = $parse('user.name');
10896 *   var setter = getter.assign;
10897 *   var context = {user:{name:'angular'}};
10898 *   var locals = {user:{name:'local'}};
10899 *
10900 *   expect(getter(context)).toEqual('angular');
10901 *   setter(context, 'newValue');
10902 *   expect(context.user.name).toEqual('newValue');
10903 *   expect(getter(context, locals)).toEqual('local');
10904 * ```
10905 *
10906 *
10907 * @param {string} expression String expression to compile.
10908 * @returns {function(context, locals)} a function which represents the compiled expression:
10909 *
10910 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
10911 *      are evaluated against (typically a scope object).
10912 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
10913 *      `context`.
10914 *
10915 *    The returned function also has the following properties:
10916 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
10917 *        literal.
10918 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
10919 *        constant literals.
10920 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
10921 *        set to a function to change its value on the given context.
10922 *
10923 */
10924
10925
10926/**
10927 * @ngdoc provider
10928 * @name $parseProvider
10929 * @function
10930 *
10931 * @description
10932 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
10933 *  service.
10934 */
10935function $ParseProvider() {
10936  var cache = {};
10937
10938  var $parseOptions = {
10939    csp: false,
10940    unwrapPromises: false,
10941    logPromiseWarnings: true
10942  };
10943
10944
10945  /**
10946   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
10947   *
10948   * @ngdoc method
10949   * @name $parseProvider#unwrapPromises
10950   * @description
10951   *
10952   * **This feature is deprecated, see deprecation notes below for more info**
10953   *
10954   * If set to true (default is false), $parse will unwrap promises automatically when a promise is
10955   * found at any part of the expression. In other words, if set to true, the expression will always
10956   * result in a non-promise value.
10957   *
10958   * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
10959   * the fulfillment value is used in place of the promise while evaluating the expression.
10960   *
10961   * **Deprecation notice**
10962   *
10963   * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
10964   * dichotomy between data access in templates (accessed as raw values) and controller code
10965   * (accessed as promises).
10966   *
10967   * In most code we ended up resolving promises manually in controllers anyway and thus unifying
10968   * the model access there.
10969   *
10970   * Other downsides of automatic promise unwrapping:
10971   *
10972   * - when building components it's often desirable to receive the raw promises
10973   * - adds complexity and slows down expression evaluation
10974   * - makes expression code pre-generation unattractive due to the amount of code that needs to be
10975   *   generated
10976   * - makes IDE auto-completion and tool support hard
10977   *
10978   * **Warning Logs**
10979   *
10980   * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
10981   * promise (to reduce the noise, each expression is logged only once). To disable this logging use
10982   * `$parseProvider.logPromiseWarnings(false)` api.
10983   *
10984   *
10985   * @param {boolean=} value New value.
10986   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
10987   *                         setter.
10988   */
10989  this.unwrapPromises = function(value) {
10990    if (isDefined(value)) {
10991      $parseOptions.unwrapPromises = !!value;
10992      return this;
10993    } else {
10994      return $parseOptions.unwrapPromises;
10995    }
10996  };
10997
10998
10999  /**
11000   * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11001   *
11002   * @ngdoc method
11003   * @name $parseProvider#logPromiseWarnings
11004   * @description
11005   *
11006   * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11007   *
11008   * The default is set to `true`.
11009   *
11010   * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11011   *
11012   * @param {boolean=} value New value.
11013   * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11014   *                         setter.
11015   */
11016 this.logPromiseWarnings = function(value) {
11017    if (isDefined(value)) {
11018      $parseOptions.logPromiseWarnings = value;
11019      return this;
11020    } else {
11021      return $parseOptions.logPromiseWarnings;
11022    }
11023  };
11024
11025
11026  this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
11027    $parseOptions.csp = $sniffer.csp;
11028
11029    promiseWarning = function promiseWarningFn(fullExp) {
11030      if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11031      promiseWarningCache[fullExp] = true;
11032      $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11033          'Automatic unwrapping of promises in Angular expressions is deprecated.');
11034    };
11035
11036    return function(exp) {
11037      var parsedExpression;
11038
11039      switch (typeof exp) {
11040        case 'string':
11041
11042          if (cache.hasOwnProperty(exp)) {
11043            return cache[exp];
11044          }
11045
11046          var lexer = new Lexer($parseOptions);
11047          var parser = new Parser(lexer, $filter, $parseOptions);
11048          parsedExpression = parser.parse(exp, false);
11049
11050          if (exp !== 'hasOwnProperty') {
11051            // Only cache the value if it's not going to mess up the cache object
11052            // This is more performant that using Object.prototype.hasOwnProperty.call
11053            cache[exp] = parsedExpression;
11054          }
11055
11056          return parsedExpression;
11057
11058        case 'function':
11059          return exp;
11060
11061        default:
11062          return noop;
11063      }
11064    };
11065  }];
11066}
11067
11068/**
11069 * @ngdoc service
11070 * @name $q
11071 * @requires $rootScope
11072 *
11073 * @description
11074 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
11075 *
11076 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11077 * interface for interacting with an object that represents the result of an action that is
11078 * performed asynchronously, and may or may not be finished at any given point in time.
11079 *
11080 * From the perspective of dealing with error handling, deferred and promise APIs are to
11081 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11082 *
11083 * ```js
11084 *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11085 *   // are available in the current lexical scope (they could have been injected or passed in).
11086 *
11087 *   function asyncGreet(name) {
11088 *     var deferred = $q.defer();
11089 *
11090 *     setTimeout(function() {
11091 *       // since this fn executes async in a future turn of the event loop, we need to wrap
11092 *       // our code into an $apply call so that the model changes are properly observed.
11093 *       scope.$apply(function() {
11094 *         deferred.notify('About to greet ' + name + '.');
11095 *
11096 *         if (okToGreet(name)) {
11097 *           deferred.resolve('Hello, ' + name + '!');
11098 *         } else {
11099 *           deferred.reject('Greeting ' + name + ' is not allowed.');
11100 *         }
11101 *       });
11102 *     }, 1000);
11103 *
11104 *     return deferred.promise;
11105 *   }
11106 *
11107 *   var promise = asyncGreet('Robin Hood');
11108 *   promise.then(function(greeting) {
11109 *     alert('Success: ' + greeting);
11110 *   }, function(reason) {
11111 *     alert('Failed: ' + reason);
11112 *   }, function(update) {
11113 *     alert('Got notification: ' + update);
11114 *   });
11115 * ```
11116 *
11117 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11118 * comes in the way of guarantees that promise and deferred APIs make, see
11119 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11120 *
11121 * Additionally the promise api allows for composition that is very hard to do with the
11122 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11123 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11124 * section on serial or parallel joining of promises.
11125 *
11126 *
11127 * # The Deferred API
11128 *
11129 * A new instance of deferred is constructed by calling `$q.defer()`.
11130 *
11131 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11132 * that can be used for signaling the successful or unsuccessful completion, as well as the status
11133 * of the task.
11134 *
11135 * **Methods**
11136 *
11137 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11138 *   constructed via `$q.reject`, the promise will be rejected instead.
11139 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11140 *   resolving it with a rejection constructed via `$q.reject`.
11141 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11142 *   multiple times before the promise is either resolved or rejected.
11143 *
11144 * **Properties**
11145 *
11146 * - promise – `{Promise}` – promise object associated with this deferred.
11147 *
11148 *
11149 * # The Promise API
11150 *
11151 * A new promise instance is created when a deferred instance is created and can be retrieved by
11152 * calling `deferred.promise`.
11153 *
11154 * The purpose of the promise object is to allow for interested parties to get access to the result
11155 * of the deferred task when it completes.
11156 *
11157 * **Methods**
11158 *
11159 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11160 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11161 *   as soon as the result is available. The callbacks are called with a single argument: the result
11162 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11163 *   provide a progress indication, before the promise is resolved or rejected.
11164 *
11165 *   This method *returns a new promise* which is resolved or rejected via the return value of the
11166 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11167 *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11168 *   method.
11169 *
11170 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11171 *
11172 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11173 *   but to do so without modifying the final value. This is useful to release resources or do some
11174 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11175 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11176 *   more information.
11177 *
11178 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11179 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11180 *   make your code IE8 and Android 2.x compatible.
11181 *
11182 * # Chaining promises
11183 *
11184 * Because calling the `then` method of a promise returns a new derived promise, it is easily
11185 * possible to create a chain of promises:
11186 *
11187 * ```js
11188 *   promiseB = promiseA.then(function(result) {
11189 *     return result + 1;
11190 *   });
11191 *
11192 *   // promiseB will be resolved immediately after promiseA is resolved and its value
11193 *   // will be the result of promiseA incremented by 1
11194 * ```
11195 *
11196 * It is possible to create chains of any length and since a promise can be resolved with another
11197 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11198 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11199 * $http's response interceptors.
11200 *
11201 *
11202 * # Differences between Kris Kowal's Q and $q
11203 *
11204 *  There are two main differences:
11205 *
11206 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11207 *   mechanism in angular, which means faster propagation of resolution or rejection into your
11208 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11209 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11210 *   all the important functionality needed for common async tasks.
11211 *
11212 *  # Testing
11213 *
11214 *  ```js
11215 *    it('should simulate promise', inject(function($q, $rootScope) {
11216 *      var deferred = $q.defer();
11217 *      var promise = deferred.promise;
11218 *      var resolvedValue;
11219 *
11220 *      promise.then(function(value) { resolvedValue = value; });
11221 *      expect(resolvedValue).toBeUndefined();
11222 *
11223 *      // Simulate resolving of promise
11224 *      deferred.resolve(123);
11225 *      // Note that the 'then' function does not get called synchronously.
11226 *      // This is because we want the promise API to always be async, whether or not
11227 *      // it got called synchronously or asynchronously.
11228 *      expect(resolvedValue).toBeUndefined();
11229 *
11230 *      // Propagate promise resolution to 'then' functions using $apply().
11231 *      $rootScope.$apply();
11232 *      expect(resolvedValue).toEqual(123);
11233 *    }));
11234 *  ```
11235 */
11236function $QProvider() {
11237
11238  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
11239    return qFactory(function(callback) {
11240      $rootScope.$evalAsync(callback);
11241    }, $exceptionHandler);
11242  }];
11243}
11244
11245
11246/**
11247 * Constructs a promise manager.
11248 *
11249 * @param {function(Function)} nextTick Function for executing functions in the next turn.
11250 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11251 *     debugging purposes.
11252 * @returns {object} Promise manager.
11253 */
11254function qFactory(nextTick, exceptionHandler) {
11255
11256  /**
11257   * @ngdoc method
11258   * @name $q#defer
11259   * @function
11260   *
11261   * @description
11262   * Creates a `Deferred` object which represents a task which will finish in the future.
11263   *
11264   * @returns {Deferred} Returns a new instance of deferred.
11265   */
11266  var defer = function() {
11267    var pending = [],
11268        value, deferred;
11269
11270    deferred = {
11271
11272      resolve: function(val) {
11273        if (pending) {
11274          var callbacks = pending;
11275          pending = undefined;
11276          value = ref(val);
11277
11278          if (callbacks.length) {
11279            nextTick(function() {
11280              var callback;
11281              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11282                callback = callbacks[i];
11283                value.then(callback[0], callback[1], callback[2]);
11284              }
11285            });
11286          }
11287        }
11288      },
11289
11290
11291      reject: function(reason) {
11292        deferred.resolve(createInternalRejectedPromise(reason));
11293      },
11294
11295
11296      notify: function(progress) {
11297        if (pending) {
11298          var callbacks = pending;
11299
11300          if (pending.length) {
11301            nextTick(function() {
11302              var callback;
11303              for (var i = 0, ii = callbacks.length; i < ii; i++) {
11304                callback = callbacks[i];
11305                callback[2](progress);
11306              }
11307            });
11308          }
11309        }
11310      },
11311
11312
11313      promise: {
11314        then: function(callback, errback, progressback) {
11315          var result = defer();
11316
11317          var wrappedCallback = function(value) {
11318            try {
11319              result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11320            } catch(e) {
11321              result.reject(e);
11322              exceptionHandler(e);
11323            }
11324          };
11325
11326          var wrappedErrback = function(reason) {
11327            try {
11328              result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11329            } catch(e) {
11330              result.reject(e);
11331              exceptionHandler(e);
11332            }
11333          };
11334
11335          var wrappedProgressback = function(progress) {
11336            try {
11337              result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11338            } catch(e) {
11339              exceptionHandler(e);
11340            }
11341          };
11342
11343          if (pending) {
11344            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11345          } else {
11346            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11347          }
11348
11349          return result.promise;
11350        },
11351
11352        "catch": function(callback) {
11353          return this.then(null, callback);
11354        },
11355
11356        "finally": function(callback) {
11357
11358          function makePromise(value, resolved) {
11359            var result = defer();
11360            if (resolved) {
11361              result.resolve(value);
11362            } else {
11363              result.reject(value);
11364            }
11365            return result.promise;
11366          }
11367
11368          function handleCallback(value, isResolved) {
11369            var callbackOutput = null;
11370            try {
11371              callbackOutput = (callback ||defaultCallback)();
11372            } catch(e) {
11373              return makePromise(e, false);
11374            }
11375            if (callbackOutput && isFunction(callbackOutput.then)) {
11376              return callbackOutput.then(function() {
11377                return makePromise(value, isResolved);
11378              }, function(error) {
11379                return makePromise(error, false);
11380              });
11381            } else {
11382              return makePromise(value, isResolved);
11383            }
11384          }
11385
11386          return this.then(function(value) {
11387            return handleCallback(value, true);
11388          }, function(error) {
11389            return handleCallback(error, false);
11390          });
11391        }
11392      }
11393    };
11394
11395    return deferred;
11396  };
11397
11398
11399  var ref = function(value) {
11400    if (value && isFunction(value.then)) return value;
11401    return {
11402      then: function(callback) {
11403        var result = defer();
11404        nextTick(function() {
11405          result.resolve(callback(value));
11406        });
11407        return result.promise;
11408      }
11409    };
11410  };
11411
11412
11413  /**
11414   * @ngdoc method
11415   * @name $q#reject
11416   * @function
11417   *
11418   * @description
11419   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11420   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11421   * a promise chain, you don't need to worry about it.
11422   *
11423   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11424   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11425   * a promise error callback and you want to forward the error to the promise derived from the
11426   * current promise, you have to "rethrow" the error by returning a rejection constructed via
11427   * `reject`.
11428   *
11429   * ```js
11430   *   promiseB = promiseA.then(function(result) {
11431   *     // success: do something and resolve promiseB
11432   *     //          with the old or a new result
11433   *     return result;
11434   *   }, function(reason) {
11435   *     // error: handle the error if possible and
11436   *     //        resolve promiseB with newPromiseOrValue,
11437   *     //        otherwise forward the rejection to promiseB
11438   *     if (canHandle(reason)) {
11439   *      // handle the error and recover
11440   *      return newPromiseOrValue;
11441   *     }
11442   *     return $q.reject(reason);
11443   *   });
11444   * ```
11445   *
11446   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11447   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11448   */
11449  var reject = function(reason) {
11450    var result = defer();
11451    result.reject(reason);
11452    return result.promise;
11453  };
11454
11455  var createInternalRejectedPromise = function(reason) {
11456    return {
11457      then: function(callback, errback) {
11458        var result = defer();
11459        nextTick(function() {
11460          try {
11461            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11462          } catch(e) {
11463            result.reject(e);
11464            exceptionHandler(e);
11465          }
11466        });
11467        return result.promise;
11468      }
11469    };
11470  };
11471
11472
11473  /**
11474   * @ngdoc method
11475   * @name $q#when
11476   * @function
11477   *
11478   * @description
11479   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11480   * This is useful when you are dealing with an object that might or might not be a promise, or if
11481   * the promise comes from a source that can't be trusted.
11482   *
11483   * @param {*} value Value or a promise
11484   * @returns {Promise} Returns a promise of the passed value or promise
11485   */
11486  var when = function(value, callback, errback, progressback) {
11487    var result = defer(),
11488        done;
11489
11490    var wrappedCallback = function(value) {
11491      try {
11492        return (isFunction(callback) ? callback : defaultCallback)(value);
11493      } catch (e) {
11494        exceptionHandler(e);
11495        return reject(e);
11496      }
11497    };
11498
11499    var wrappedErrback = function(reason) {
11500      try {
11501        return (isFunction(errback) ? errback : defaultErrback)(reason);
11502      } catch (e) {
11503        exceptionHandler(e);
11504        return reject(e);
11505      }
11506    };
11507
11508    var wrappedProgressback = function(progress) {
11509      try {
11510        return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11511      } catch (e) {
11512        exceptionHandler(e);
11513      }
11514    };
11515
11516    nextTick(function() {
11517      ref(value).then(function(value) {
11518        if (done) return;
11519        done = true;
11520        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11521      }, function(reason) {
11522        if (done) return;
11523        done = true;
11524        result.resolve(wrappedErrback(reason));
11525      }, function(progress) {
11526        if (done) return;
11527        result.notify(wrappedProgressback(progress));
11528      });
11529    });
11530
11531    return result.promise;
11532  };
11533
11534
11535  function defaultCallback(value) {
11536    return value;
11537  }
11538
11539
11540  function defaultErrback(reason) {
11541    return reject(reason);
11542  }
11543
11544
11545  /**
11546   * @ngdoc method
11547   * @name $q#all
11548   * @function
11549   *
11550   * @description
11551   * Combines multiple promises into a single promise that is resolved when all of the input
11552   * promises are resolved.
11553   *
11554   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11555   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11556   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11557   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11558   *   with the same rejection value.
11559   */
11560  function all(promises) {
11561    var deferred = defer(),
11562        counter = 0,
11563        results = isArray(promises) ? [] : {};
11564
11565    forEach(promises, function(promise, key) {
11566      counter++;
11567      ref(promise).then(function(value) {
11568        if (results.hasOwnProperty(key)) return;
11569        results[key] = value;
11570        if (!(--counter)) deferred.resolve(results);
11571      }, function(reason) {
11572        if (results.hasOwnProperty(key)) return;
11573        deferred.reject(reason);
11574      });
11575    });
vendor: 4,330 bytes, lines 11576-11709
11576
11577    if (counter === 0) {
11578      deferred.resolve(results);
11579    }
11580
11581    return deferred.promise;
11582  }
11583
11584  return {
11585    defer: defer,
11586    reject: reject,
11587    when: when,
11588    all: all
11589  };
11590}
11591
11592function $$RAFProvider(){ //rAF
11593  this.$get = ['$window', '$timeout', function($window, $timeout) {
11594    var requestAnimationFrame = $window.requestAnimationFrame ||
11595                                $window.webkitRequestAnimationFrame ||
11596                                $window.mozRequestAnimationFrame;
11597
11598    var cancelAnimationFrame = $window.cancelAnimationFrame ||
11599                               $window.webkitCancelAnimationFrame ||
11600                               $window.mozCancelAnimationFrame ||
11601                               $window.webkitCancelRequestAnimationFrame;
11602
11603    var rafSupported = !!requestAnimationFrame;
11604    var raf = rafSupported
11605      ? function(fn) {
11606          var id = requestAnimationFrame(fn);
11607          return function() {
11608            cancelAnimationFrame(id);
11609          };
11610        }
11611      : function(fn) {
11612          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
11613          return function() {
11614            $timeout.cancel(timer);
11615          };
11616        };
11617
11618    raf.supported = rafSupported;
11619
11620    return raf;
11621  }];
11622}
11623
11624/**
11625 * DESIGN NOTES
11626 *
11627 * The design decisions behind the scope are heavily favored for speed and memory consumption.
11628 *
11629 * The typical use of scope is to watch the expressions, which most of the time return the same
11630 * value as last time so we optimize the operation.
11631 *
11632 * Closures construction is expensive in terms of speed as well as memory:
11633 *   - No closures, instead use prototypical inheritance for API
11634 *   - Internal state needs to be stored on scope directly, which means that private state is
11635 *     exposed as $$____ properties
11636 *
11637 * Loop operations are optimized by using while(count--) { ... }
11638 *   - this means that in order to keep the same order of execution as addition we have to add
11639 *     items to the array at the beginning (shift) instead of at the end (push)
11640 *
11641 * Child scopes are created and removed often
11642 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11643 *
11644 * There are few watches then a lot of observers. This is why you don't want the observer to be
11645 * implemented in the same way as watch. Watch requires return of initialization function which
11646 * are expensive to construct.
11647 */
11648
11649
11650/**
11651 * @ngdoc provider
11652 * @name $rootScopeProvider
11653 * @description
11654 *
11655 * Provider for the $rootScope service.
11656 */
11657
11658/**
11659 * @ngdoc method
11660 * @name $rootScopeProvider#digestTtl
11661 * @description
11662 *
11663 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11664 * assuming that the model is unstable.
11665 *
11666 * The current default is 10 iterations.
11667 *
11668 * In complex applications it's possible that the dependencies between `$watch`s will result in
11669 * several digest iterations. However if an application needs more than the default 10 digest
11670 * iterations for its model to stabilize then you should investigate what is causing the model to
11671 * continuously change during the digest.
11672 *
11673 * Increasing the TTL could have performance implications, so you should not change it without
11674 * proper justification.
11675 *
11676 * @param {number} limit The number of digest iterations.
11677 */
11678
11679
11680/**
11681 * @ngdoc service
11682 * @name $rootScope
11683 * @description
11684 *
11685 * Every application has a single root {@link ng.$rootScope.Scope scope}.
11686 * All other scopes are descendant scopes of the root scope. Scopes provide separation
11687 * between the model and the view, via a mechanism for watching the model for changes.
11688 * They also provide an event emission/broadcast and subscription facility. See the
11689 * {@link guide/scope developer guide on scopes}.
11690 */
11691function $RootScopeProvider(){
11692  var TTL = 10;
11693  var $rootScopeMinErr = minErr('$rootScope');
11694  var lastDirtyWatch = null;
11695
11696  this.digestTtl = function(value) {
11697    if (arguments.length) {
11698      TTL = value;
11699    }
11700    return TTL;
11701  };
11702
11703  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11704      function( $injector,   $exceptionHandler,   $parse,   $browser) {
11705
11706    /**
11707     * @ngdoc type
11708     * @name $rootScope.Scope
11709     *
11710     * @description
11711     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11712     * {@link auto.$injector $injector}. Child scopes are created using the
11713     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
11714     * compiled HTML template is executed.)
11715     *
11716     * Here is a simple scope snippet to show how you can interact with the scope.
11717     * ```html
11718     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11719     * ```
11720     *
11721     * # Inheritance
11722     * A scope can inherit from a parent scope, as in this example:
11723     * ```js
11724         var parent = $rootScope;
11725         var child = parent.$new();
11726
11727         parent.salutation = "Hello";
11728         child.name = "World";
11729         expect(child.salutation).toEqual('Hello');
11730
11731         child.salutation = "Welcome";
11732         expect(child.salutation).toEqual('Welcome');
11733         expect(parent.salutation).toEqual('Hello');
11734     * ```
11735     *
11736     *
11737     * @param {Object.<string, function()>=} providers Map of service factory which need to be
11738     *                                       provided for the current scope. Defaults to {@link ng}.
11739     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11740     *                              append/override services provided by `providers`. This is handy
11741     *                              when unit-testing and having the need to override a default
11742     *                              service.
11743     * @returns {Object} Newly created scope.
11744     *
11745     */
11746    function Scope() {
11747      this.$id = nextUid();
11748      this.$$phase = this.$parent = this.$$watchers =
11749                     this.$$nextSibling = this.$$prevSibling =
11750                     this.$$childHead = this.$$childTail = null;
11751      this['this'] = this.$root =  this;
11752      this.$$destroyed = false;
11753      this.$$asyncQueue = [];
11754      this.$$postDigestQueue = [];
11755      this.$$listeners = {};
11756      this.$$listenerCount = {};
11757      this.$$isolateBindings = {};
11758    }
11759
11760    /**
11761     * @ngdoc property
11762     * @name $rootScope.Scope#$id
11763     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11764     *   debugging.
11765     */
11766
11767
11768    Scope.prototype = {
11769      constructor: Scope,
11770      /**
11771       * @ngdoc method
11772       * @name $rootScope.Scope#$new
11773       * @function
11774       *
11775       * @description
11776       * Creates a new child {@link ng.$rootScope.Scope scope}.
11777       *
11778       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
11779       * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
11780       * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
11781       *
11782       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
11783       * desired for the scope and its child scopes to be permanently detached from the parent and
11784       * thus stop participating in model change detection and listener notification by invoking.
11785       *
11786       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
11787       *         parent scope. The scope is isolated, as it can not see parent scope properties.
11788       *         When creating widgets, it is useful for the widget to not accidentally read parent
11789       *         state.
11790       *
11791       * @returns {Object} The newly created child scope.
11792       *
11793       */
11794      $new: function(isolate) {
11795        var ChildScope,
11796            child;
11797
11798        if (isolate) {
11799          child = new Scope();
11800          child.$root = this.$root;
11801          // ensure that there is just one async queue per $rootScope and its children
11802          child.$$asyncQueue = this.$$asyncQueue;
11803          child.$$postDigestQueue = this.$$postDigestQueue;
11804        } else {
11805          ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
11806            // the name it does not become random set of chars. This will then show up as class
11807            // name in the web inspector.
11808          ChildScope.prototype = this;
11809          child = new ChildScope();
11810          child.$id = nextUid();
11811        }
11812        child['this'] = child;
11813        child.$$listeners = {};
11814        child.$$listenerCount = {};
11815        child.$parent = this;
11816        child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
11817        child.$$prevSibling = this.$$childTail;
11818        if (this.$$childHead) {
11819          this.$$childTail.$$nextSibling = child;
11820          this.$$childTail = child;
11821        } else {
11822          this.$$childHead = this.$$childTail = child;
11823        }
11824        return child;
11825      },
11826
11827      /**
11828       * @ngdoc method
11829       * @name $rootScope.Scope#$watch
11830       * @function
11831       *
11832       * @description
11833       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
11834       *
11835       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
11836       *   $digest()} and should return the value that will be watched. (Since
11837       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
11838       *   `watchExpression` can execute multiple times per
11839       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
11840       * - The `listener` is called only when the value from the current `watchExpression` and the
11841       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
11842       *   see below). The inequality is determined according to
11843       *   {@link angular.equals} function. To save the value of the object for later comparison,
11844       *   the {@link angular.copy} function is used. It also means that watching complex options
11845       *   will have adverse memory and performance implications.
11846       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
11847       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
11848       *   iteration limit is 10 to prevent an infinite loop deadlock.
11849       *
11850       *
11851       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
11852       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
11853       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
11854       * change is detected, be prepared for multiple calls to your listener.)
11855       *
11856       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
11857       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
11858       * watcher. In rare cases, this is undesirable because the listener is called when the result
11859       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
11860       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
11861       * listener was called due to initialization.
11862       *
11863       * The example below contains an illustration of using a function as your $watch listener
11864       *
11865       *
11866       * # Example
11867       * ```js
11868           // let's assume that scope was dependency injected as the $rootScope
11869           var scope = $rootScope;
11870           scope.name = 'misko';
11871           scope.counter = 0;
11872
11873           expect(scope.counter).toEqual(0);
11874           scope.$watch('name', function(newValue, oldValue) {
11875             scope.counter = scope.counter + 1;
11876           });
11877           expect(scope.counter).toEqual(0);
11878
11879           scope.$digest();
11880           // no variable change
11881           expect(scope.counter).toEqual(0);
11882
11883           scope.name = 'adam';
11884           scope.$digest();
11885           expect(scope.counter).toEqual(1);
11886
11887
11888
11889           // Using a listener function
11890           var food;
11891           scope.foodCounter = 0;
11892           expect(scope.foodCounter).toEqual(0);
11893           scope.$watch(
11894             // This is the listener function
11895             function() { return food; },
11896             // This is the change handler
11897             function(newValue, oldValue) {
11898               if ( newValue !== oldValue ) {
11899                 // Only increment the counter if the value changed
11900                 scope.foodCounter = scope.foodCounter + 1;
11901               }
11902             }
11903           );
11904           // No digest has been run so the counter will be zero
11905           expect(scope.foodCounter).toEqual(0);
11906
11907           // Run the digest but since food has not changed count will still be zero
11908           scope.$digest();
11909           expect(scope.foodCounter).toEqual(0);
11910
11911           // Update food and run digest.  Now the counter will increment
11912           food = 'cheeseburger';
11913           scope.$digest();
11914           expect(scope.foodCounter).toEqual(1);
11915
11916       * ```
11917       *
11918       *
11919       *
11920       * @param {(function()|string)} watchExpression Expression that is evaluated on each
11921       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
11922       *    a call to the `listener`.
11923       *
11924       *    - `string`: Evaluated as {@link guide/expression expression}
11925       *    - `function(scope)`: called with current `scope` as a parameter.
11926       * @param {(function()|string)=} listener Callback called whenever the return value of
11927       *   the `watchExpression` changes.
11928       *
11929       *    - `string`: Evaluated as {@link guide/expression expression}
11930       *    - `function(newValue, oldValue, scope)`: called with current and previous values as
11931       *      parameters.
11932       *
11933       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
11934       *     comparing for reference equality.
11935       * @returns {function()} Returns a deregistration function for this listener.
11936       */
11937      $watch: function(watchExp, listener, objectEquality) {
11938        var scope = this,
11939            get = compileToFn(watchExp, 'watch'),
11940            array = scope.$$watchers,
11941            watcher = {
11942              fn: listener,
11943              last: initWatchVal,
11944              get: get,
11945              exp: watchExp,
11946              eq: !!objectEquality
11947            };
11948
11949        lastDirtyWatch = null;
11950
11951        // in the case user pass string, we need to compile it, do we really need this ?
11952        if (!isFunction(listener)) {
11953          var listenFn = compileToFn(listener || noop, 'listener');
11954          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
11955        }
11956
11957        if (typeof watchExp == 'string' && get.constant) {
11958          var originalFn = watcher.fn;
11959          watcher.fn = function(newVal, oldVal, scope) {
11960            originalFn.call(this, newVal, oldVal, scope);
11961            arrayRemove(array, watcher);
11962          };
11963        }
11964
11965        if (!array) {
11966          array = scope.$$watchers = [];
11967        }
11968        // we use unshift since we use a while loop in $digest for speed.
11969        // the while loop reads in reverse order.
11970        array.unshift(watcher);
11971
11972        return function() {
11973          arrayRemove(array, watcher);
11974          lastDirtyWatch = null;
11975        };
11976      },
11977
11978
11979      /**
11980       * @ngdoc method
11981       * @name $rootScope.Scope#$watchCollection
11982       * @function
11983       *
11984       * @description
11985       * Shallow watches the properties of an object and fires whenever any of the properties change
11986       * (for arrays, this implies watching the array items; for object maps, this implies watching
11987       * the properties). If a change is detected, the `listener` callback is fired.
11988       *
11989       * - The `obj` collection is observed via standard $watch operation and is examined on every
11990       *   call to $digest() to see if any items have been added, removed, or moved.
11991       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
11992       *   adding, removing, and moving items belonging to an object or array.
11993       *
11994       *
11995       * # Example
11996       * ```js
11997          $scope.names = ['igor', 'matias', 'misko', 'james'];
11998          $scope.dataCount = 4;
11999
12000          $scope.$watchCollection('names', function(newNames, oldNames) {
12001            $scope.dataCount = newNames.length;
12002          });
12003
12004          expect($scope.dataCount).toEqual(4);
12005          $scope.$digest();
12006
12007          //still at 4 ... no changes
12008          expect($scope.dataCount).toEqual(4);
12009
12010          $scope.names.pop();
12011          $scope.$digest();
12012
12013          //now there's been a change
12014          expect($scope.dataCount).toEqual(3);
12015       * ```
12016       *
12017       *
12018       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12019       *    expression value should evaluate to an object or an array which is observed on each
12020       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12021       *    collection will trigger a call to the `listener`.
12022       *
12023       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12024       *    when a change is detected.
12025       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12026       *    - The `oldCollection` object is a copy of the former collection data.
12027       *      Due to performance considerations, the`oldCollection` value is computed only if the
12028       *      `listener` function declares two or more arguments.
12029       *    - The `scope` argument refers to the current scope.
12030       *
12031       * @returns {function()} Returns a de-registration function for this listener. When the
12032       *    de-registration function is executed, the internal watch operation is terminated.
12033       */
12034      $watchCollection: function(obj, listener) {
12035        var self = this;
12036        // the current value, updated on each dirty-check run
12037        var newValue;
12038        // a shallow copy of the newValue from the last dirty-check run,
12039        // updated to match newValue during dirty-check run
12040        var oldValue;
12041        // a shallow copy of the newValue from when the last change happened
12042        var veryOldValue;
12043        // only track veryOldValue if the listener is asking for it
12044        var trackVeryOldValue = (listener.length > 1);
12045        var changeDetected = 0;
12046        var objGetter = $parse(obj);
12047        var internalArray = [];
12048        var internalObject = {};
12049        var initRun = true;
12050        var oldLength = 0;
12051
12052        function $watchCollectionWatch() {
12053          newValue = objGetter(self);
12054          var newLength, key;
12055
12056          if (!isObject(newValue)) { // if primitive
12057            if (oldValue !== newValue) {
12058              oldValue = newValue;
12059              changeDetected++;
12060            }
12061          } else if (isArrayLike(newValue)) {
12062            if (oldValue !== internalArray) {
12063              // we are transitioning from something which was not an array into array.
12064              oldValue = internalArray;
12065              oldLength = oldValue.length = 0;
12066              changeDetected++;
12067            }
12068
12069            newLength = newValue.length;
12070
12071            if (oldLength !== newLength) {
12072              // if lengths do not match we need to trigger change notification
12073              changeDetected++;
12074              oldValue.length = oldLength = newLength;
12075            }
12076            // copy the items to oldValue and look for changes.
12077            for (var i = 0; i < newLength; i++) {
12078              var bothNaN = (oldValue[i] !== oldValue[i]) &&
12079                  (newValue[i] !== newValue[i]);
12080              if (!bothNaN && (oldValue[i] !== newValue[i])) {
12081                changeDetected++;
12082                oldValue[i] = newValue[i];
12083              }
12084            }
12085          } else {
12086            if (oldValue !== internalObject) {
12087              // we are transitioning from something which was not an object into object.
12088              oldValue = internalObject = {};
12089              oldLength = 0;
12090              changeDetected++;
12091            }
12092            // copy the items to oldValue and look for changes.
12093            newLength = 0;
12094            for (key in newValue) {
12095              if (newValue.hasOwnProperty(key)) {
12096                newLength++;
12097                if (oldValue.hasOwnProperty(key)) {
12098                  if (oldValue[key] !== newValue[key]) {
12099                    changeDetected++;
12100                    oldValue[key] = newValue[key];
12101                  }
12102                } else {
12103                  oldLength++;
12104                  oldValue[key] = newValue[key];
12105                  changeDetected++;
12106                }
12107              }
12108            }
12109            if (oldLength > newLength) {
12110              // we used to have more keys, need to find them and destroy them.
12111              changeDetected++;
12112              for(key in oldValue) {
12113                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12114                  oldLength--;
12115                  delete oldValue[key];
12116                }
12117              }
12118            }
12119          }
12120          return changeDetected;
12121        }
12122
12123        function $watchCollectionAction() {
12124          if (initRun) {
12125            initRun = false;
12126            listener(newValue, newValue, self);
12127          } else {
12128            listener(newValue, veryOldValue, self);
12129          }
12130
12131          // make a copy for the next time a collection is changed
12132          if (trackVeryOldValue) {
12133            if (!isObject(newValue)) {
12134              //primitive
12135              veryOldValue = newValue;
12136            } else if (isArrayLike(newValue)) {
12137              veryOldValue = new Array(newValue.length);
12138              for (var i = 0; i < newValue.length; i++) {
12139                veryOldValue[i] = newValue[i];
12140              }
12141            } else { // if object
12142              veryOldValue = {};
12143              for (var key in newValue) {
12144                if (hasOwnProperty.call(newValue, key)) {
12145                  veryOldValue[key] = newValue[key];
12146                }
12147              }
12148            }
12149          }
12150        }
12151
12152        return this.$watch($watchCollectionWatch, $watchCollectionAction);
12153      },
12154
12155      /**
12156       * @ngdoc method
12157       * @name $rootScope.Scope#$digest
12158       * @function
12159       *
12160       * @description
12161       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12162       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12163       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12164       * until no more listeners are firing. This means that it is possible to get into an infinite
12165       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12166       * iterations exceeds 10.
12167       *
12168       * Usually, you don't call `$digest()` directly in
12169       * {@link ng.directive:ngController controllers} or in
12170       * {@link ng.$compileProvider#directive directives}.
12171       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12172       * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12173       *
12174       * If you want to be notified whenever `$digest()` is called,
12175       * you can register a `watchExpression` function with
12176       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12177       *
12178       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12179       *
12180       * # Example
12181       * ```js
12182           var scope = ...;
12183           scope.name = 'misko';
12184           scope.counter = 0;
12185
12186           expect(scope.counter).toEqual(0);
12187           scope.$watch('name', function(newValue, oldValue) {
12188             scope.counter = scope.counter + 1;
12189           });
12190           expect(scope.counter).toEqual(0);
12191
12192           scope.$digest();
12193           // no variable change
12194           expect(scope.counter).toEqual(0);
12195
12196           scope.name = 'adam';
12197           scope.$digest();
12198           expect(scope.counter).toEqual(1);
12199       * ```
12200       *
12201       */
12202      $digest: function() {
12203        var watch, value, last,
12204            watchers,
12205            asyncQueue = this.$$asyncQueue,
12206            postDigestQueue = this.$$postDigestQueue,
12207            length,
12208            dirty, ttl = TTL,
12209            next, current, target = this,
12210            watchLog = [],
12211            logIdx, logMsg, asyncTask;
12212
12213        beginPhase('$digest');
12214
12215        lastDirtyWatch = null;
12216
12217        do { // "while dirty" loop
12218          dirty = false;
12219          current = target;
12220
12221          while(asyncQueue.length) {
12222            try {
12223              asyncTask = asyncQueue.shift();
12224              asyncTask.scope.$eval(asyncTask.expression);
12225            } catch (e) {
12226              clearPhase();
12227              $exceptionHandler(e);
12228            }
12229            lastDirtyWatch = null;
12230          }
12231
12232          traverseScopesLoop:
12233          do { // "traverse the scopes" loop
12234            if ((watchers = current.$$watchers)) {
12235              // process our watches
12236              length = watchers.length;
12237              while (length--) {
12238                try {
12239                  watch = watchers[length];
12240                  // Most common watches are on primitives, in which case we can short
12241                  // circuit it with === operator, only when === fails do we use .equals
12242                  if (watch) {
12243                    if ((value = watch.get(current)) !== (last = watch.last) &&
12244                        !(watch.eq
12245                            ? equals(value, last)
12246                            : (typeof value == 'number' && typeof last == 'number'
12247                               && isNaN(value) && isNaN(last)))) {
12248                      dirty = true;
12249                      lastDirtyWatch = watch;
12250                      watch.last = watch.eq ? copy(value) : value;
12251                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
12252                      if (ttl < 5) {
12253                        logIdx = 4 - ttl;
12254                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
12255                        logMsg = (isFunction(watch.exp))
12256                            ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12257                            : watch.exp;
12258                        logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12259                        watchLog[logIdx].push(logMsg);
12260                      }
12261                    } else if (watch === lastDirtyWatch) {
12262                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12263                      // have already been tested.
12264                      dirty = false;
12265                      break traverseScopesLoop;
12266                    }
12267                  }
12268                } catch (e) {
12269                  clearPhase();
12270                  $exceptionHandler(e);
12271                }
12272              }
12273            }
12274
12275            // Insanity Warning: scope depth-first traversal
12276            // yes, this code is a bit crazy, but it works and we have tests to prove it!
12277            // this piece should be kept in sync with the traversal in $broadcast
12278            if (!(next = (current.$$childHead ||
12279                (current !== target && current.$$nextSibling)))) {
12280              while(current !== target && !(next = current.$$nextSibling)) {
12281                current = current.$parent;
12282              }
12283            }
12284          } while ((current = next));
12285
12286          // `break traverseScopesLoop;` takes us to here
12287
12288          if((dirty || asyncQueue.length) && !(ttl--)) {
12289            clearPhase();
12290            throw $rootScopeMinErr('infdig',
12291                '{0} $digest() iterations reached. Aborting!\n' +
12292                'Watchers fired in the last 5 iterations: {1}',
12293                TTL, toJson(watchLog));
12294          }
12295
12296        } while (dirty || asyncQueue.length);
12297
12298        clearPhase();
12299
12300        while(postDigestQueue.length) {
12301          try {
12302            postDigestQueue.shift()();
12303          } catch (e) {
12304            $exceptionHandler(e);
12305          }
12306        }
12307      },
12308
12309
12310      /**
12311       * @ngdoc event
12312       * @name $rootScope.Scope#$destroy
12313       * @eventType broadcast on scope being destroyed
12314       *
12315       * @description
12316       * Broadcasted when a scope and its children are being destroyed.
12317       *
12318       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12319       * clean up DOM bindings before an element is removed from the DOM.
12320       */
12321
12322      /**
12323       * @ngdoc method
12324       * @name $rootScope.Scope#$destroy
12325       * @function
12326       *
12327       * @description
12328       * Removes the current scope (and all of its children) from the parent scope. Removal implies
12329       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12330       * propagate to the current scope and its children. Removal also implies that the current
12331       * scope is eligible for garbage collection.
12332       *
12333       * The `$destroy()` is usually used by directives such as
12334       * {@link ng.directive:ngRepeat ngRepeat} for managing the
12335       * unrolling of the loop.
12336       *
12337       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12338       * Application code can register a `$destroy` event handler that will give it a chance to
12339       * perform any necessary cleanup.
12340       *
12341       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12342       * clean up DOM bindings before an element is removed from the DOM.
12343       */
12344      $destroy: function() {
12345        // we can't destroy the root scope or a scope that has been already destroyed
12346        if (this.$$destroyed) return;
12347        var parent = this.$parent;
12348
12349        this.$broadcast('$destroy');
12350        this.$$destroyed = true;
12351        if (this === $rootScope) return;
12352
12353        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12354
12355        // sever all the references to parent scopes (after this cleanup, the current scope should
12356        // not be retained by any of our references and should be eligible for garbage collection)
12357        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12358        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12359        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12360        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12361
12362
12363        // All of the code below is bogus code that works around V8's memory leak via optimized code
12364        // and inline caches.
12365        //
12366        // see:
12367        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12368        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12369        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12370
12371        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12372            this.$$childTail = this.$root = null;
12373
12374        // don't reset these to null in case some async task tries to register a listener/watch/task
12375        this.$$listeners = {};
12376        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12377
12378        // prevent NPEs since these methods have references to properties we nulled out
12379        this.$destroy = this.$digest = this.$apply = noop;
12380        this.$on = this.$watch = function() { return noop; };
12381      },
12382
12383      /**
12384       * @ngdoc method
12385       * @name $rootScope.Scope#$eval
12386       * @function
12387       *
12388       * @description
12389       * Executes the `expression` on the current scope and returns the result. Any exceptions in
12390       * the expression are propagated (uncaught). This is useful when evaluating Angular
12391       * expressions.
12392       *
12393       * # Example
12394       * ```js
12395           var scope = ng.$rootScope.Scope();
12396           scope.a = 1;
12397           scope.b = 2;
12398
12399           expect(scope.$eval('a+b')).toEqual(3);
12400           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12401       * ```
12402       *
12403       * @param {(string|function())=} expression An angular expression to be executed.
12404       *
12405       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12406       *    - `function(scope)`: execute the function with the current `scope` parameter.
12407       *
12408       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12409       * @returns {*} The result of evaluating the expression.
12410       */
12411      $eval: function(expr, locals) {
12412        return $parse(expr)(this, locals);
12413      },
12414
12415      /**
12416       * @ngdoc method
12417       * @name $rootScope.Scope#$evalAsync
12418       * @function
12419       *
12420       * @description
12421       * Executes the expression on the current scope at a later point in time.
12422       *
12423       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12424       * that:
12425       *
12426       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12427       *     rendering).
12428       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12429       *     `expression` execution.
12430       *
12431       * Any exceptions from the execution of the expression are forwarded to the
12432       * {@link ng.$exceptionHandler $exceptionHandler} service.
12433       *
12434       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12435       * will be scheduled. However, it is encouraged to always call code that changes the model
12436       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12437       *
12438       * @param {(string|function())=} expression An angular expression to be executed.
12439       *
12440       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12441       *    - `function(scope)`: execute the function with the current `scope` parameter.
12442       *
12443       */
12444      $evalAsync: function(expr) {
12445        // if we are outside of an $digest loop and this is the first time we are scheduling async
12446        // task also schedule async auto-flush
12447        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12448          $browser.defer(function() {
12449            if ($rootScope.$$asyncQueue.length) {
12450              $rootScope.$digest();
12451            }
12452          });
12453        }
12454
12455        this.$$asyncQueue.push({scope: this, expression: expr});
12456      },
12457
12458      $$postDigest : function(fn) {
12459        this.$$postDigestQueue.push(fn);
12460      },
12461
12462      /**
12463       * @ngdoc method
12464       * @name $rootScope.Scope#$apply
12465       * @function
12466       *
12467       * @description
12468       * `$apply()` is used to execute an expression in angular from outside of the angular
12469       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12470       * Because we are calling into the angular framework we need to perform proper scope life
12471       * cycle of {@link ng.$exceptionHandler exception handling},
12472       * {@link ng.$rootScope.Scope#$digest executing watches}.
12473       *
12474       * ## Life cycle
12475       *
12476       * # Pseudo-Code of `$apply()`
12477       * ```js
12478           function $apply(expr) {
12479             try {
12480               return $eval(expr);
12481             } catch (e) {
12482               $exceptionHandler(e);
12483             } finally {
12484               $root.$digest();
12485             }
12486           }
12487       * ```
12488       *
12489       *
12490       * Scope's `$apply()` method transitions through the following stages:
12491       *
12492       * 1. The {@link guide/expression expression} is executed using the
12493       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12494       * 2. Any exceptions from the execution of the expression are forwarded to the
12495       *    {@link ng.$exceptionHandler $exceptionHandler} service.
12496       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12497       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12498       *
12499       *
12500       * @param {(string|function())=} exp An angular expression to be executed.
12501       *
12502       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12503       *    - `function(scope)`: execute the function with current `scope` parameter.
12504       *
12505       * @returns {*} The result of evaluating the expression.
12506       */
12507      $apply: function(expr) {
12508        try {
12509          beginPhase('$apply');
12510          return this.$eval(expr);
12511        } catch (e) {
12512          $exceptionHandler(e);
12513        } finally {
12514          clearPhase();
12515          try {
12516            $rootScope.$digest();
12517          } catch (e) {
12518            $exceptionHandler(e);
12519            throw e;
12520          }
12521        }
12522      },
12523
12524      /**
12525       * @ngdoc method
12526       * @name $rootScope.Scope#$on
12527       * @function
12528       *
12529       * @description
12530       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12531       * discussion of event life cycle.
12532       *
12533       * The event listener function format is: `function(event, args...)`. The `event` object
12534       * passed into the listener has the following attributes:
12535       *
12536       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12537       *     `$broadcast`-ed.
12538       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12539       *   - `name` - `{string}`: name of the event.
12540       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12541       *     further event propagation (available only for events that were `$emit`-ed).
12542       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12543       *     to true.
12544       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12545       *
12546       * @param {string} name Event name to listen on.
12547       * @param {function(event, ...args)} listener Function to call when the event is emitted.
12548       * @returns {function()} Returns a deregistration function for this listener.
12549       */
12550      $on: function(name, listener) {
12551        var namedListeners = this.$$listeners[name];
12552        if (!namedListeners) {
12553          this.$$listeners[name] = namedListeners = [];
12554        }
12555        namedListeners.push(listener);
12556
12557        var current = this;
12558        do {
12559          if (!current.$$listenerCount[name]) {
12560            current.$$listenerCount[name] = 0;
12561          }
12562          current.$$listenerCount[name]++;
12563        } while ((current = current.$parent));
12564
12565        var self = this;
12566        return function() {
12567          namedListeners[indexOf(namedListeners, listener)] = null;
12568          decrementListenerCount(self, 1, name);
12569        };
12570      },
12571
12572
12573      /**
12574       * @ngdoc method
12575       * @name $rootScope.Scope#$emit
12576       * @function
12577       *
12578       * @description
12579       * Dispatches an event `name` upwards through the scope hierarchy notifying the
12580       * registered {@link ng.$rootScope.Scope#$on} listeners.
12581       *
12582       * The event life cycle starts at the scope on which `$emit` was called. All
12583       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12584       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12585       * registered listeners along the way. The event will stop propagating if one of the listeners
12586       * cancels it.
12587       *
12588       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12589       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12590       *
12591       * @param {string} name Event name to emit.
12592       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12593       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
12594       */
12595      $emit: function(name, args) {
12596        var empty = [],
12597            namedListeners,
12598            scope = this,
12599            stopPropagation = false,
12600            event = {
12601              name: name,
12602              targetScope: scope,
12603              stopPropagation: function() {stopPropagation = true;},
12604              preventDefault: function() {
12605                event.defaultPrevented = true;
12606              },
12607              defaultPrevented: false
12608            },
12609            listenerArgs = concat([event], arguments, 1),
12610            i, length;
12611
12612        do {
12613          namedListeners = scope.$$listeners[name] || empty;
12614          event.currentScope = scope;
12615          for (i=0, length=namedListeners.length; i<length; i++) {
12616
12617            // if listeners were deregistered, defragment the array
12618            if (!namedListeners[i]) {
12619              namedListeners.splice(i, 1);
12620              i--;
12621              length--;
12622              continue;
12623            }
12624            try {
12625              //allow all listeners attached to the current scope to run
12626              namedListeners[i].apply(null, listenerArgs);
12627            } catch (e) {
12628              $exceptionHandler(e);
12629            }
12630          }
12631          //if any listener on the current scope stops propagation, prevent bubbling
12632          if (stopPropagation) return event;
12633          //traverse upwards
12634          scope = scope.$parent;
12635        } while (scope);
12636
12637        return event;
12638      },
12639
12640
12641      /**
12642       * @ngdoc method
12643       * @name $rootScope.Scope#$broadcast
12644       * @function
12645       *
12646       * @description
12647       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12648       * registered {@link ng.$rootScope.Scope#$on} listeners.
12649       *
12650       * The event life cycle starts at the scope on which `$broadcast` was called. All
12651       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12652       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12653       * scope and calls all registered listeners along the way. The event cannot be canceled.
12654       *
12655       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12656       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12657       *
12658       * @param {string} name Event name to broadcast.
12659       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12660       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
12661       */
12662      $broadcast: function(name, args) {
12663        var target = this,
12664            current = target,
12665            next = target,
12666            event = {
12667              name: name,
12668              targetScope: target,
12669              preventDefault: function() {
12670                event.defaultPrevented = true;
12671              },
12672              defaultPrevented: false
12673            },
12674            listenerArgs = concat([event], arguments, 1),
12675            listeners, i, length;
12676
12677        //down while you can, then up and next sibling or up and next sibling until back at root
12678        while ((current = next)) {
12679          event.currentScope = current;
12680          listeners = current.$$listeners[name] || [];
12681          for (i=0, length = listeners.length; i<length; i++) {
12682            // if listeners were deregistered, defragment the array
12683            if (!listeners[i]) {
12684              listeners.splice(i, 1);
12685              i--;
12686              length--;
12687              continue;
12688            }
12689
12690            try {
12691              listeners[i].apply(null, listenerArgs);
12692            } catch(e) {
12693              $exceptionHandler(e);
12694            }
12695          }
12696
12697          // Insanity Warning: scope depth-first traversal
12698          // yes, this code is a bit crazy, but it works and we have tests to prove it!
12699          // this piece should be kept in sync with the traversal in $digest
12700          // (though it differs due to having the extra check for $$listenerCount)
12701          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12702              (current !== target && current.$$nextSibling)))) {
12703            while(current !== target && !(next = current.$$nextSibling)) {
12704              current = current.$parent;
12705            }
12706          }
12707        }
12708
12709        return event;
12710      }
12711    };
12712
12713    var $rootScope = new Scope();
12714
12715    return $rootScope;
12716
12717
12718    function beginPhase(phase) {
12719      if ($rootScope.$$phase) {
12720        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12721      }
12722
12723      $rootScope.$$phase = phase;
12724    }
12725
12726    function clearPhase() {
12727      $rootScope.$$phase = null;
12728    }
12729
12730    function compileToFn(exp, name) {
12731      var fn = $parse(exp);
12732      assertArgFn(fn, name);
12733      return fn;
12734    }
12735
12736    function decrementListenerCount(current, count, name) {
12737      do {
12738        current.$$listenerCount[name] -= count;
12739
12740        if (current.$$listenerCount[name] === 0) {
12741          delete current.$$listenerCount[name];
12742        }
12743      } while ((current = current.$parent));
12744    }
12745
12746    /**
12747     * function used as an initial value for watchers.
12748     * because it's unique we can easily tell it apart from other values
12749     */
12750    function initWatchVal() {}
12751  }];
12752}
12753
12754/**
12755 * @description
12756 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
12757 */
12758function $$SanitizeUriProvider() {
12759  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12760    imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12761
12762  /**
12763   * @description
12764   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12765   * urls during a[href] sanitization.
12766   *
12767   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12768   *
12769   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12770   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12771   * regular expression. If a match is found, the original url is 
12771written into the dom. Otherwise,
12772   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12773   *
12774   * @param {RegExp=} regexp New regexp to whitelist urls with.
12775   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12776   *    chaining otherwise.
12777   */
12778  this.aHrefSanitizationWhitelist = function(regexp) {
12779    if (isDefined(regexp)) {
12780      aHrefSanitizationWhitelist = regexp;
12781      return this;
12782    }
12783    return aHrefSanitizationWhitelist;
12784  };
12785
12786
12787  /**
12788   * @description
12789   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12790   * urls during img[src] sanitization.
12791   *
12792   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12793   *
12794   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12795   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12796   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12797   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12798   *
12799   * @param {RegExp=} regexp New regexp to whitelist urls with.
12800   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12801   *    chaining otherwise.
12802   */
12803  this.imgSrcSanitizationWhitelist = function(regexp) {
12804    if (isDefined(regexp)) {
12805      imgSrcSanitizationWhitelist = regexp;
12806      return this;
12807    }
12808    return imgSrcSanitizationWhitelist;
12809  };
12810
12811  this.$get = function() {
12812    return function sanitizeUri(uri, isImage) {
12813      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12814      var normalizedVal;
12815      // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12816      if (!msie || msie >= 8 ) {
12817        normalizedVal = urlResolve(uri).href;
12818        if (normalizedVal !== '' && !normalizedVal.match(regex)) {
12819          return 'unsafe:'+normalizedVal;
12820        }
12821      }
12822      return uri;
12823    };
12824  };
12825}
12826
12827var $sceMinErr = minErr('$sce');
12828
12829var SCE_CONTEXTS = {
12830  HTML: 'html',
12831  CSS: 'css',
12832  URL: 'url',
12833  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
12834  // url.  (e.g. ng-include, script src, templateUrl)
12835  RESOURCE_URL: 'resourceUrl',
12836  JS: 'js'
12837};
12838
12839// Helper functions follow.
12840
12841// Copied from:
12842// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
12843// Prereq: s is a string.
12844function escapeForRegexp(s) {
12845  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
12846           replace(/\x08/g, '\\x08');
12847}
12848
12849
12850function adjustMatcher(matcher) {
12851  if (matcher === 'self') {
12852    return matcher;
12853  } else if (isString(matcher)) {
12854    // Strings match exactly except for 2 wildcards - '*' and '**'.
12855    // '*' matches any character except those from the set ':/.?&'.
12856    // '**' matches any character (like .* in a RegExp).
12857    // More than 2 *'s raises an error as it's ill defined.
12858    if (matcher.indexOf('***') > -1) {
12859      throw $sceMinErr('iwcard',
12860          'Illegal sequence *** in string matcher.  String: {0}', matcher);
12861    }
12862    matcher = escapeForRegexp(matcher).
12863                  replace('\\*\\*', '.*').
12864                  replace('\\*', '[^:/.?&;]*');
12865    return new RegExp('^' + matcher + '$');
12866  } else if (isRegExp(matcher)) {
12867    // The only other type of matcher allowed is a Regexp.
12868    // Match entire URL / disallow partial matches.
12869    // Flags are reset (i.e. no global, ignoreCase or multiline)
12870    return new RegExp('^' + matcher.source + '$');
12871  } else {
12872    throw $sceMinErr('imatcher',
12873        'Matchers may only be "self", string patterns or RegExp objects');
12874  }
12875}
12876
12877
12878function adjustMatchers(matchers) {
12879  var adjustedMatchers = [];
12880  if (isDefined(matchers)) {
12881    forEach(matchers, function(matcher) {
12882      adjustedMatchers.push(adjustMatcher(matcher));
12883    });
12884  }
12885  return adjustedMatchers;
12886}
12887
12888
12889/**
12890 * @ngdoc service
12891 * @name $sceDelegate
12892 * @function
12893 *
12894 * @description
12895 *
12896 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
12897 * Contextual Escaping (SCE)} services to AngularJS.
12898 *
12899 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
12900 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
12901 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
12902 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
12903 * work because `$sce` delegates to `$sceDelegate` for these operations.
12904 *
12905 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
12906 *
12907 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
12908 * can override it completely to change the behavior of `$sce`, the common case would
12909 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
12910 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
12911 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
12912 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
12913 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12914 */
12915
12916/**
12917 * @ngdoc provider
12918 * @name $sceDelegateProvider
12919 * @description
12920 *
12921 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
12922 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
12923 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
12924 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
12925 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
12926 *
12927 * For the general details about this service in Angular, read the main page for {@link ng.$sce
12928 * Strict Contextual Escaping (SCE)}.
12929 *
12930 * **Example**:  Consider the following case. <a name="example"></a>
12931 *
12932 * - your app is hosted at url `http://myapp.example.com/`
12933 * - but some of your templates are hosted on other domains you control such as
12934 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
12935 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
12936 *
12937 * Here is what a secure configuration for this scenario might look like:
12938 *
12939 * <pre class="prettyprint">
12940 *    angular.module('myApp', []).config(function($sceDelegateProvider) {
12941 *      $sceDelegateProvider.resourceUrlWhitelist([
12942 *        // Allow same origin resource loads.
12943 *        'self',
12944 *        // Allow loading from our assets domain.  Notice the difference between * and **.
12945 *        'http://srv*.assets.example.com/**']);
12946 *
12947 *      // The blacklist overrides the whitelist so the open redirect here is blocked.
12948 *      $sceDelegateProvider.resourceUrlBlacklist([
12949 *        'http://myapp.example.com/clickThru**']);
12950 *      });
12951 * </pre>
12952 */
12953
12954function $SceDelegateProvider() {
12955  this.SCE_CONTEXTS = SCE_CONTEXTS;
12956
12957  // Resource URLs can also be trusted by policy.
12958  var resourceUrlWhitelist = ['self'],
12959      resourceUrlBlacklist = [];
12960
12961  /**
12962   * @ngdoc method
12963   * @name $sceDelegateProvider#resourceUrlWhitelist
12964   * @function
12965   *
12966   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
12967   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12968   *     changes to the array are ignored.
12969   *
12970   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
12971   *     allowed in this array.
12972   *
12973   *     Note: **an empty whitelist array will block all URLs**!
12974   *
12975   * @return {Array} the currently set whitelist array.
12976   *
12977   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
12978   * same origin resource requests.
12979   *
12980   * @description
12981   * Sets/Gets the whitelist of trusted resource URLs.
12982   */
12983  this.resourceUrlWhitelist = function (value) {
12984    if (arguments.length) {
12985      resourceUrlWhitelist = adjustMatchers(value);
12986    }
12987    return resourceUrlWhitelist;
12988  };
12989
12990  /**
12991   * @ngdoc method
12992   * @name $sceDelegateProvider#resourceUrlBlacklist
12993   * @function
12994   *
12995   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
12996   *     provided.  This must be an array or null.  A snapshot of this array is used so further
12997   *     changes to the array are ignored.
12998   *
12999   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13000   *     allowed in this array.
13001   *
13002   *     The typical usage for the blacklist is to **block
13003   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13004   *     these would otherwise be trusted but actually return content from the redirected domain.
13005   *
vendor: 4,741 bytes, lines 13006-13133
13006   *     Finally, **the blacklist overrides the whitelist** and has the final say.
13007   *
13008   * @return {Array} the currently set blacklist array.
13009   *
13010   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13011   * is no blacklist.)
13012   *
13013   * @description
13014   * Sets/Gets the blacklist of trusted resource URLs.
13015   */
13016
13017  this.resourceUrlBlacklist = function (value) {
13018    if (arguments.length) {
13019      resourceUrlBlacklist = adjustMatchers(value);
13020    }
13021    return resourceUrlBlacklist;
13022  };
13023
13024  this.$get = ['$injector', function($injector) {
13025
13026    var htmlSanitizer = function htmlSanitizer(html) {
13027      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13028    };
13029
13030    if ($injector.has('$sanitize')) {
13031      htmlSanitizer = $injector.get('$sanitize');
13032    }
13033
13034
13035    function matchUrl(matcher, parsedUrl) {
13036      if (matcher === 'self') {
13037        return urlIsSameOrigin(parsedUrl);
13038      } else {
13039        // definitely a regex.  See adjustMatchers()
13040        return !!matcher.exec(parsedUrl.href);
13041      }
13042    }
13043
13044    function isResourceUrlAllowedByPolicy(url) {
13045      var parsedUrl = urlResolve(url.toString());
13046      var i, n, allowed = false;
13047      // Ensure that at least one item from the whitelist allows this url.
13048      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13049        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13050          allowed = true;
13051          break;
13052        }
13053      }
13054      if (allowed) {
13055        // Ensure that no item from the blacklist blocked this url.
13056        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13057          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13058            allowed = false;
13059            break;
13060          }
13061        }
13062      }
13063      return allowed;
13064    }
13065
13066    function generateHolderType(Base) {
13067      var holderType = function TrustedValueHolderType(trustedValue) {
13068        this.$$unwrapTrustedValue = function() {
13069          return trustedValue;
13070        };
13071      };
13072      if (Base) {
13073        holderType.prototype = new Base();
13074      }
13075      holderType.prototype.valueOf = function sceValueOf() {
13076        return this.$$unwrapTrustedValue();
13077      };
13078      holderType.prototype.toString = function sceToString() {
13079        return this.$$unwrapTrustedValue().toString();
13080      };
13081      return holderType;
13082    }
13083
13084    var trustedValueHolderBase = generateHolderType(),
13085        byType = {};
13086
13087    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13088    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13089    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13090    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13091    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13092
13093    /**
13094     * @ngdoc method
13095     * @name $sceDelegate#trustAs
13096     *
13097     * @description
13098     * Returns an object that is trusted by angular for use in specified strict
13099     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13100     * attribute interpolation, any dom event binding attribute interpolation
13101     * such as for onclick,  etc.) that uses the provided value.
13102     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13103     *
13104     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13105     *   resourceUrl, html, js and css.
13106     * @param {*} value The value that that should be considered trusted/safe.
13107     * @returns {*} A value that can be used to stand in for the provided `value` in places
13108     * where Angular expects a $sce.trustAs() return value.
13109     */
13110    function trustAs(type, trustedValue) {
13111      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13112      if (!Constructor) {
13113        throw $sceMinErr('icontext',
13114            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13115            type, trustedValue);
13116      }
13117      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13118        return trustedValue;
13119      }
13120      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13121      // mutable objects, we ensure here that the value passed in is actually a string.
13122      if (typeof trustedValue !== 'string') {
13123        throw $sceMinErr('itype',
13124            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13125            type);
13126      }
13127      return new Constructor(trustedValue);
13128    }
13129
13130    /**
13131     * @ngdoc method
13132     * @name $sceDelegate#valueOf
13133     *
13134     * @description
13135     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13136     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13137     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13138     *
13139     * If the passed parameter is not a value that had been returned by {@link
13140     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13141     *
13142     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13143     *      call or anything else.
13144     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13145     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13146     *     `value` unchanged.
13147     */
13148    function valueOf(maybeTrusted) {
13149      if (maybeTrusted instanceof trustedValueHolderBase) {
13150        return maybeTrusted.$$unwrapTrustedValue();
13151      } else {
13152        return maybeTrusted;
13153      }
13154    }
13155
13156    /**
13157     * @ngdoc method
13158     * @name $sceDelegate#getTrusted
13159     *
13160     * @description
13161     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13162     * returns the originally supplied value if the queried context type is a supertype of the
13163     * created type.  If this condition isn't satisfied, throws an exception.
13164     *
13165     * @param {string} type The kind of context in which this value is to be used.
13166     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13167     *     `$sceDelegate.trustAs`} call.
13168     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13169     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13170     */
13171    function getTrusted(type, maybeTrusted) {
13172      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13173        return maybeTrusted;
13174      }
13175      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13176      if (constructor && maybeTrusted instanceof constructor) {
13177        return maybeTrusted.$$unwrapTrustedValue();
13178      }
13179      // If we get here, then we may only take one of two actions.
13180      // 1. sanitize the value for the requested type, or
13181      // 2. throw an exception.
13182      if (type === SCE_CONTEXTS.RESOURCE_URL) {
13183        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13184          return maybeTrusted;
13185        } else {
13186          throw $sceMinErr('insecurl',
13187              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13188              maybeTrusted.toString());
13189        }
13190      } else if (type === SCE_CONTEXTS.HTML) {
13191        return htmlSanitizer(maybeTrusted);
13192      }
13193      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13194    }
13195
13196    return { trustAs: trustAs,
13197             getTrusted: getTrusted,
13198             valueOf: valueOf };
13199  }];
13200}
13201
13202
13203/**
13204 * @ngdoc provider
13205 * @name $sceProvider
13206 * @description
13207 *
13208 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13209 * -   enable/disable Strict Contextual Escaping (SCE) in a module
13210 * -   override the default implementation with a custom delegate
13211 *
13212 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13213 */
13214
13215/* jshint maxlen: false*/
13216
13217/**
13218 * @ngdoc service
13219 * @name $sce
13220 * @function
13221 *
13222 * @description
13223 *
13224 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13225 *
13226 * # Strict Contextual Escaping
13227 *
13228 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13229 * contexts to result in a value that is marked as safe to use for that context.  One example of
13230 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13231 * to these contexts as privileged or SCE contexts.
13232 *
13233 * As of version 1.2, Angular ships with SCE enabled by default.
13234 *
13235 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13236 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13237 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13238 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13239 * to the top of your HTML document.
13240 *
13241 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13242 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13243 *
13244 * Here's an example of a binding in a privileged context:
13245 *
13246 * <pre class="prettyprint">
13247 *     <input ng-model="userHtml">
13248 *     <div ng-bind-html="userHtml">
13249 * </pre>
13250 *
13251 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13252 * disabled, this application allows the user to render arbitrary HTML into the DIV.
13253 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13254 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13255 * security vulnerabilities.)
13256 *
13257 * For the case of HTML, you might use a library, either on the client side, or on the server side,
13258 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13259 *
13260 * How would you ensure that every place that used these types of bindings was bound to a value that
13261 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13262 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13263 * properties/fields and forgot to update the binding to the sanitized value?
13264 *
13265 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13266 * determine that something explicitly says it's safe to use a value for binding in that
13267 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13268 * for those values that you can easily tell are safe - because they were received from your server,
13269 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13270 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13271 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13272 *
13273 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13274 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13275 * obtain values that will be accepted by SCE / privileged contexts.
13276 *
13277 *
13278 * ## How does it work?
13279 *
13280 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13281 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13282 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13283 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13284 *
13285 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13286 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13287 * simplified):
13288 *
13289 * <pre class="prettyprint">
13290 *   var ngBindHtmlDirective = ['$sce', function($sce) {
13291 *     return function(scope, element, attr) {
13292 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13293 *         element.html(value || '');
13294 *       });
13295 *     };
13296 *   }];
13297 * </pre>
13298 *
13299 * ## Impact on loading templates
13300 *
13301 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13302 * `templateUrl`'s specified by {@link guide/directive directives}.
13303 *
13304 * By default, Angular only loads templates from the same domain and protocol as the application
13305 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13306 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13307 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13308 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13309 *
13310 * *Please note*:
13311 * The browser's
13312 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13313 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13314 * policy apply in addition to this and may further restrict whether the template is successfully
13315 * loaded.  This means that without the right CORS policy, loading templates from a different domain
13316 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13317 * browsers.
13318 *
13319 * ## This feels like too much overhead for the developer?
13320 *
13321 * It's important to remember that SCE only applies to interpolation expressions.
13322 *
13323 * If your expressions are constant literals, they're automatically trusted and you don't need to
13324 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13325 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13326 *
13327 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13328 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13329 *
13330 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13331 * templates in `ng-include` from your application's domain without having to even know about SCE.
13332 * It blocks loading templates from other domains or loading templates over http from an https
13333 * served document.  You can change these by setting your own custom {@link
13334 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13335 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13336 *
13337 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13338 * application that's secure and can be audited to verify that with much more ease than bolting
13339 * security onto an application later.
13340 *
13341 * <a name="contexts"></a>
13342 * ## What trusted context types are supported?
13343 *
13344 * | Context             | Notes          |
13345 * |---------------------|----------------|
13346 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
13347 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13348 * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
13349 * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
13350 * | `$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. |
13351 *
13352 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13353 *
13354 *  Each element in these arrays must be one of the following:
13355 *
13356 *  - **'self'**
13357 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13358 *      domain** as the application document using the **same protocol**.
13359 *  - **String** (except the special value `'self'`)
13360 *    - The string is matched against the full *normalized / absolute URL* of the resource
13361 *      being tested (substring matches are not good enough.)
13362 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13363 *      match themselves.
13364 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13365 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13366 *      in a whitelist.
13367 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13368 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13369 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13370 *      not have been the intention.)  It's usage at the very end of the path is ok.  (e.g.
13371 *      http://foo.example.com/templates/**).
13372 *  - **RegExp** (*see caveat below*)
13373 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13374 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13375 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13376 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13377 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13378 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13379 *      is highly recommended to use the string patterns and only fall back to regular expressions
13380 *      if they as a last resort.
13381 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13382 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13383 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13384 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13385 *    - If you are generating your JavaScript from some other templating engine (not
13386 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13387 *      remember to escape your regular expression (and be aware that you might need more than
13388 *      one level of escaping depending on your templating engine and the way you interpolated
13389 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13390 *      enough before coding your own.  e.g. Ruby has
13391 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13392 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13393 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13394 *      Closure library's [goog.string.regExpEscape(s)](
13395 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13396 *
13397 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13398 *
13399 * ## Show me an example using SCE.
13400 *
13401 * @example
13402<example module="mySceApp" deps="angular-sanitize.js">
13403<file name="index.html">
13404  <div ng-controller="myAppController as myCtrl">
13405    <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13406    <b>User comments</b><br>
13407    By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13408    $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13409    exploit.
13410    <div class="well">
13411      <div ng-repeat="userComment in myCtrl.userComments">
13412        <b>{{userComment.name}}</b>:
13413        <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13414        <br>
13415      </div>
13416    </div>
13417  </div>
13418</file>
13419
13420<file name="script.js">
13421  var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13422
13423  mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13424    var self = this;
13425    $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13426      self.userComments = userComments;
13427    });
13428    self.explicitlyTrustedHtml = $sce.trustAsHtml(
13429        '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13430        'sanitization.&quot;">Hover over this text.</span>');
13431  });
13432</file>
13433
13434<file name="test_data.json">
13435[
13436  { "name": "Alice",
13437    "htmlComment":
13438        "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13439  },
13440  { "name": "Bob",
13441    "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13442  }
13443]
13444</file>
13445
13446<file name="protractor.js" type="protractor">
13447  describe('SCE doc demo', function() {
13448    it('should sanitize untrusted values', function() {
13449      expect(element(by.css('.htmlComment')).getInnerHtml())
13450          .toBe('<span>Is <i>anyone</i> reading this?</span>');
13451    });
13452
13453    it('should NOT sanitize explicitly trusted values', function() {
13454      expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13455          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13456          'sanitization.&quot;">Hover over this text.</span>');
13457    });
13458  });
13459</file>
13460</example>
13461 *
13462 *
13463 *
13464 * ## Can I disable SCE completely?
13465 *
13466 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13467 * for little coding overhead.  It will be much harder to take an SCE disabled application and
13468 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13469 * for cases where you have a lot of existing code that was written before SCE was introduced and
13470 * you're migrating them a module at a time.
13471 *
13472 * That said, here's how you can completely disable SCE:
13473 *
13474 * <pre class="prettyprint">
13475 *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13476 *     // Completely disable SCE.  For demonstration purposes only!
13477 *     // Do not use in new projects.
13478 *     $sceProvider.enabled(false);
13479 *   });
13480 * </pre>
13481 *
13482 */
13483/* jshint maxlen: 100 */
13484
13485function $SceProvider() {
13486  var enabled = true;
13487
13488  /**
13489   * @ngdoc method
13490   * @name $sceProvider#enabled
13491   * @function
13492   *
13493   * @param {boolean=} value If provided, then enables/disables SCE.
13494   * @return {boolean} true if SCE is enabled, false otherwise.
13495   *
13496   * @description
13497   * Enables/disables SCE and returns the current value.
13498   */
13499  this.enabled = function (value) {
13500    if (arguments.length) {
13501      enabled = !!value;
13502    }
13503    return enabled;
13504  };
13505
13506
13507  /* Design notes on the default implementation for SCE.
13508   *
13509   * The API contract for the SCE delegate
13510   * -------------------------------------
13511   * The SCE delegate object must provide the following 3 methods:
13512   *
13513   * - trustAs(contextEnum, value)
13514   *     This method is used to tell the SCE service that the provided value is OK to use in the
13515   *     contexts specified by contextEnum.  It must return an object that will be accepted by
13516   *     getTrusted() for a compatible contextEnum and return this value.
13517   *
13518   * - valueOf(value)
13519   *     For values that were not produced by trustAs(), return them as is.  For values that were
13520   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13521   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13522   *     such a value.
13523   *
13524   * - getTrusted(contextEnum, value)
13525   *     This function should return the a value that is safe to use in the context specified by
13526   *     contextEnum or throw and exception otherwise.
13527   *
13528   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13529   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13530   * instance, an implementation could maintain a registry of all trusted objects by context.  In
13531   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13532   * return the same object passed in if it was found in the registry under a compatible context or
13533   * throw an exception otherwise.  An implementation might only wrap values some of the time based
13534   * on some criteria.  getTrusted() might return a value and not throw an exception for special
13535   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13536   *
13537   *
13538   * A note on the inheritance model for SCE contexts
13539   * ------------------------------------------------
13540   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13541   * is purely an implementation details.
13542   *
13543   * The contract is simply this:
13544   *
13545   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13546   *     will also succeed.
13547   *
13548   * Inheritance happens to capture this in a natural way.  In some future, we
13549   * may not use inheritance anymore.  That is OK because no code outside of
13550   * sce.js and sceSpecs.js would need to be aware of this detail.
13551   */
13552
13553  this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
13554                $parse,   $sniffer,   $sceDelegate) {
13555    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13556    // the "expression(javascript expression)" syntax which is insecure.
13557    if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13558      throw $sceMinErr('iequirks',
13559        'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13560        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13561        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13562    }
13563
13564    var sce = copy(SCE_CONTEXTS);
13565
13566    /**
13567     * @ngdoc method
13568     * @name $sce#isEnabled
13569     * @function
13570     *
13571     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13572     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13573     *
13574     * @description
13575     * Returns a boolean indicating if SCE is enabled.
13576     */
13577    sce.isEnabled = function () {
13578      return enabled;
13579    };
13580    sce.trustAs = $sceDelegate.trustAs;
13581    sce.getTrusted = $sceDelegate.getTrusted;
13582    sce.valueOf = $sceDelegate.valueOf;
13583
13584    if (!enabled) {
13585      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
13586      sce.valueOf = identity;
13587    }
13588
13589    /**
13590     * @ngdoc method
13591     * @name $sce#parse
13592     *
13593     * @description
13594     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13595     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13596     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
13597     * *result*)}
13598     *
13599     * @param {string} type The kind of SCE context in which this result will be used.
13600     * @param {string} expression String expression to compile.
13601     * @returns {function(context, locals)} a function which represents the compiled expression:
13602     *
13603     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13604     *      are evaluated against (typically a scope object).
13605     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13606     *      `context`.
13607     */
13608    sce.parseAs = function sceParseAs(type, expr) {
13609      var parsed = $parse(expr);
13610      if (parsed.literal && parsed.constant) {
13611        return parsed;
13612      } else {
13613        return function sceParseAsTrusted(self, locals) {
13614          return sce.getTrusted(type, parsed(self, locals));
13615        };
13616      }
13617    };
13618
13619    /**
13620     * @ngdoc method
13621     * @name $sce#trustAs
13622     *
13623     * @description
13624     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
13625     * returns an object that is trusted by angular for use in specified strict contextual
13626     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13627     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13628     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13629     * escaping.
13630     *
13631     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13632     *   resource_url, html, js and css.
13633     * @param {*} value The value that that should be considered trusted/safe.
13634     * @returns {*} A value that can be used to stand in for the provided `value` in places
13635     * where Angular expects a $sce.trustAs() return value.
13636     */
13637
13638    /**
13639     * @ngdoc method
13640     * @name $sce#trustAsHtml
13641     *
13642     * @description
13643     * Shorthand method.  `$sce.trustAsHtml(value)` →
13644     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13645     *
13646     * @param {*} value The value to trustAs.
13647     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
13648     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13649     *     only accept expressions that are either literal constants or are the
13650     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13651     */
13652
13653    /**
13654     * @ngdoc method
13655     * @name $sce#trustAsUrl
13656     *
13657     * @description
13658     * Shorthand method.  `$sce.trustAsUrl(value)` →
13659     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13660     *
13661     * @param {*} value The value to trustAs.
13662     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
13663     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13664     *     only accept expressions that are either literal constants or are the
13665     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13666     */
13667
13668    /**
13669     * @ngdoc method
13670     * @name $sce#trustAsResourceUrl
13671     *
13672     * @description
13673     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13674     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13675     *
13676     * @param {*} value The value to trustAs.
13677     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
13678     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13679     *     only accept expressions that are either literal constants or are the return
13680     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
13681     */
13682
13683    /**
13684     * @ngdoc method
13685     * @name $sce#trustAsJs
13686     *
13687     * @description
13688     * Shorthand method.  `$sce.trustAsJs(value)` →
13689     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13690     *
13691     * @param {*} value The value to trustAs.
13692     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
13693     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13694     *     only accept expressions that are either literal constants or are the
13695     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13696     */
13697
13698    /**
13699     * @ngdoc method
13700     * @name $sce#getTrusted
13701     *
13702     * @description
13703     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
13704     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
13705     * originally supplied value if the queried context type is a supertype of the created type.
13706     * If this condition isn't satisfied, throws an exception.
13707     *
13708     * @param {string} type The kind of context in which this value is to be used.
13709     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
13710     *                         call.
13711     * @returns {*} The value the was originally provided to
13712     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
13713     *              Otherwise, throws an exception.
13714     */
13715
13716    /**
13717     * @ngdoc method
13718     * @name $sce#getTrustedHtml
13719     *
13720     * @description
13721     * Shorthand method.  `$sce.getTrustedHtml(value)` →
13722     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13723     *
13724     * @param {*} value The value to pass to `$sce.getTrusted`.
13725     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13726     */
13727
13728    /**
13729     * @ngdoc method
13730     * @name $sce#getTrustedCss
13731     *
13732     * @description
13733     * Shorthand method.  `$sce.getTrustedCss(value)` →
13734     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13735     *
13736     * @param {*} value The value to pass to `$sce.getTrusted`.
13737     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13738     */
13739
13740    /**
13741     * @ngdoc method
13742     * @name $sce#getTrustedUrl
13743     *
13744     * @description
13745     * Shorthand method.  `$sce.getTrustedUrl(value)` →
13746     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13747     *
13748     * @param {*} value The value to pass to `$sce.getTrusted`.
13749     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13750     */
13751
13752    /**
13753     * @ngdoc method
13754     * @name $sce#getTrustedResourceUrl
13755     *
13756     * @description
13757     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
13758     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
13759     *
13760     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
13761     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
13762     */
13763
13764    /**
13765     * @ngdoc method
13766     * @name $sce#getTrustedJs
13767     *
13768     * @description
13769     * Shorthand method.  `$sce.getTrustedJs(value)` →
13770     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
13771     *
13772     * @param {*} value The value to pass to `$sce.getTrusted`.
13773     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
13774     */
13775
13776    /**
13777     * @ngdoc method
13778     * @name $sce#parseAsHtml
13779     *
13780     * @description
13781     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
13782     *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
13783     *
13784     * @param {string} expression String expression to compile.
13785     * @returns {function(context, locals)} a function which represents the compiled expression:
13786     *
13787     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13788     *      are evaluated against (typically a scope object).
13789     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13790     *      `context`.
13791     */
13792
13793    /**
13794     * @ngdoc method
13795     * @name $sce#parseAsCss
13796     *
13797     * @description
13798     * Shorthand method.  `$sce.parseAsCss(value)` →
13799     *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
13800     *
13801     * @param {string} expression String expression to compile.
13802     * @returns {function(context, locals)} a function which represents the compiled expression:
13803     *
13804     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13805     *      are evaluated against (typically a scope object).
13806     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13807     *      `context`.
13808     */
13809
13810    /**
13811     * @ngdoc method
13812     * @name $sce#parseAsUrl
13813     *
13814     * @description
13815     * Shorthand method.  `$sce.parseAsUrl(value)` →
13816     *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
13817     *
13818     * @param {string} expression String expression to compile.
13819     * @returns {function(context, locals)} a function which represents the compiled expression:
13820     *
13821     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13822     *      are evaluated against (typically a scope object).
13823     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13824     *      `context`.
13825     */
13826
13827    /**
13828     * @ngdoc method
13829     * @name $sce#parseAsResourceUrl
13830     *
13831     * @description
13832     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
13833     *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
13834     *
13835     * @param {string} expression String expression to compile.
13836     * @returns {function(context, locals)} a function which represents the compiled expression:
13837     *
13838     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13839     *      are evaluated against (typically a scope object).
13840     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13841     *      `context`.
13842     */
13843
13844    /**
13845     * @ngdoc method
13846     * @name $sce#parseAsJs
13847     *
13848     * @description
13849     * Shorthand method.  `$sce.parseAsJs(value)` →
13850     *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
13851     *
13852     * @param {string} expression String expression to compile.
13853     * @returns {function(context, locals)} a function which represents the compiled expression:
13854     *
13855     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13856     *      are evaluated against (typically a scope object).
13857     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13858     *      `context`.
13859     */
13860
13861    // Shorthand delegations.
13862    var parse = sce.parseAs,
13863        getTrusted = sce.getTrusted,
13864        trustAs = sce.trustAs;
13865
13866    forEach(SCE_CONTEXTS, function (enumValue, name) {
13867      var lName = lowercase(name);
13868      sce[camelCase("parse_as_" + lName)] = function (expr) {
13869        return parse(enumValue, expr);
13870      };
13871      sce[camelCase("get_trusted_" + lName)] = function (value) {
13872        return getTrusted(enumValue, value);
13873      };
13874      sce[camelCase("trust_as_" + lName)] = function (value) {
13875        return trustAs(enumValue, value);
13876      };
13877    });
13878
13879    return sce;
13880  }];
13881}
13882
13883/**
13884 * !!! This is an undocumented "private" service !!!
13885 *
13886 * @name $sniffer
13887 * @requires $window
13888 * @requires $document
13889 *
13890 * @property {boolean} history Does the browser support html5 history api ?
13891 * @property {boolean} hashchange Does the browser support hashchange event ?
13892 * @property {boolean} transitions Does the browser support CSS transition events ?
13893 * @property {boolean} animations Does the browser support CSS animation events ?
13894 *
13895 * @description
13896 * This is very simple implementation of testing browser's features.
13897 */
13898function $SnifferProvider() {
13899  this.$get = ['$window', '$document', function($window, $document) {
13900    var eventSupport = {},
13901        android =
13902          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
13903        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
13904        document = $document[0] || {},
13905        documentMode = document.documentMode,
13906        vendorPrefix,
13907        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
13908        bodyStyle = document.body && document.body.style,
13909        transitions = false,
13910        animations = false,
13911        match;
13912
13913    if (bodyStyle) {
13914      for(var prop in bodyStyle) {
13915        if(match = vendorRegex.exec(prop)) {
13916          vendorPrefix = match[0];
13917          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
13918          break;
13919        }
13920      }
13921
13922      if(!vendorPrefix) {
13923        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
13924      }
13925
13926      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
13927      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
13928
13929      if (android && (!transitions||!animations)) {
13930        transitions = isString(document.body.style.webkitTransition);
13931        animations = isString(document.body.style.webkitAnimation);
13932      }
13933    }
13934
13935
13936    return {
13937      // Android has history.pushState, but it does not update location correctly
13938      // so let's not use the history API at all.
13939      // http://code.google.com/p/android/issues/detail?id=17471
13940      // https://github.com/angular/angular.js/issues/904
13941
13942      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
13943      // so let's not use the history API also
13944      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
13945      // jshint -W018
13946      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
13947      // jshint +W018
13948      hashchange: 'onhashchange' in $window &&
13949                  // IE8 compatible mode lies
13950                  (!documentMode || documentMode > 7),
13951      hasEvent: function(event) {
13952        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
13953        // it. In particular the event is not fired when backspace or delete key are pressed or
13954        // when cut operation is performed.
13955        if (event == 'input' && msie == 9) return false;
13956
13957        if (isUndefined(eventSupport[event])) {
13958          var divElm = document.createElement('div');
13959          eventSupport[event] = 'on' + event in divElm;
13960        }
13961
13962        return eventSupport[event];
13963      },
13964      csp: csp(),
13965      vendorPrefix: vendorPrefix,
13966      transitions : transitions,
13967      animations : animations,
13968      android: android,
13969      msie : msie,
13970      msieDocumentMode: documentMode
13971    };
13972  }];
13973}
13974
13975function $TimeoutProvider() {
13976  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
13977       function($rootScope,   $browser,   $q,   $exceptionHandler) {
13978    var deferreds = {};
13979
13980
13981     /**
13982      * @ngdoc service
13983      * @name $timeout
13984      *
13985      * @description
13986      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
13987      * block and delegates any exceptions to
13988      * {@link ng.$exceptionHandler $exceptionHandler} service.
13989      *
13990      * The return value of registering a timeout function is a promise, which will be resolved when
13991      * the timeout is reached and the timeout function is executed.
13992      *
13993      * To cancel a timeout request, call `$timeout.cancel(promise)`.
13994      *
13995      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
13996      * synchronously flush the queue of deferred functions.
13997      *
13998      * @param {function()} fn A function, whose execution should be delayed.
13999      * @param {number=} [delay=0] Delay in milliseconds.
14000      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14001      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14002      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14003      *   promise will be resolved with is the return value of the `fn` function.
14004      *
14005      */
14006    function timeout(fn, delay, invokeApply) {
14007      var deferred = $q.defer(),
14008          promise = deferred.promise,
14009          skipApply = (isDefined(invokeApply) && !invokeApply),
14010          timeoutId;
14011
14012      timeoutId = $browser.defer(function() {
14013        try {
14014          deferred.resolve(fn());
14015        } catch(e) {
14016          deferred.reject(e);
14017          $exceptionHandler(e);
14018        }
14019        finally {
14020          delete deferreds[promise.$$timeoutId];
14021        }
14022
14023        if (!skipApply) $rootScope.$apply();
14024      }, delay);
14025
14026      promise.$$timeoutId = timeoutId;
14027      deferreds[timeoutId] = deferred;
14028
14029      return promise;
14030    }
14031
14032
14033     /**
14034      * @ngdoc method
14035      * @name $timeout#cancel
14036      *
14037      * @description
14038      * Cancels a task associated with the `promise`. As a result of this, the promise will be
14039      * resolved with a rejection.
14040      *
14041      * @param {Promise=} promise Promise returned by the `$timeout` function.
14042      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14043      *   canceled.
14044      */
14045    timeout.cancel = function(promise) {
14046      if (promise && promise.$$timeoutId in deferreds) {
14047        deferreds[promise.$$timeoutId].reject('canceled');
14048        delete deferreds[promise.$$timeoutId];
14049        return $browser.defer.cancel(promise.$$timeoutId);
14050      }
14051      return false;
14052    };
14053
14054    return timeout;
14055  }];
14056}
14057
14058// NOTE:  The usage of window and document instead of $window and $document here is
14059// deliberate.  This service depends on the specific behavior of anchor nodes created by the
14060// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14061// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14062// doesn't know about mocked locations and resolves URLs to the real document - which is
14063// exactly the behavior needed here.  There is little value is mocking these out for this
14064// service.
14065var urlParsingNode = document.createElement("a");
14066var originUrl = urlResolve(window.location.href, true);
14067
14068
14069/**
14070 *
14071 * Implementation Notes for non-IE browsers
14072 * ----------------------------------------
14073 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14074 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14075 * URL will be resolved into an absolute URL in the context of the application document.
14076 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14077 * properties are all populated to reflect the normalized URL.  This approach has wide
14078 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14079 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14080 *
14081 * Implementation Notes for IE
14082 * ---------------------------
14083 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14084 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14085 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14086 * work around that by performing the parsing in a 2nd step by taking a previously normalized
14087 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14088 * properties such as protocol, hostname, port, etc.
14089 *
14090 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14091 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14092 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14093 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14094 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14095 * method and IE < 8 is unsupported.
14096 *
14097 * References:
14098 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14099 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14100 *   http://url.spec.whatwg.org/#urlutils
14101 *   https://github.com/angular/angular.js/pull/2902
14102 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14103 *
14104 * @function
14105 * @param {string} url The URL to be parsed.
14106 * @description Normalizes and parses a URL.
14107 * @returns {object} Returns the normalized URL as a dictionary.
14108 *
14109 *   | member name   | Description    |
14110 *   |---------------|----------------|
14111 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14112 *   | protocol      | The protocol including the trailing colon                              |
14113 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14114 *   | search        | The search params, minus the question mark                             |
14115 *   | hash          | The hash string, minus the hash symbol
14116 *   | hostname      | The hostname
14117 *   | port          | The port, without ":"
14118 *   | pathname      | The pathname, beginning with "/"
14119 *
14120 */
14121function urlResolve(url, base) {
14122  var href = url;
14123
14124  if (msie) {
14125    // Normalize before parse.  Refer Implementation Notes on why this is
14126    // done in two steps on IE.
14127    urlParsingNode.setAttribute("href", href);
14128    href = urlParsingNode.href;
14129  }
14130
14131  urlParsingNode.setAttribute('href', href);
14132
14133  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14134  return {
14135    href: urlParsingNode.href,
14136    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14137    host: urlParsingNode.host,
14138    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14139    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14140    hostname: urlParsingNode.hostname,
14141    port: urlParsingNode.port,
14142    pathname: (urlParsingNode.pathname.charAt(0) === '/')
14143      ? urlParsingNode.pathname
14144      : '/' + urlParsingNode.pathname
14145  };
14146}
14147
14148/**
14149 * Parse a request URL and determine whether this is a same-origin request as the application document.
14150 *
14151 * @param {string|object} requestUrl The url of the request as a string that will be resolved
14152 * or a parsed URL object.
14153 * @returns {boolean} Whether the request is for the same origin as the application document.
14154 */
14155function urlIsSameOrigin(requestUrl) {
14156  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14157  return (parsed.protocol === originUrl.protocol &&
14158          parsed.host === originUrl.host);
14159}
14160
14161/**
14162 * @ngdoc service
14163 * @name $window
14164 *
14165 * @description
14166 * A reference to the browser's `window` object. While `window`
14167 * is globally available in JavaScript, it causes testability problems, because
14168 * it is a global variable. In angular we always refer to it through the
14169 * `$window` service, so it may be overridden, removed or mocked for testing.
14170 *
14171 * Expressions, like the one defined for the `ngClick` directive in the example
14172 * below, are evaluated with respect to the current scope.  Therefore, there is
14173 * no risk of inadvertently coding in a dependency on a global value in such an
14174 * expression.
14175 *
14176 * @example
14177   <example>
14178     <file name="index.html">
14179       <script>
14180         function Ctrl($scope, $window) {
14181           $scope.greeting = 'Hello, World!';
14182           $scope.doGreeting = function(greeting) {
14183               $window.alert(greeting);
14184           };
14185         }
14186       </script>
14187       <div ng-controller="Ctrl">
14188         <input type="text" ng-model="greeting" />
14189         <button ng-click="doGreeting(greeting)">ALERT</button>
14190       </div>
14191     </file>
14192     <file name="protractor.js" type="protractor">
14193      it('should display the greeting in the input box', function() {
14194       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14195       // If we click the button it will block the test runner
14196       // element(':button').click();
14197      });
14198     </file>
14199   </example>
14200 */
14201function $WindowProvider(){
14202  this.$get = valueFn(window);
14203}
14204
14205/**
14206 * @ngdoc provider
14207 * @name $filterProvider
14208 * @description
14209 *
14210 * Filters are just functions which transform input to an output. However filters need to be
14211 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14212 * annotated with dependencies and is responsible for creating a filter function.
14213 *
14214 * ```js
14215 *   // Filter registration
14216 *   function MyModule($provide, $filterProvider) {
14217 *     // create a service to demonstrate injection (not always needed)
14218 *     $provide.value('greet', function(name){
14219 *       return 'Hello ' + name + '!';
14220 *     });
14221 *
14222 *     // register a filter factory which uses the
14223 *     // greet service to demonstrate DI.
14224 *     $filterProvider.register('greet', function(greet){
14225 *       // return the filter function which uses the greet service
14226 *       // to generate salutation
14227 *       return function(text) {
14228 *         // filters need to be forgiving so check input validity
14229 *         return text && greet(text) || text;
14230 *       };
14231 *     });
14232 *   }
14233 * ```
14234 *
14235 * The filter function is registered with the `$injector` under the filter name suffix with
14236 * `Filter`.
14237 *
14238 * ```js
14239 *   it('should be the same instance', inject(
14240 *     function($filterProvider) {
14241 *       $filterProvider.register('reverse', function(){
14242 *         return ...;
14243 *       });
14244 *     },
14245 *     function($filter, reverseFilter) {
14246 *       expect($filter('reverse')).toBe(reverseFilter);
14247 *     });
14248 * ```
14249 *
14250 *
14251 * For more information about how angular filters work, and how to create your own filters, see
14252 * {@link guide/filter Filters} in the Angular Developer Guide.
14253 */
14254/**
14255 * @ngdoc method
14256 * @name $filterProvider#register
14257 * @description
14258 * Register filter factory function.
14259 *
14260 * @param {String} name Name of the filter.
14261 * @param {Function} fn The filter factory function which is injectable.
14262 */
14263
14264
14265/**
14266 * @ngdoc service
14267 * @name $filter
14268 * @function
14269 * @description
14270 * Filters are used for formatting data displayed to the user.
14271 *
14272 * The general syntax in templates is as follows:
14273 *
14274 *         {{ expression [| filter_name[:parameter_value] ... ] }}
14275 *
14276 * @param {String} name Name of the filter function to retrieve
14277 * @return {Function} the filter function
14278 */
14279$FilterProvider.$inject = ['$provide'];
14280function $FilterProvider($provide) {
14281  var suffix = 'Filter';
14282
14283  /**
14284   * @ngdoc method
14285   * @name $controllerProvider#register
14286   * @param {string|Object} name Name of the filter function, or an object map of filters where
14287   *    the keys are the filter names and the values are the filter factories.
14288   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14289   *    of the registered filter instances.
14290   */
14291  function register(name, factory) {
14292    if(isObject(name)) {
14293      var filters = {};
14294      forEach(name, function(filter, key) {
14295        filters[key] = register(key, filter);
14296      });
14297      return filters;
14298    } else {
14299      return $provide.factory(name + suffix, factory);
14300    }
14301  }
14302  this.register = register;
14303
14304  this.$get = ['$injector', function($injector) {
14305    return function(name) {
14306      return $injector.get(name + suffix);
14307    };
14308  }];
14309
14310  ////////////////////////////////////////
14311
14312  /* global
14313    currencyFilter: false,
14314    dateFilter: false,
14315    filterFilter: false,
14316    jsonFilter: false,
14317    limitToFilter: false,
14318    lowercaseFilter: false,
14319    numberFilter: false,
14320    orderByFilter: false,
14321    uppercaseFilter: false,
14322  */
14323
14324  register('currency', currencyFilter);
14325  register('date', dateFilter);
14326  register('filter', filterFilter);
14327  register('json', jsonFilter);
14328  register('limitTo', limitToFilter);
14329  register('lowercase', lowercaseFilter);
14330  register('number', numberFilter);
14331  register('orderBy', orderByFilter);
14332  register('uppercase', uppercaseFilter);
14333}
14334
14335/**
14336 * @ngdoc filter
14337 * @name filter
14338 * @function
14339 *
14340 * @description
14341 * Selects a subset of items from `array` and returns it as a new array.
14342 *
14343 * @param {Array} array The source array.
14344 * @param {string|Object|function()} expression The predicate to be used for selecting items from
14345 *   `array`.
14346 *
14347 *   Can be one of:
14348 *
14349 *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14350 *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14351 *     will be returned. The predicate can be negated by prefixing the string with `!`.
14352 *
14353 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14354 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14355 *     which have property `name` containing "M" and property `phone` containing "1". A special
14356 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14357 *     property of the object. That's equivalent to the simple substring match with a `string`
14358 *     as described above.
14359 *
14360 *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14361 *     called for each element of `array`. The final result is an array of those elements that
14362 *     the predicate returned true for.
14363 *
14364 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14365 *     determining if the expected value (from the filter expression) and actual value (from
14366 *     the object in the array) should be considered a match.
14367 *
14368 *   Can be one of:
14369 *
14370 *     - `function(actual, expected)`:
14371 *       The function will be given the object value and the predicate value to compare and
14372 *       should return true if the item should be included in filtered result.
14373 *
14374 *     - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14375 *       this is essentially strict comparison of expected and actual.
14376 *
14377 *     - `false|undefined`: A short hand for a function which will look for a substring match in case
14378 *       insensitive way.
14379 *
14380 * @example
14381   <example>
14382     <file name="index.html">
14383       <div ng-init="friends = [{name:'John', phone:'555-1276'},
14384                                {name:'Mary', phone:'800-BIG-MARY'},
14385                                {name:'Mike', phone:'555-4321'},
14386                                {name:'Adam', phone:'555-5678'},
14387                                {name:'Julie', phone:'555-8765'},
14388                                {name:'Juliette', phone:'555-5678'}]"></div>
14389
14390       Search: <input ng-model="searchText">
14391       <table id="searchTextResults">
14392         <tr><th>Name</th><th>Phone</th></tr>
14393         <tr ng-repeat="friend in friends | filter:searchText">
14394           <td>{{friend.name}}</td>
14395           <td>{{friend.phone}}</td>
14396         </tr>
14397       </table>
14398       <hr>
14399       Any: <input ng-model="search.$"> <br>
14400       Name only <input ng-model="search.name"><br>
14401       Phone only <input ng-model="search.phone"><br>
14402       Equality <input type="checkbox" ng-model="strict"><br>
14403       <table id="searchObjResults">
14404         <tr><th>Name</th><th>Phone</th></tr>
14405         <tr ng-repeat="friendObj in friends | filter:search:strict">
14406           <td>{{friendObj.name}}</td>
14407           <td>{{friendObj.phone}}</td>
14408         </tr>
14409       </table>
14410     </file>
14411     <file name="protractor.js" type="protractor">
14412       var expectFriendNames = function(expectedNames, key) {
14413         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14414           arr.forEach(function(wd, i) {
14415             expect(wd.getText()).toMatch(expectedNames[i]);
14416           });
14417         });
14418       };
14419
14420       it('should search across all fields when filtering with a string', function() {
14421         var searchText = element(by.model('searchText'));
14422         searchText.clear();
14423         searchText.sendKeys('m');
14424         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14425
14426         searchText.clear();
14427         searchText.sendKeys('76');
14428         expectFriendNames(['John', 'Julie'], 'friend');
14429       });
14430
14431       it('should search in specific fields when filtering with a predicate object', function() {
14432         var searchAny = element(by.model('search.$'));
14433         searchAny.clear();
14434         searchAny.sendKeys('i');
14435         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14436       });
14437       it('should use a equal comparison when comparator is true', function() {
14438         var searchName = element(by.model('search.name'));
14439         var strict = element(by.model('strict'));
14440         searchName.clear();
14441         searchName.sendKeys('Julie');
14442         strict.click();
14443         expectFriendNames(['Julie'], 'friendObj');
14444       });
14445     </file>
14446   </example>
14447 */
14448function filterFilter() {
14449  return function(array, expression, comparator) {
14450    if (!isArray(array)) return array;
14451
14452    var comparatorType = typeof(comparator),
14453        predicates = [];
14454
14455    predicates.check = function(value) {
14456      for (var j = 0; j < predicates.length; j++) {
14457        if(!predicates[j](value)) {
14458          return false;
14459        }
14460      }
14461      return true;
14462    };
14463
14464    if (comparatorType !== 'function') {
14465      if (comparatorType === 'boolean' && comparator) {
14466        comparator = function(obj, text) {
14467          return angular.equals(obj, text);
14468        };
14469      } else {
14470        comparator = function(obj, text) {
14471          if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14472            for (var objKey in obj) {
14473              if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14474                  comparator(obj[objKey], text[objKey])) {
14475                return true;
14476              }
14477            }
14478            return false;
14479          }
14480          text = (''+text).toLowerCase();
14481          return (''+obj).toLowerCase().indexOf(text) > -1;
14482        };
14483      }
14484    }
14485
14486    var search = function(obj, text){
14487      if (typeof text == 'string' && text.charAt(0) === '!') {
14488        return !search(obj, text.substr(1));
14489      }
14490      switch (typeof obj) {
14491        case "boolean":
14492        case "number":
14493        case "string":
14494          return comparator(obj, text);
14495        case "object":
14496          switch (typeof text) {
14497            case "object":
14498              return comparator(obj, text);
14499            default:
14500              for ( var objKey in obj) {
14501                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14502                  return true;
14503                }
14504              }
14505              break;
14506          }
14507          return false;
14508        case "array":
14509          for ( var i = 0; i < obj.length; i++) {
14510            if (search(obj[i], text)) {
14511              return true;
14512            }
14513          }
14514          return false;
14515        default:
14516          return false;
14517      }
14518    };
14519    switch (typeof expression) {
14520      case "boolean":
14521      case "number":
14522      case "string":
14523        // Set up expression object and fall through
14524        expression = {$:expression};
14525        // jshint -W086
14526      case "object":
14527        // jshint +W086
14528        for (var key in expression) {
14529          (function(path) {
14530            if (typeof expression[path] == 'undefined') return;
14531            predicates.push(function(value) {
14532              return search(path == '$' ? value : (value && value[path]), expression[path]);
14533            });
14534          })(key);
14535        }
14536        break;
14537      case 'function':
14538        predicates.push(expression);
14539        break;
14540      default:
14541        return array;
14542    }
14543    var filtered = [];
14544    for ( var j = 0; j < array.length; j++) {
14545      var value = array[j];
14546      if (predicates.check(value)) {
14547        filtered.push(value);
14548      }
14549    }
14550    return filtered;
14551  };
14552}
14553
14554/**
14555 * @ngdoc filter
14556 * @name currency
14557 * @function
14558 *
14559 * @description
14560 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14561 * symbol for current locale is used.
14562 *
14563 * @param {number} amount Input to filter.
14564 * @param {string=} symbol Currency symbol or identifier to be displayed.
14565 * @returns {string} Formatted number.
14566 *
14567 *
14568 * @example
14569   <example>
14570     <file name="index.html">
14571       <script>
14572         function Ctrl($scope) {
14573           $scope.amount = 1234.56;
14574         }
14575       </script>
14576       <div ng-controller="Ctrl">
14577         <input type="number" ng-model="amount"> <br>
14578         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14579         custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14580       </div>
14581     </file>
14582     <file name="protractor.js" type="protractor">
14583       it('should init with 1234.56', function() {
14584         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14585         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14586       });
14587       it('should update', function() {
14588         if (browser.params.browser == 'safari') {
14589           // Safari does not understand the minus key. See
14590           // https://github.com/angular/protractor/issues/481
14591           return;
14592         }
14593         element(by.model('amount')).clear();
14594         element(by.model('amount')).sendKeys('-1234');
14595         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14596         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14597       });
14598     </file>
14599   </example>
14600 */
14601currencyFilter.$inject = ['$locale'];
14602function currencyFilter($locale) {
14603  var formats = $locale.NUMBER_FORMATS;
14604  return function(amount, currencySymbol){
14605    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14606    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14607                replace(/\u00A4/g, currencySymbol);
14608  };
14609}
14610
14611/**
14612 * @ngdoc filter
14613 * @name number
14614 * @function
14615 *
14616 * @description
14617 * Formats a number as text.
14618 *
14619 * If the input is not a number an empty string is returned.
14620 *
14621 * @param {number|string} number Number to format.
14622 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14623 * If this is not provided then the fraction size is computed from the current locale's number
14624 * formatting pattern. In the case of the default locale, it will be 3.
14625 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14626 *
14627 * @example
14628   <example>
14629     <file name="index.html">
14630       <script>
14631         function Ctrl($scope) {
14632           $scope.val = 1234.56789;
14633         }
14634       </script>
14635       <div ng-controller="Ctrl">
14636         Enter number: <input ng-model='val'><br>
14637         Default formatting: <span id='number-default'>{{val | number}}</span><br>
14638         No fractions: <span>{{val | number:0}}</span><br>
14639         Negative number: <span>{{-val | number:4}}</span>
14640       </div>
14641     </file>
14642     <file name="protractor.js" type="protractor">
14643       it('should format numbers', function() {
14644         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14645         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14646         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14647       });
14648
14649       it('should update', function() {
14650         element(by.model('val')).clear();
14651         element(by.model('val')).sendKeys('3374.333');
14652         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14653         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14654         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14655      });
14656     </file>
14657   </example>
14658 */
14659
14660
14661numberFilter.$inject = ['$locale'];
14662function numberFilter($locale) {
14663  var formats = $locale.NUMBER_FORMATS;
14664  return function(number, fractionSize) {
14665    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14666      fractionSize);
14667  };
14668}
14669
14670var DECIMAL_SEP = '.';
14671function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14672  if (number == null || !isFinite(number) || isObject(number)) return '';
14673
14674  var isNegative = number < 0;
14675  number = Math.abs(number);
14676  var numStr = number + '',
14677      formatedText = '',
14678      parts = [];
14679
14680  var hasExponent = false;
14681  if (numStr.indexOf('e') !== -1) {
14682    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14683    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14684      numStr = '0';
14685    } else {
14686      formatedText = numStr;
14687      hasExponent = true;
14688    }
14689  }
14690
14691  if (!hasExponent) {
14692    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14693
14694    // determine fractionSize if it is not specified
14695    if (isUndefined(fractionSize)) {
14696      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14697    }
14698
14699    var pow = Math.pow(10, fractionSize);
14700    number = Math.round(number * pow) / pow;
14701    var fraction = ('' + number).split(DECIMAL_SEP);
14702    var whole = fraction[0];
14703    fraction = fraction[1] || '';
14704
14705    var i, pos = 0,
14706        lgroup = pattern.lgSize,
14707        group = pattern.gSize;
14708
14709    if (whole.length >= (lgroup + group)) {
14710      pos = whole.length - lgroup;
14711      for (i = 0; i < pos; i++) {
14712        if ((pos - i)%group === 0 && i !== 0) {
14713          formatedText += groupSep;
14714        }
14715        formatedText += whole.charAt(i);
14716      }
14717    }
14718
14719    for (i = pos; i < whole.length; i++) {
14720      if ((whole.length - i)%lgroup === 0 && i !== 0) {
14721        formatedText += groupSep;
14722      }
14723      formatedText += whole.charAt(i);
14724    }
14725
14726    // format fraction part.
14727    while(fraction.length < fractionSize) {
14728      fraction += '0';
14729    }
14730
14731    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
14732  } else {
14733
14734    if (fractionSize > 0 && number > -1 && number < 1) {
14735      formatedText = number.toFixed(fractionSize);
14736    }
14737  }
14738
14739  parts.push(isNegative ? pattern.negPre : pattern.posPre);
14740  parts.push(formatedText);
14741  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
14742  return parts.join('');
14743}
14744
14745function padNumber(num, digits, trim) {
14746  var neg = '';
14747  if (num < 0) {
14748    neg =  '-';
14749    num = -num;
14750  }
14751  num = '' + num;
14752  while(num.length < digits) num = '0' + num;
14753  if (trim)
14754    num = num.substr(num.length - digits);
14755  return neg + num;
14756}
14757
14758
14759function dateGetter(name, size, offset, trim) {
14760  offset = offset || 0;
14761  return function(date) {
14762    var value = date['get' + name]();
14763    if (offset > 0 || value > -offset)
14764      value += offset;
14765    if (value === 0 && offset == -12 ) value = 12;
14766    return padNumber(value, size, trim);
14767  };
14768}
14769
14770function dateStrGetter(name, shortForm) {
14771  return function(date, formats) {
14772    var value = date['get' + name]();
14773    var get = uppercase(shortForm ? ('SHORT' + name) : name);
14774
14775    return formats[get][value];
14776  };
14777}
14778
14779function timeZoneGetter(date) {
14780  var zone = -1 * date.getTimezoneOffset();
14781  var paddedZone = (zone >= 0) ? "+" : "";
14782
14783  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
14784                padNumber(Math.abs(zone % 60), 2);
14785
14786  return paddedZone;
14787}
14788
14789function ampmGetter(date, formats) {
14790  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
14791}
14792
14793var DATE_FORMATS = {
14794  yyyy: dateGetter('FullYear', 4),
14795    yy: dateGetter('FullYear', 2, 0, true),
14796     y: dateGetter('FullYear', 1),
14797  MMMM: dateStrGetter('Month'),
14798   MMM: dateStrGetter('Month', true),
14799    MM: dateGetter('Month', 2, 1),
14800     M: dateGetter('Month', 1, 1),
14801    dd: dateGetter('Date', 2),
14802     d: dateGetter('Date', 1),
14803    HH: dateGetter('Hours', 2),
14804     H: dateGetter('Hours', 1),
14805    hh: dateGetter('Hours', 2, -12),
14806     h: dateGetter('Hours', 1, -12),
14807    mm: dateGetter('Minutes', 2),
14808     m: dateGetter('Minutes', 1),
14809    ss: dateGetter('Seconds', 2),
14810     s: dateGetter('Seconds', 1),
14811     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
14812     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
14813   sss: dateGetter('Milliseconds', 3),
14814  EEEE: dateStrGetter('Day'),
14815   EEE: dateStrGetter('Day', true),
14816     a: ampmGetter,
14817     Z: timeZoneGetter
14818};
14819
14820var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
14821    NUMBER_STRING = /^\-?\d+$/;
14822
14823/**
14824 * @ngdoc filter
14825 * @name date
14826 * @function
14827 *
14828 * @description
14829 *   Formats `date` to a string based on the requested `format`.
14830 *
14831 *   `format` string can be composed of the following elements:
14832 *
14833 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
14834 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
14835 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
14836 *   * `'MMMM'`: Month in year (January-December)
14837 *   * `'MMM'`: Month in year (Jan-Dec)
14838 *   * `'MM'`: Month in year, padded (01-12)
14839 *   * `'M'`: Month in year (1-12)
14840 *   * `'dd'`: Day in month, padded (01-31)
14841 *   * `'d'`: Day in month (1-31)
14842 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
14843 *   * `'EEE'`: Day in Week, (Sun-Sat)
14844 *   * `'HH'`: Hour in day, padded (00-23)
14845 *   * `'H'`: Hour in day (0-23)
14846 *   * `'hh'`: Hour in am/pm, padded (01-12)
14847 *   * `'h'`: Hour in am/pm, (1-12)
14848 *   * `'mm'`: Minute in hour, padded (00-59)
14849 *   * `'m'`: Minute in hour (0-59)
14850 *   * `'ss'`: Second in minute, padded (00-59)
14851 *   * `'s'`: Second in minute (0-59)
14852 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
14853 *   * `'a'`: am/pm marker
14854 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
14855 *
14856 *   `format` string can also be one of the following predefined
14857 *   {@link guide/i18n localizable formats}:
14858 *
14859 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
14860 *     (e.g. Sep 3, 2010 12:05:08 pm)
14861 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
14862 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
14863 *     (e.g. Friday, September 3, 2010)
14864 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
14865 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
14866 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
14867 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
14868 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
14869 *
14870 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
14871 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
14872 *   (e.g. `"h 'o''clock'"`).
14873 *
14874 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
14875 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
14876 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
14877 *    specified in the string input, the time is considered to be in the local timezone.
14878 * @param {string=} format Formatting rules (see Description). If not specified,
14879 *    `mediumDate` is used.
14880 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
14881 *
14882 * @example
14883   <example>
14884     <file name="index.html">
14885       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
14886           <span>{{1288323623006 | date:'medium'}}</span><br>
14887       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
14888          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
14889       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
14890          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
14891     </file>
14892     <file name="protractor.js" type="protractor">
14893       it('should format date', function() {
14894         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
14895            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
14896         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
14897            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
14898         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
14899            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
14900       });
14901     </file>
14902   </example>
14903 */
14904dateFilter.$inject = ['$locale'];
14905function dateFilter($locale) {
14906
14907
14908  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
14909                     // 1        2       3         4          5          6          7          8  9     10      11
14910  function jsonStringToDate(string) {
14911    var match;
14912    if (match = string.match(R_ISO8601_STR)) {
14913      var date = new Date(0),
14914          tzHour = 0,
14915          tzMin  = 0,
14916          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
14917          timeSetter = match[8] ? date.setUTCHours : date.setHours;
14918
14919      if (match[9]) {
14920        tzHour = int(match[9] + match[10]);
14921        tzMin = int(match[9] + match[11]);
14922      }
14923      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
14924      var h = int(match[4]||0) - tzHour;
14925      var m = int(match[5]||0) - tzMin;
14926      var s = int(match[6]||0);
14927      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
14928      timeSetter.call(date, h, m, s, ms);
14929      return date;
14930    }
14931    return string;
14932  }
14933
14934
14935  return function(date, format) {
14936    var text = '',
14937        parts = [],
14938        fn, match;
14939
14940    format = format || 'mediumDate';
14941    format = $locale.DATETIME_FORMATS[format] || format;
14942    if (isString(date)) {
14943      if (NUMBER_STRING.test(date)) {
14944        date = int(date);
14945      } else {
14946        date = jsonStringToDate(date);
14947      }
14948    }
14949
14950    if (isNumber(date)) {
14951      date = new Date(date);
14952    }
14953
14954    if (!isDate(date)) {
14955      return date;
14956    }
14957
14958    while(format) {
14959      match = DATE_FORMATS_SPLIT.exec(format);
14960      if (match) {
14961        parts = concat(parts, match, 1);
14962        format = parts.pop();
14963      } else {
14964        parts.push(format);
14965        format = null;
14966      }
14967    }
14968
14969    forEach(parts, function(value){
14970      fn = DATE_FORMATS[value];
14971      text += fn ? fn(date, $locale.DATETIME_FORMATS)
14972                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
14973    });
14974
14975    return text;
14976  };
14977}
14978
14979
14980/**
14981 * @ngdoc filter
14982 * @name json
14983 * @function
14984 *
14985 * @description
14986 *   Allows you to convert a JavaScript object into JSON string.
14987 *
14988 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
14989 *   the binding is automatically converted to JSON.
14990 *
14991 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
14992 * @returns {string} JSON string.
14993 *
14994 *
14995 * @example
14996   <example>
14997     <file name="index.html">
14998       <pre>{{ {'name':'value'} | json }}</pre>
14999     </file>
15000     <file name="protractor.js" type="protractor">
15001       it('should jsonify filtered objects', function() {
15002         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15003       });
15004     </file>
15005   </example>
15006 *
15007 */
15008function jsonFilter() {
15009  return function(object) {
15010    return toJson(object, true);
15011  };
15012}
15013
15014
15015/**
15016 * @ngdoc filter
15017 * @name lowercase
15018 * @function
15019 * @description
15020 * Converts string to lowercase.
15021 * @see angular.lowercase
15022 */
15023var lowercaseFilter = valueFn(lowercase);
15024
15025
15026/**
15027 * @ngdoc filter
15028 * @name uppercase
15029 * @function
15030 * @description
15031 * Converts string to uppercase.
15032 * @see angular.uppercase
15033 */
15034var uppercaseFilter = valueFn(uppercase);
15035
15036/**
15037 * @ngdoc filter
15038 * @name limitTo
15039 * @function
15040 *
15041 * @description
15042 * Creates a new array or string containing only a specified number of elements. The elements
15043 * are taken from either the beginning or the end of the source array or string, as specified by
15044 * the value and sign (positive or negative) of `limit`.
15045 *
15046 * @param {Array|string} input Source array or string to be limited.
15047 * @param {string|number} limit The length of the returned array or string. If the `limit` number
15048 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15049 *     If the number is negative, `limit` number  of items from the end of the source array/string
15050 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15051 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15052 *     had less than `limit` elements.
15053 *
15054 * @example
15055   <example>
15056     <file name="index.html">
15057       <script>
15058         function Ctrl($scope) {
15059           $scope.numbers = [1,2,3,4,5,6,7,8,9];
15060           $scope.letters = "abcdefghi";
15061           $scope.numLimit = 3;
15062           $scope.letterLimit = 3;
15063         }
15064       </script>
15065       <div ng-controller="Ctrl">
15066         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
15067         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15068         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
15069         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15070       </div>
15071     </file>
15072     <file name="protractor.js" type="protractor">
15073       var numLimitInput = element(by.model('numLimit'));
15074       var letterLimitInput = element(by.model('letterLimit'));
15075       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15076       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15077
15078       it('should limit the number array to first three items', function() {
15079         expect(numLimitInput.getAttribute('value')).toBe('3');
15080         expect(letterLimitInput.getAttribute('value')).toBe('3');
15081         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15082         expect(limitedLetters.getText()).toEqual('Output letters: abc');
15083       });
15084
15085       it('should update the output when -3 is entered', function() {
15086         numLimitInput.clear();
15087         numLimitInput.sendKeys('-3');
15088         letterLimitInput.clear();
15089         letterLimitInput.sendKeys('-3');
15090         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15091         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15092       });
15093
15094       it('should not exceed the maximum size of input array', function() {
15095         numLimitInput.clear();
15096         numLimitInput.sendKeys('100');
15097         letterLimitInput.clear();
15098         letterLimitInput.sendKeys('100');
15099         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15100         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15101       });
15102     </file>
15103   </example>
15104 */
15105function limitToFilter(){
15106  return function(input, limit) {
15107    if (!isArray(input) && !isString(input)) return input;
15108
15109    limit = int(limit);
15110
15111    if (isString(input)) {
15112      //NaN check on limit
15113      if (limit) {
15114        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
15115      } else {
15116        return "";
15117      }
15118    }
15119
15120    var out = [],
15121      i, n;
15122
15123    // if abs(limit) exceeds maximum length, trim it
15124    if (limit > input.length)
15125      limit = input.length;
15126    else if (limit < -input.length)
15127      limit = -input.length;
15128
15129    if (limit > 0) {
15130      i = 0;
15131      n = limit;
15132    } else {
15133      i = input.length + limit;
15134      n = input.length;
15135    }
15136
15137    for (; i<n; i++) {
15138      out.push(input[i]);
15139    }
15140
15141    return out;
15142  };
15143}
15144
15145/**
15146 * @ngdoc filter
15147 * @name orderBy
15148 * @function
15149 *
15150 * @description
15151 * Orders a specified `array` by the `expression` predicate.
15152 *
15153 * @param {Array} array The array to sort.
15154 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
15155 *    used by the comparator to determine the order of elements.
15156 *
15157 *    Can be one of:
15158 *
15159 *    - `function`: Getter function. The result of this function will be sorted using the
15160 *      `<`, `=`, `>` operator.
15161 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
15162 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
15163 *      ascending or descending sort order (for example, +name or -name).
15164 *    - `Array`: An array of function or string predicates. The first predicate in the array
15165 *      is used for sorting, but when two items are equivalent, the next predicate is used.
15166 *
15167 * @param {boolean=} reverse Reverse the order of the array.
15168 * @returns {Array} Sorted copy of the source array.
15169 *
15170 * @example
15171   <example>
15172     <file name="index.html">
15173       <script>
15174         function Ctrl($scope) {
15175           $scope.friends =
15176               [{name:'John', phone:'555-1212', age:10},
15177                {name:'Mary', phone:'555-9876', age:19},
15178                {name:'Mike', phone:'555-4321', age:21},
15179                {name:'Adam', phone:'555-5678', age:35},
15180                {name:'Julie', phone:'555-8765', age:29}]
15181           $scope.predicate = '-age';
15182         }
15183       </script>
15184       <div ng-controller="Ctrl">
15185         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15186         <hr/>
15187         [ <a href="" ng-click="predicate=''">unsorted</a> ]
15188         <table class="friend">
15189           <tr>
15190             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15191                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15192             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15193             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15194           </tr>
15195           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15196             <td>{{friend.name}}</td>
15197             <td>{{friend.phone}}</td>
15198             <td>{{friend.age}}</td>
15199           </tr>
15200         </table>
15201       </div>
15202     </file>
15203   </example>
15204 */
15205orderByFilter.$inject = ['$parse'];
15206function orderByFilter($parse){
15207  return function(array, sortPredicate, reverseOrder) {
15208    if (!isArray(array)) return array;
15209    if (!sortPredicate) return array;
15210    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15211    sortPredicate = map(sortPredicate, function(predicate){
15212      var descending = false, get = predicate || identity;
15213      if (isString(predicate)) {
15214        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15215          descending = predicate.charAt(0) == '-';
15216          predicate = predicate.substring(1);
15217        }
15218        get = $parse(predicate);
15219        if (get.constant) {
15220          var key = get();
15221          return reverseComparator(function(a,b) {
15222            return compare(a[key], b[key]);
15223          }, descending);
15224        }
15225      }
15226      return reverseComparator(function(a,b){
15227        return compare(get(a),get(b));
15228      }, descending);
15229    });
15230    var arrayCopy = [];
15231    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
15232    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
15233
15234    function comparator(o1, o2){
15235      for ( var i = 0; i < sortPredicate.length; i++) {
15236        var comp = sortPredicate[i](o1, o2);
15237        if (comp !== 0) return comp;
15238      }
15239      return 0;
15240    }
15241    function reverseComparator(comp, descending) {
15242      return toBoolean(descending)
15243          ? function(a,b){return comp(b,a);}
15244          : comp;
15245    }
15246    function compare(v1, v2){
15247      var t1 = typeof v1;
15248      var t2 = typeof v2;
15249      if (t1 == t2) {
15250        if (t1 == "string") {
15251           v1 = v1.toLowerCase();
15252           v2 = v2.toLowerCase();
15253        }
15254        if (v1 === v2) return 0;
15255        return v1 < v2 ? -1 : 1;
15256      } else {
15257        return t1 < t2 ? -1 : 1;
15258      }
15259    }
15260  };
15261}
15262
15263function ngDirective(directive) {
15264  if (isFunction(directive)) {
15265    directive = {
15266      link: directive
15267    };
15268  }
15269  directive.restrict = directive.restrict || 'AC';
15270  return valueFn(directive);
15271}
15272
15273/**
15274 * @ngdoc directive
15275 * @name a
15276 * @restrict E
15277 *
15278 * @description
15279 * Modifies the default behavior of the html A tag so that the default action is prevented when
15280 * the href attribute is empty.
15281 *
15282 * This change permits the easy creation of action links with the `ngClick` directive
15283 * without changing the location or causing page reloads, e.g.:
15284 * `<a href="" ng-click="list.addItem()">Add Item</a>`
15285 */
15286var htmlAnchorDirective = valueFn({
15287  restrict: 'E',
15288  compile: function(element, attr) {
15289
15290    if (msie <= 8) {
15291
15292      // turn <a href ng-click="..">link</a> into a stylable link in IE
15293      // but only if it doesn't have name attribute, in which case it's an anchor
15294      if (!attr.href && !attr.name) {
15295        attr.$set('href', '');
15296      }
15297
15298      // add a comment node to anchors to workaround IE bug that causes element content to be reset
15299      // to new attribute content if attribute is updated with value containing @ and element also
15300      // contains value with @
15301      // see issue #1949
15302      element.append(document.createComment('IE fix'));
15303    }
15304
15305    if (!attr.href && !attr.xlinkHref && !attr.name) {
15306      return function(scope, element) {
15307        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15308        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15309                   'xlink:href' : 'href';
15310        element.on('click', function(event){
15311          // if we have no href url, then don't navigate anywhere.
15312          if (!element.attr(href)) {
15313            event.preventDefault();
15314          }
15315        });
15316      };
15317    }
15318  }
15319});
15320
15321/**
15322 * @ngdoc directive
15323 * @name ngHref
15324 * @restrict A
15325 * @priority 99
15326 *
15327 * @description
15328 * Using Angular markup like `{{hash}}` in an href attribute will
15329 * make the link go to the wrong URL if the user clicks it before
15330 * Angular has a chance to replace the `{{hash}}` markup with its
15331 * value. Until Angular replaces the markup the link will be broken
15332 * and will most likely return a 404 error.
15333 *
15334 * The `ngHref` directive solves this problem.
15335 *
15336 * The wrong way to write it:
15337 * ```html
15338 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15339 * ```
15340 *
15341 * The correct way to write it:
15342 * ```html
15343 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15344 * ```
15345 *
15346 * @element A
15347 * @param {template} ngHref any string which can contain `{{}}` markup.
15348 *
15349 * @example
15350 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15351 * in links and their different behaviors:
15352    <example>
15353      <file name="index.html">
15354        <input ng-model="value" /><br />
15355        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15356        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15357        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15358        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15359        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15360        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15361      </file>
15362      <file name="protractor.js" type="protractor">
15363        it('should execute ng-click but not reload when href without value', function() {
15364          element(by.id('link-1')).click();
15365          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15366          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15367        });
15368
15369        it('should execute ng-click but not reload when href empty string', function() {
15370          element(by.id('link-2')).click();
15371          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15372          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15373        });
15374
15375        it('should execute ng-click and change url when ng-href specified', function() {
15376          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15377
15378          element(by.id('link-3')).click();
15379
15380          // At this point, we navigate away from an Angular page, so we need
15381          // to use browser.driver to get the base webdriver.
15382
15383          browser.wait(function() {
15384            return browser.driver.getCurrentUrl().then(function(url) {
15385              return url.match(/\/123$/);
15386            });
15387          }, 1000, 'page should navigate to /123');
15388        });
15389
15390        xit('should execute ng-click but not reload when href empty string and name specified', function() {
15391          element(by.id('link-4')).click();
15392          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15393          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15394        });
15395
15396        it('should execute ng-click but not reload when no href but name specified', function() {
15397          element(by.id('link-5')).click();
15398          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15399          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15400        });
15401
15402        it('should only change url when only ng-href', function() {
15403          element(by.model('value')).clear();
15404          element(by.model('value')).sendKeys('6');
15405          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15406
15407          element(by.id('link-6')).click();
15408
15409          // At this point, we navigate away from an Angular page, so we need
15410          // to use browser.driver to get the base webdriver.
15411          browser.wait(function() {
15412            return browser.driver.getCurrentUrl().then(function(url) {
15413              return url.match(/\/6$/);
15414            });
15415          }, 1000, 'page should navigate to /6');
15416        });
15417      </file>
15418    </example>
15419 */
15420
15421/**
15422 * @ngdoc directive
15423 * @name ngSrc
15424 * @restrict A
15425 * @priority 99
15426 *
15427 * @description
15428 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15429 * work right: The browser will fetch from the URL with the literal
15430 * text `{{hash}}` until Angular replaces the expression inside
15431 * `{{hash}}`. The `ngSrc` directive solves this problem.
15432 *
15433 * The buggy way to write it:
15434 * ```html
15435 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15436 * ```
15437 *
15438 * The correct way to write it:
15439 * ```html
15440 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15441 * ```
15442 *
15443 * @element IMG
15444 * @param {template} ngSrc any string which can contain `{{}}` markup.
15445 */
15446
15447/**
15448 * @ngdoc directive
15449 * @name ngSrcset
15450 * @restrict A
15451 * @priority 99
15452 *
15453 * @description
15454 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15455 * work right: The browser will fetch from the URL with the literal
15456 * text `{{hash}}` until Angular replaces the expression inside
15457 * `{{hash}}`. The `ngSrcset` directive solves this problem.
15458 *
15459 * The buggy way to write it:
15460 * ```html
15461 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15462 * ```
15463 *
15464 * The correct way to write it:
15465 * ```html
15466 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15467 * ```
15468 *
15469 * @element IMG
15470 * @param {template} ngSrcset any string which can contain `{{}}` markup.
15471 */
15472
15473/**
15474 * @ngdoc directive
15475 * @name ngDisabled
15476 * @restrict A
15477 * @priority 100
15478 *
15479 * @description
15480 *
15481 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15482 * ```html
15483 * <div ng-init="scope = { isDisabled: false }">
15484 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15485 * </div>
15486 * ```
15487 *
15488 * The HTML specification does not require browsers to preserve the values of boolean attributes
15489 * such as disabled. (Their presence means true and their absence means false.)
15490 * If we put an Angular interpolation expression into such an attribute then the
15491 * binding information would be lost when the browser removes the attribute.
15492 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15493 * This complementary directive is not removed by the browser and so provides
15494 * a permanent reliable place to store the binding information.
15495 *
15496 * @example
15497    <example>
15498      <file name="index.html">
15499        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15500        <button ng-model="button" ng-disabled="checked">Button</button>
15501      </file>
15502      <file name="protractor.js" type="protractor">
15503        it('should toggle button', function() {
15504          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
15505          element(by.model('checked')).click();
15506          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
15507        });
15508      </file>
15509    </example>
15510 *
15511 * @element INPUT
15512 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
15513 *     then special attribute "disabled" will be set on the element
15514 */
15515
15516
15517/**
15518 * @ngdoc directive
15519 * @name ngChecked
15520 * @restrict A
15521 * @priority 100
15522 *
15523 * @description
15524 * The HTML specification does not require browsers to preserve the values of boolean attributes
15525 * such as checked. (Their presence means true and their absence means false.)
15526 * If we put an Angular interpolation expression into such an attribute then the
15527 * binding information would be lost when the browser removes the attribute.
15528 * The `ngChecked` directive solves this problem for the `checked` attribute.
15529 * This complementary directive is not removed by the browser and so provides
15530 * a permanent reliable place to store the binding information.
15531 * @example
15532    <example>
15533      <file name="index.html">
15534        Check me to check both: <input type="checkbox" ng-model="master"><br/>
15535        <input id="checkSlave" type="checkbox" ng-checked="master">
15536      </file>
15537      <file name="protractor.js" type="protractor">
15538        it('should check both checkBoxes', function() {
15539          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15540          element(by.model('master')).click();
15541          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15542        });
15543      </file>
15544    </example>
15545 *
15546 * @element INPUT
15547 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
15548 *     then special attribute "checked" will be set on the element
15549 */
15550
15551
15552/**
15553 * @ngdoc directive
15554 * @name ngReadonly
15555 * @restrict A
15556 * @priority 100
15557 *
15558 * @description
15559 * The HTML specification does not require browsers to preserve the values of boolean attributes
15560 * such as readonly. (Their presence means true and their absence means false.)
15561 * If we put an Angular interpolation expression into such an attribute then the
15562 * binding information would be lost when the browser removes the attribute.
15563 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15564 * This complementary directive is not removed by the browser and so provides
15565 * a permanent reliable place to store the binding information.
15566 * @example
15567    <example>
15568      <file name="index.html">
15569        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15570        <input type="text" ng-readonly="checked" value="I'm Angular"/>
15571      </file>
15572      <file name="protractor.js" type="protractor">
15573        it('should toggle readonly attr', function() {
15574          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
15575          element(by.model('checked')).click();
15576          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
15577        });
15578      </file>
15579    </example>
15580 *
15581 * @element INPUT
15582 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
15583 *     then special attribute "readonly" will be set on the element
15584 */
15585
15586
15587/**
15588 * @ngdoc directive
15589 * @name ngSelected
15590 * @restrict A
15591 * @priority 100
15592 *
15593 * @description
15594 * The HTML specification does not require browsers to preserve the values of boolean attributes
15595 * such as selected. (Their presence means true and their absence means false.)
15596 * If we put an Angular interpolation expression into such an attribute then the
15597 * binding information would be lost when the browser removes the attribute.
15598 * The `ngSelected` directive solves this problem for the `selected` attribute.
15599 * This complementary directive is not removed by the browser and so provides
15600 * a permanent reliable place to store the binding information.
15601 *
15602 * @example
15603    <example>
15604      <file name="index.html">
15605        Check me to select: <input type="checkbox" ng-model="selected"><br/>
15606        <select>
15607          <option>Hello!</option>
15608          <option id="greet" ng-selected="selected">Greetings!</option>
15609        </select>
15610      </file>
15611      <file name="protractor.js" type="protractor">
15612        it('should select Greetings!', function() {
15613          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15614          element(by.model('selected')).click();
15615          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15616        });
15617      </file>
15618    </example>
15619 *
15620 * @element OPTION
15621 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
15622 *     then special attribute "selected" will be set on the element
15623 */
15624
15625/**
15626 * @ngdoc directive
15627 * @name ngOpen
15628 * @restrict A
15629 * @priority 100
15630 *
15631 * @description
15632 * The HTML specification does not require browsers to preserve the values of boolean attributes
15633 * such as open. (Their presence means true and their absence means false.)
15634 * If we put an Angular interpolation expression into such an attribute then the
15635 * binding information would be lost when the browser removes the attribute.
15636 * The `ngOpen` directive solves this problem for the `open` attribute.
15637 * This complementary directive is not removed by the browser and so provides
15638 * a permanent reliable place to store the binding information.
15639 * @example
15640     <example>
15641       <file name="index.html">
15642         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15643         <details id="details" ng-open="open">
15644            <summary>Show/Hide me</summary>
15645         </details>
15646       </file>
15647       <file name="protractor.js" type="protractor">
15648         it('should toggle open', function() {
15649           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15650           element(by.model('open')).click();
15651           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15652         });
15653       </file>
15654     </example>
15655 *
15656 * @element DETAILS
15657 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
15658 *     then special attribute "open" will be set on the element
15659 */
15660
15661var ngAttributeAliasDirectives = {};
15662
15663
15664// boolean attrs are evaluated
15665forEach(BOOLEAN_ATTR, function(propName, attrName) {
15666  // binding to multiple is not supported
15667  if (propName == "multiple") return;
15668
15669  var normalized = directiveNormalize('ng-' + attrName);
15670  ngAttributeAliasDirectives[normalized] = function() {
15671    return {
15672      priority: 100,
15673      link: function(scope, element, attr) {
15674        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
15675          attr.$set(attrName, !!value);
15676        });
15677      }
15678    };
15679  };
15680});
15681
15682
15683// ng-src, ng-srcset, ng-href are interpolated
15684forEach(['src', 'srcset', 'href'], function(attrName) {
15685  var normalized = directiveNormalize('ng-' + attrName);
15686  ngAttributeAliasDirectives[normalized] = function() {
15687    return {
15688      priority: 99, // it needs to run after the attributes are interpolated
15689      link: function(scope, element, attr) {
15690        var propName = attrName,
15691            name = attrName;
15692
15693        if (attrName === 'href' &&
15694            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
15695          name = 'xlinkHref';
15696          attr.$attr[name] = 'xlink:href';
15697          propName = null;
15698        }
15699
15700        attr.$observe(normalized, function(value) {
15701          if (!value)
15702             return;
15703
15704          attr.$set(name, value);
15705
15706          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
15707          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
15708          // to set the property as well to achieve the desired effect.
15709          // we use attr[attrName] value since $set can sanitize the url.
15710          if (msie && propName) element.prop(propName, attr[name]);
15711        });
15712      }
15713    };
15714  };
15715});
15716
15717/* global -nullFormCtrl */
15718var nullFormCtrl = {
15719  $addControl: noop,
15720  $removeControl: noop,
15721  $setValidity: noop,
15722  $setDirty: noop,
15723  $setPristine: noop
15724};
15725
15726/**
15727 * @ngdoc type
15728 * @name form.FormController
15729 *
15730 * @property {boolean} $pristine True if user has not interacted with the form yet.
15731 * @property {boolean} $dirty True if user has already interacted with the form.
15732 * @property {boolean} $valid True if all of the containing forms and controls are valid.
15733 * @property {boolean}
15733 $invalid True if at least one containing control or form is invalid.
15734 *
15735 * @property {Object} $error Is an object hash, containing references to all invalid controls or
15736 *  forms, where:
15737 *
15738 *  - keys are validation tokens (error names),
15739 *  - values are arrays of controls or forms that are invalid for given error name.
15740 *
15741 *
15742 *  Built-in validation tokens:
15743 *
15744 *  - `email`
15745 *  - `max`
15746 *  - `maxlength`
15747 *  - `min`
15748 *  - `minlength`
15749 *  - `number`
15750 *  - `pattern`
15751 *  - `required`
15752 *  - `url`
15753 *
15754 * @description
15755 * `FormController` keeps track of all its controls and nested forms as well as state of them,
15756 * such as being valid/invalid or dirty/pristine.
15757 *
15758 * Each {@link ng.directive:form form} directive creates an instance
15759 * of `FormController`.
15760 *
15761 */
15762//asks for $scope to fool the BC controller module
15763FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
15764function FormController(element, attrs, $scope, $animate) {
15765  var form = this,
15766      parentForm = element.parent().controller('form') || nullFormCtrl,
15767      invalidCount = 0, // used to easily determine if we are valid
15768      errors = form.$error = {},
15769      controls = [];
15770
15771  // init state
15772  form.$name = attrs.name || attrs.ngForm;
15773  form.$dirty = false;
15774  form.$pristine = true;
15775  form.$valid = true;
15776  form.$invalid = false;
15777
15778  parentForm.$addControl(form);
15779
15780  // Setup initial state of the control
15781  element.addClass(PRISTINE_CLASS);
15782  toggleValidCss(true);
15783
15784  // convenience method for easy toggling of classes
15785  function toggleValidCss(isValid, validationErrorKey) {
15786    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
15787    $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
15788    $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
15789  }
15790
15791  /**
15792   * @ngdoc method
15793   * @name form.FormController#$addControl
15794   *
15795   * @description
15796   * Register a control with the form.
15797   *
15798   * Input elements using ngModelController do this automatically when they are linked.
15799   */
15800  form.$addControl = function(control) {
15801    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
15802    // and not added to the scope.  Now we throw an error.
15803    assertNotHasOwnProperty(control.$name, 'input');
15804    controls.push(control);
15805
15806    if (control.$name) {
15807      form[control.$name] = control;
15808    }
15809  };
15810
15811  /**
15812   * @ngdoc method
15813   * @name form.FormController#$removeControl
15814   *
15815   * @description
15816   * Deregister a control from the form.
15817   *
15818   * Input elements using ngModelController do this automatically when they are destroyed.
15819   */
15820  form.$removeControl = function(control) {
15821    if (control.$name && form[control.$name] === control) {
15822      delete form[control.$name];
15823    }
15824    forEach(errors, function(queue, validationToken) {
15825      form.$setValidity(validationToken, true, control);
15826    });
15827
15828    arrayRemove(controls, control);
15829  };
15830
15831  /**
15832   * @ngdoc method
15833   * @name form.FormController#$setValidity
15834   *
15835   * @description
15836   * Sets the validity of a form control.
15837   *
15838   * This method will also propagate to parent forms.
15839   */
15840  form.$setValidity = function(validationToken, isValid, control) {
15841    var queue = errors[validationToken];
15842
15843    if (isValid) {
15844      if (queue) {
15845        arrayRemove(queue, control);
15846        if (!queue.length) {
15847          invalidCount--;
15848          if (!invalidCount) {
15849            toggleValidCss(isValid);
15850            form.$valid = true;
15851            form.$invalid = false;
15852          }
15853          errors[validationToken] = false;
15854          toggleValidCss(true, validationToken);
15855          parentForm.$setValidity(validationToken, true, form);
15856        }
15857      }
15858
15859    } else {
15860      if (!invalidCount) {
15861        toggleValidCss(isValid);
15862      }
15863      if (queue) {
15864        if (includes(queue, control)) return;
15865      } else {
15866        errors[validationToken] = queue = [];
15867        invalidCount++;
15868        toggleValidCss(false, validationToken);
15869        parentForm.$setValidity(validationToken, false, form);
15870      }
15871      queue.push(control);
15872
15873      form.$valid = false;
15874      form.$invalid = true;
15875    }
15876  };
15877
15878  /**
15879   * @ngdoc method
15880   * @name form.FormController#$setDirty
15881   *
15882   * @description
15883   * Sets the form to a dirty state.
15884   *
15885   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
15886   * state (ng-dirty class). This method will also propagate to parent forms.
15887   */
15888  form.$setDirty = function() {
15889    $animate.removeClass(element, PRISTINE_CLASS);
15890    $animate.addClass(element, DIRTY_CLASS);
15891    form.$dirty = true;
15892    form.$pristine = false;
15893    parentForm.$setDirty();
15894  };
15895
15896  /**
15897   * @ngdoc method
15898   * @name form.FormController#$setPristine
15899   *
15900   * @description
15901   * Sets the form to its pristine state.
15902   *
15903   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
15904   * state (ng-pristine class). This method will also propagate to all the controls contained
15905   * in this form.
15906   *
15907   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
15908   * saving or resetting it.
15909   */
15910  form.$setPristine = function () {
15911    $animate.removeClass(element, DIRTY_CLASS);
15912    $animate.addClass(element, PRISTINE_CLASS);
15913    form.$dirty = false;
15914    form.$pristine = true;
15915    forEach(controls, function(control) {
15916      control.$setPristine();
15917    });
15918  };
15919}
15920
15921
15922/**
15923 * @ngdoc directive
15924 * @name ngForm
15925 * @restrict EAC
15926 *
15927 * @description
15928 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
15929 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
15930 * sub-group of controls needs to be determined.
15931 *
15932 * Note: the purpose of `ngForm` is to group controls,
15933 * but not to be a replacement for the `<form>` tag with all of its capabilities
15934 * (e.g. posting to the server, ...).
15935 *
15936 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
15937 *                       related scope, under this name.
15938 *
15939 */
15940
15941 /**
15942 * @ngdoc directive
15943 * @name form
15944 * @restrict E
15945 *
15946 * @description
15947 * Directive that instantiates
15948 * {@link form.FormController FormController}.
15949 *
15950 * If the `name` attribute is specified, the form controller is published onto the current scope under
15951 * this name.
15952 *
15953 * # Alias: {@link ng.directive:ngForm `ngForm`}
15954 *
15955 * In Angular forms can be nested. This means that the outer form is valid when all of the child
15956 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
15957 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
15958 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
15959 * using Angular validation directives in forms that are dynamically generated using the
15960 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
15961 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
15962 * `ngForm` directive and nest these in an outer `form` element.
15963 *
15964 *
15965 * # CSS classes
15966 *  - `ng-valid` is set if the form is valid.
15967 *  - `ng-invalid` is set if the form is invalid.
15968 *  - `ng-pristine` is set if the form is pristine.
15969 *  - `ng-dirty` is set if the form is dirty.
15970 *
15971 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
15972 *
15973 *
15974 * # Submitting a form and preventing the default action
15975 *
15976 * Since the role of forms in client-side Angular applications is different than in classical
15977 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
15978 * page reload that sends the data to the server. Instead some javascript logic should be triggered
15979 * to handle the form submission in an application-specific way.
15980 *
15981 * For this reason, Angular prevents the default action (form submission to the server) unless the
15982 * `<form>` element has an `action` attribute specified.
15983 *
15984 * You can use one of the following two ways to specify what javascript method should be called when
15985 * a form is submitted:
15986 *
15987 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
15988 * - {@link ng.directive:ngClick ngClick}
15988 directive on the first
15989  *  button or input field of type submit (input[type=submit])
15990 *
15991 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
15992 * or {@link ng.directive:ngClick ngClick} directives.
15993 * This is because of the following form submission rules in the HTML specification:
15994 *
15995 * - If a form has only one input field then hitting enter in this field triggers form submit
15996 * (`ngSubmit`)
15997 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
15998 * doesn't trigger submit
15999 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16000 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16001 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16002 *
16003 * @param {string=} name Name of the form. If specified, the form controller will be published into
16004 *                       related scope, under this name.
16005 *
16006 * ## Animation Hooks
16007 *
16008 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16009 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16010 * other validations that are performed within the form. Animations in ngForm are similar to how
16011 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16012 * as JS animations.
16013 *
16014 * The following example shows a simple way to utilize CSS transitions to style a form element
16015 * that has been rendered as invalid after it has been validated:
16016 *
16017 * <pre>
16018 * //be sure to include ngAnimate as a module to hook into more
16019 * //advanced animations
16020 * .my-form {
16021 *   transition:0.5s linear all;
16022 *   background: white;
16023 * }
16024 * .my-form.ng-invalid {
16025 *   background: red;
16026 *   color:white;
16027 * }
16028 * </pre>
16029 *
16030 * @example
16031    <example deps="angular-animate.js" animations="true" fixBase="true">
16032      <file name="index.html">
16033       <script>
16034         function Ctrl($scope) {
16035           $scope.userType = 'guest';
16036         }
16037       </script>
16038       <style>
16039        .my-form {
16040          -webkit-transition:all linear 0.5s;
16041          transition:all linear 0.5s;
16042          background: transparent;
16043        }
16044        .my-form.ng-invalid {
16045          background: red;
16046        }
16047       </style>
16048       <form name="myForm" ng-controller="Ctrl" class="my-form">
16049         userType: <input name="input" ng-model="userType" required>
16050         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16051         <tt>userType = {{userType}}</tt><br>
16052         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16053         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16054         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16055         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16056        </form>
16057      </file>
16058      <file name="protractor.js" type="protractor">
16059        it('should initialize to model', function() {
16060          var userType = element(by.binding('userType'));
16061          var valid = element(by.binding('myForm.input.$valid'));
16062
16063          expect(userType.getText()).toContain('guest');
16064          expect(valid.getText()).toContain('true');
16065        });
16066
16067        it('should be invalid if empty', function() {
16068          var userType = element(by.binding('userType'));
16069          var valid = element(by.binding('myForm.input.$valid'));
16070          var userInput = element(by.model('userType'));
16071
16072          userInput.clear();
16073          userInput.sendKeys('');
16074
16075          expect(userType.getText()).toEqual('userType =');
16076          expect(valid.getText()).toContain('false');
16077        });
16078      </file>
16079    </example>
16080 *
16081 */
16082var formDirectiveFactory = function(isNgForm) {
16083  return ['$timeout', function($timeout) {
16084    var formDirective = {
16085      name: 'form',
16086      restrict: isNgForm ? 'EAC' : 'E',
16087      controller: FormController,
16088      compile: function() {
16089        return {
16090          pre: function(scope, formElement, attr, controller) {
16091            if (!attr.action) {
16092              // we can't use jq events because if a form is destroyed during submission the default
16093              // action is not prevented. see #1238
16094              //
16095              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16096              // page reload if the form was destroyed by submission of the form via a click handler
16097              // on a button in the form. Looks like an IE9 specific bug.
16098              var preventDefaultListener = function(event) {
16099                event.preventDefault
16100                  ? event.preventDefault()
16101                  : event.returnValue = false; // IE
16102              };
16103
16104              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16105
16106              // unregister the preventDefault listener so that we don't not leak memory but in a
16107              // way that will achieve the prevention of the default action.
16108              formElement.on('$destroy', function() {
16109                $timeout(function() {
16110                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16111                }, 0, false);
16112              });
16113            }
16114
16115            var parentFormCtrl = formElement.parent().controller('form'),
16116                alias = attr.name || attr.ngForm;
16117
16118            if (alias) {
16119              setter(scope, alias, controller, alias);
16120            }
16121            if (parentFormCtrl) {
16122              formElement.on('$destroy', function() {
16123                parentFormCtrl.$removeControl(controller);
16124                if (alias) {
16125                  setter(scope, alias, undefined, alias);
16126                }
16127                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16128              });
16129            }
16130          }
16131        };
16132      }
16133    };
16134
16135    return formDirective;
16136  }];
16137};
16138
16139var formDirective = formDirectiveFactory();
16140var ngFormDirective = formDirectiveFactory(true);
16141
16142/* global
16143
16144    -VALID_CLASS,
16145    -INVALID_CLASS,
16146    -PRISTINE_CLASS,
16147    -DIRTY_CLASS
16148*/
16149
16150var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16151var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
16152var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16153
16154var inputType = {
16155
16156  /**
16157   * @ngdoc input
16158   * @name input[text]
16159   *
16160   * @description
16161   * Standard HTML text input with angular data binding.
16162   *
16163   * @param {string} ngModel Assignable angular expression to data-bind to.
16164   * @param {string=} name Property name of the form under which the control is published.
16165   * @param {string=} required Adds `required` validation error key if the value is not entered.
16166   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16167   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16168   *    `required` when you want to data-bind to the `required` attribute.
16169   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16170   *    minlength.
16171   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16172   *    maxlength.
16173   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16174   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16175   *    patterns defined as scope expressions.
16176   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16177   *    interaction with the input element.
16178   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16179   *
16180   * @example
16181      <example name="text-input-directive">
16182        <file name="index.html">
16183         <script>
16184           function Ctrl($scope) {
16185             $scope.text = 'guest';
16186             $scope.word = /^\s*\w*\s*$/;
16187           }
16188         </script>
16189         <form name="myForm" ng-controller="Ctrl">
16190           Single word: <input type="text" name="input" ng-model="text"
16191                               ng-pattern="word" required ng-trim="false">
16192           <span class="error" ng-show="myForm.input.$error.required">
16193             Required!</span>
16194           <span class="error" ng-show="myForm.input.$error.pattern">
16195             Single word only!</span>
16196
16197           <tt>text = {{text}}</tt><br/>
16198           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16199           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16200           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16201           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16202          </form>
16203        </file>
16204        <file name="protractor.js" type="protractor">
16205          var text = element(by.binding('text'));
16206          var valid = element(by.binding('myForm.input.$valid'));
16207          var input = element(by.model('text'));
16208
16209          it('should initialize to model', function() {
16210            expect(text.getText()).toContain('guest');
16211            expect(valid.getText()).toContain('true');
16212          });
16213
16214          it('should be invalid if empty', function() {
16215            input.clear();
16216            input.sendKeys('');
16217
16218            expect(text.getText()).toEqual('text =');
16219            expect(valid.getText()).toContain('false');
16220          });
16221
16222          it('should be invalid if multi word', function() {
16223            input.clear();
16224            input.sendKeys('hello world');
16225
16226            expect(valid.getText()).toContain('false');
16227          });
16228        </file>
16229      </example>
16230   */
16231  'text': textInputType,
16232
16233
16234  /**
16235   * @ngdoc input
16236   * @name input[number]
16237   *
16238   * @description
16239   * Text input with number validation and transformation. Sets the `number` validation
16240   * error if not a valid number.
16241   *
16242   * @param {string} ngModel Assignable angular expression to data-bind to.
16243   * @param {string=} name Property name of the form under which the control is published.
16244   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16245   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16246   * @param {string=} required Sets `required` validation error key if the value is not entered.
16247   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16248   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16249   *    `required` when you want to data-bind to the `required` attribute.
16250   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16251   *    minlength.
16252   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16253   *    maxlength.
16254   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16255   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16256   *    patterns defined as scope expressions.
16257   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16258   *    interaction with the input element.
16259   *
16260   * @example
16261      <example name="number-input-directive">
16262        <file name="index.html">
16263         <script>
16264           function Ctrl($scope) {
16265             $scope.value = 12;
16266           }
16267         </script>
16268         <form name="myForm" ng-controller="Ctrl">
16269           Number: <input type="number" name="input" ng-model="value"
16270                          min="0" max="99" required>
16271           <span class="error" ng-show="myForm.input.$error.required">
16272             Required!</span>
16273           <span class="error" ng-show="myForm.input.$error.number">
16274             Not valid number!</span>
16275           <tt>value = {{value}}</tt><br/>
16276           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16277           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16278           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16279           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16280          </form>
16281        </file>
16282        <file name="protractor.js" type="protractor">
16283          var value = element(by.binding('value'));
16284          var valid = element(by.binding('myForm.input.$valid'));
16285          var input = element(by.model('value'));
16286
16287          it('should initialize to model', function() {
16288            expect(value.getText()).toContain('12');
16289            expect(valid.getText()).toContain('true');
16290          });
16291
16292          it('should be invalid if empty', function() {
16293            input.clear();
16294            input.sendKeys('');
16295            expect(value.getText()).toEqual('value =');
16296            expect(valid.getText()).toContain('false');
16297          });
16298
16299          it('should be invalid if over max', function() {
16300            input.clear();
16301            input.sendKeys('123');
16302            expect(value.getText()).toEqual('value =');
16303            expect(valid.getText()).toContain('false');
16304          });
16305        </file>
16306      </example>
16307   */
16308  'number': numberInputType,
16309
16310
16311  /**
16312   * @ngdoc input
16313   * @name input[url]
16314   *
16315   * @description
16316   * Text input with URL validation. Sets the `url` validation error key if the content is not a
16317   * valid URL.
16318   *
16319   * @param {string} ngModel Assignable angular expression to data-bind to.
16320   * @param {string=} name Property name of the form under which the control is published.
16321   * @param {string=} required Sets `required` validation error key if the value is not entered.
16322   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16323   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16324   *    `required` when you want to data-bind to the `required` attribute.
16325   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16326   *    minlength.
16327   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16328   *    maxlength.
16329   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16330   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16331   *    patterns defined as scope expressions.
16332   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16333   *    interaction with the input element.
16334   *
16335   * @example
16336      <example name="url-input-directive">
16337        <file name="index.html">
16338         <script>
16339           function Ctrl($scope) {
16340             $scope.text = 'http://google.com';
16341           }
16342         </script>
16343         <form name="myForm" ng-controller="Ctrl">
16344           URL: <input type="url" name="input" ng-model="text" required>
16345           <span class="error" ng-show="myForm.input.$error.required">
16346             Required!</span>
16347           <span class="error" ng-show="myForm.input.$error.url">
16348             Not valid url!</span>
16349           <tt>text = {{text}}</tt><br/>
16350           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16351           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16352           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16353           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16354           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16355          </form>
16356        </file>
16357        <file name="protractor.js" type="protractor">
16358          var text = element(by.binding('text'));
16359          var valid = element(by.binding('myForm.input.$valid'));
16360          var input = element(by.model('text'));
16361
16362          it('should initialize to model', function() {
16363            expect(text.getText()).toContain('http://google.com');
16364            expect(valid.getText()).toContain('true');
16365          });
16366
16367          it('should be invalid if empty', function() {
16368            input.clear();
16369            input.sendKeys('');
16370
16371            expect(text.getText()).toEqual('text =');
16372            expect(valid.getText()).toContain('false');
16373          });
16374
16375          it('should be invalid if not url', function() {
16376            input.clear();
16377            input.sendKeys('box');
16378
16379            expect(valid.getText()).toContain('false');
16380          });
16381        </file>
16382      </example>
16383   */
16384  'url': urlInputType,
16385
16386
16387  /**
16388   * @ngdoc input
16389   * @name input[email]
16390   *
16391   * @description
16392   * Text input with email validation. Sets the `email` validation error key if not a valid email
16393   * address.
16394   *
16395   * @param {string} ngModel Assignable angular expression to data-bind to.
16396   * @param {string=} name Property name of the form under which the control is published.
16397   * @param {string=} required Sets `required` validation error key if the value is not entered.
16398   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16399   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16400   *    `required` when you want to data-bind to the `required` attribute.
16401   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16402   *    minlength.
16403   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16404   *    maxlength.
16405   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16406   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16407   *    patterns defined as scope expressions.
16408   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16409   *    interaction with the input element.
16410   *
16411   * @example
16412      <example name="email-input-directive">
16413        <file name="index.html">
16414         <script>
16415           function Ctrl($scope) {
16416             $scope.text = '[email protected]';
16417           }
16418         </script>
16419           <form name="myForm" ng-controller="Ctrl">
16420             Email: <input type="email" name="input" ng-model="text" required>
16421             <span class="error" ng-show="myForm.input.$error.required">
16422               Required!</span>
16423             <span class="error" ng-show="myForm.input.$error.email">
16424               Not valid email!</span>
16425             <tt>text = {{text}}</tt><br/>
16426             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16427             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16428             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16429             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16430             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16431           </form>
16432         </file>
16433        <file name="protractor.js" type="protractor">
16434          var text = element(by.binding('text'));
16435          var valid = element(by.binding('myForm.input.$valid'));
16436          var input = element(by.model('text'));
16437
16438          it('should initialize to model', function() {
16439            expect(text.getText()).toContain('[email protected]');
16440            expect(valid.getText()).toContain('true');
16441          });
16442
16443          it('should be invalid if empty', function() {
16444            input.clear();
16445            input.sendKeys('');
16446            expect(text.getText()).toEqual('text =');
16447            expect(valid.getText()).toContain('false');
16448          });
16449
16450          it('should be invalid if not email', function() {
16451            input.clear();
16452            input.sendKeys('xxx');
16453
16454            expect(valid.getText()).toContain('false');
16455          });
16456        </file>
16457      </example>
16458   */
16459  'email': emailInputType,
16460
16461
16462  /**
16463   * @ngdoc input
16464   * @name input[radio]
16465   *
16466   * @description
16467   * HTML radio button.
16468   *
16469   * @param {string} ngModel Assignable angular expression to data-bind to.
16470   * @param {string} value The value to which the expression should be set when selected.
16471   * @param {string=} name Property name of the form under which the control is published.
16472   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16473   *    interaction with the input element.
16474   * @param {string} ngValue Angular expression which sets the value to which the expression should
16475   *    be set when selected.
16476   *
16477   * @example
16478      <example name="radio-input-directive">
16479        <file name="index.html">
16480         <script>
16481           function Ctrl($scope) {
16482             $scope.color = 'blue';
16483             $scope.specialValue = {
16484               "id": "12345",
16485               "value": "green"
16486             };
16487           }
16488         </script>
16489         <form name="myForm" ng-controller="Ctrl">
16490           <input type="radio" ng-model="color" value="red">  Red <br/>
16491           <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16492           <input type="radio" ng-model="color" value="blue"> Blue <br/>
16493           <tt>color = {{color | json}}</tt><br/>
16494          </form>
16495          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16496        </file>
16497        <file name="protractor.js" type="protractor">
16498          it('should change state', function() {
16499            var color = element(by.binding('color'));
16500
16501            expect(color.getText()).toContain('blue');
16502
16503            element.all(by.model('color')).get(0).click();
16504
16505            expect(color.getText()).toContain('red');
16506          });
16507        </file>
16508      </example>
16509   */
16510  'radio': radioInputType,
16511
16512
16513  /**
16514   * @ngdoc input
16515   * @name input[checkbox]
16516   *
16517   * @description
16518   * HTML checkbox.
16519   *
16520   * @param {string} ngModel Assignable angular expression to data-bind to.
16521   * @param {string=} name Property name of the form under which the control is published.
16522   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16523   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16524   * @param {string=} ngChange Angular expression to be executed when input changes due to user
16525   *    interaction with the input element.
16526   *
16527   * @example
16528      <example name="checkbox-input-directive">
16529        <file name="index.html">
16530         <script>
16531           function Ctrl($scope) {
16532             $scope.value1 = true;
16533             $scope.value2 = 'YES'
16534           }
16535         </script>
16536         <form name="myForm" ng-controller="Ctrl">
16537           Value1: <input type="checkbox" ng-model="value1"> <br/>
16538           Value2: <input type="checkbox" ng-model="value2"
16539                          ng-true-value="YES" ng-false-value="NO"> <br/>
16540           <tt>value1 = {{value1}}</tt><br/>
16541           <tt>value2 = {{value2}}</tt><br/>
16542          </form>
16543        </file>
16544        <file name="protractor.js" type="protractor">
16545          it('should change state', function() {
16546            var value1 = element(by.binding('value1'));
16547            var value2 = element(by.binding('value2'));
16548
16549            expect(value1.getText()).toContain('true');
16550            expect(value2.getText()).toContain('YES');
16551
16552            element(by.model('value1')).click();
16553            element(by.model('value2')).click();
16554
16555            expect(value1.getText()).toContain('false');
16556            expect(value2.getText()).toContain('NO');
16557          });
16558        </file>
16559      </example>
16560   */
16561  'checkbox': checkboxInputType,
16562
16563  'hidden': noop,
16564  'button': noop,
16565  'submit': noop,
16566  'reset': noop,
16567  'file': noop
16568};
16569
16570// A helper function to call $setValidity and return the value / undefined,
16571// a pattern that is repeated a lot in the input validation logic.
16572function validate(ctrl, validatorName, validity, value){
16573  ctrl.$setValidity(validatorName, validity);
16574  return validity ? value : undefined;
16575}
16576
16577
16578function addNativeHtml5Validators(ctrl, validatorName, element) {
16579  var validity = element.prop('validity');
16580  if (isObject(validity)) {
16581    var validator = function(value) {
16582      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
16583      // perform the required validation)
16584      if (!ctrl.$error[validatorName] && (validity.badInput || validity.customError ||
16585          validity.typeMismatch) && !validity.valueMissing) {
16586        ctrl.$setValidity(validatorName, false);
16587        return;
16588      }
16589      return value;
16590    };
16591    ctrl.$parsers.push(validator);
16592  }
16593}
16594
16595function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16596  var validity = element.prop('validity');
16597  // In composition mode, users are still inputing intermediate text buffer,
16598  // hold the listener until composition is done.
16599  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16600  if (!$sniffer.android) {
16601    var composing = false;
16602
16603    element.on('compositionstart', function(data) {
16604      composing = true;
16605    });
16606
16607    element.on('compositionend', function() {
16608      composing = false;
16609      listener();
16610    });
16611  }
16612
16613  var listener = function() {
16614    if (composing) return;
16615    var value = element.val();
16616
16617    // By default we will trim the value
16618    // If the attribute ng-trim exists we will avoid trimming
16619    // e.g. <input ng-model="foo" ng-trim="false">
16620    if (toBoolean(attr.ngTrim || 'T')) {
16621      value = trim(value);
16622    }
16623
16624    if (ctrl.$viewValue !== value ||
16625        // If the value is still empty/falsy, and there is no `required` error, run validators
16626        // again. This enables HTML5 constraint validation errors to affect Angular validation
16627        // even when the first character entered causes an error.
16628        (validity && value === '' && !validity.valueMissing)) {
16629      if (scope.$$phase) {
16630        ctrl.$setViewValue(value);
16631      } else {
16632        scope.$apply(function() {
16633          ctrl.$setViewValue(value);
16634        });
16635      }
16636    }
16637  };
16638
16639  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
16640  // input event on backspace, delete or cut
16641  if ($sniffer.hasEvent('input')) {
16642    element.on('input', listener);
16643  } else {
16644    var timeout;
16645
16646    var deferListener = function() {
16647      if (!timeout) {
16648        timeout = $browser.defer(function() {
16649          listener();
16650          timeout = null;
16651        });
16652      }
16653    };
16654
16655    element.on('keydown', function(event) {
16656      var key = event.keyCode;
16657
16658      // ignore
16659      //    command            modifiers                   arrows
16660      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
16661
16662      deferListener();
16663    });
16664
16665    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
16666    if ($sniffer.hasEvent('paste')) {
16667      element.on('paste cut', deferListener);
16668    }
16669  }
16670
16671  // if user paste into input using mouse on older browser
16672  // or form autocomplete on newer browser, we need "change" event to catch it
16673  element.on('change', listener);
16674
16675  ctrl.$render = function() {
16676    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
16677  };
16678
16679  // pattern validator
16680  var pattern = attr.ngPattern,
16681      patternValidator,
16682      match;
16683
16684  if (pattern) {
16685    var validateRegex = function(regexp, value) {
16686      return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
16687    };
16688    match = pattern.match(/^\/(.*)\/([gim]*)$/);
16689    if (match) {
16690      pattern = new RegExp(match[1], match[2]);
16691      patternValidator = function(value) {
16692        return validateRegex(pattern, value);
16693      };
16694    } else {
16695      patternValidator = function(value) {
16696        var patternObj = scope.$eval(pattern);
16697
16698        if (!patternObj || !patternObj.test) {
16699          throw minErr('ngPattern')('noregexp',
16700            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
16701            patternObj, startingTag(element));
16702        }
16703        return validateRegex(patternObj, value);
16704      };
16705    }
16706
16707    ctrl.$formatters.push(patternValidator);
16708    ctrl.$parsers.push(patternValidator);
16709  }
16710
16711  // min length validator
16712  if (attr.ngMinlength) {
16713    var minlength = int(attr.ngMinlength);
16714    var minLengthValidator = function(value) {
16715      return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
16716    };
16717
16718    ctrl.$parsers.push(minLengthValidator);
16719    ctrl.$formatters.push(minLengthValidator);
16720  }
16721
16722  // max length validator
16723  if (attr.ngMaxlength) {
16724    var maxlength = int(attr.ngMaxlength);
16725    var maxLengthValidator = function(value) {
16726      return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
16727    };
16728
16729    ctrl.$parsers.push(maxLengthValidator);
16730    ctrl.$formatters.push(maxLengthValidator);
16731  }
16732}
16733
16734function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16735  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16736
16737  ctrl.$parsers.push(function(value) {
16738    var empty = ctrl.$isEmpty(value);
16739    if (empty || NUMBER_REGEXP.test(value)) {
16740      ctrl.$setValidity('number', true);
16741      return value === '' ? null : (empty ? value : parseFloat(value));
16742    } else {
16743      ctrl.$setValidity('number', false);
16744      return undefined;
16745    }
16746  });
16747
16748  addNativeHtml5Validators(ctrl, 'number', element);
16749
16750  ctrl.$formatters.push(function(value) {
16751    return ctrl.$isEmpty(value) ? '' : '' + value;
16752  });
16753
16754  if (attr.min) {
16755    var minValidator = function(value) {
16756      var min = parseFloat(attr.min);
16757      return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
16758    };
16759
16760    ctrl.$parsers.push(minValidator);
16761    ctrl.$formatters.push(minValidator);
16762  }
16763
16764  if (attr.max) {
16765    var maxValidator = function(value) {
16766      var max = parseFloat(attr.max);
16767      return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
16768    };
16769
16770    ctrl.$parsers.push(maxValidator);
16771    ctrl.$formatters.push(maxValidator);
16772  }
16773
16774  ctrl.$formatters.push(function(value) {
16775    return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
16776  });
16777}
16778
16779function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16780  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16781
16782  var urlValidator = function(value) {
16783    return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
16784  };
16785
16786  ctrl.$formatters.push(urlValidator);
16787  ctrl.$parsers.push(urlValidator);
16788}
16789
16790function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16791  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16792
16793  var emailValidator = function(value) {
16794    return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
16795  };
16796
16797  ctrl.$formatters.push(emailValidator);
16798  ctrl.$parsers.push(emailValidator);
16799}
16800
16801function radioInputType(scope, element, attr, ctrl) {
16802  // make the name unique, if not defined
16803  if (isUndefined(attr.name)) {
16804    element.attr('name', nextUid());
16805  }
16806
16807  element.on('click', function() {
16808    if (element[0].checked) {
16809      scope.$apply(function() {
16810        ctrl.$setViewValue(attr.value);
16811      });
16812    }
16813  });
16814
16815  ctrl.$render = function() {
16816    var value = attr.value;
16817    element[0].checked = (value == ctrl.$viewValue);
16818  };
16819
16820  attr.$observe('value', ctrl.$render);
16821}
16822
16823function checkboxInputType(scope, element, attr, ctrl) {
16824  var trueValue = attr.ngTrueValue,
16825      falseValue = attr.ngFalseValue;
16826
16827  if (!isString(trueValue)) trueValue = true;
16828  if (!isString(falseValue)) falseValue = false;
16829
16830  element.on('click', function() {
16831    scope.$apply(function() {
16832      ctrl.$setViewValue(element[0].checked);
16833    });
16834  });
16835
16836  ctrl.$render = function() {
16837    element[0].checked = ctrl.$viewValue;
16838  };
16839
16840  // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
16841  ctrl.$isEmpty = function(value) {
16842    return value !== trueValue;
16843  };
16844
16845  ctrl.$formatters.push(function(value) {
16846    return value === trueValue;
16847  });
16848
16849  ctrl.$parsers.push(function(value) {
16850    return value ? trueValue : falseValue;
16851  });
16852}
16853
16854
16855/**
16856 * @ngdoc directive
16857 * @name textarea
16858 * @restrict E
16859 *
16860 * @description
16861 * HTML textarea element control with angular data-binding. The data-binding and validation
16862 * properties of this element are exactly the same as those of the
16863 * {@link ng.directive:input input element}.
16864 *
16865 * @param {string} ngModel Assignable angular expression to data-bind to.
16866 * @param {string=} name Property name of the form under which the control is published.
16867 * @param {string=} required Sets `required` validation error key if the value is not entered.
16868 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16869 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16870 *    `required` when you want to data-bind to the `required` attribute.
16871 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16872 *    minlength.
16873 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16874 *    maxlength.
16875 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16876 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16877 *    patterns defined as scope expressions.
16878 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16879 *    interaction with the input element.
16880 */
16881
16882
16883/**
16884 * @ngdoc directive
16885 * @name input
16886 * @restrict E
16887 *
16888 * @description
16889 * HTML input element control with angular data-binding. Input control follows HTML5 input types
16890 * and polyfills the HTML5 validation behavior for older browsers.
16891 *
16892 * @param {string} ngModel Assignable angular expression to data-bind to.
16893 * @param {string=} name Property name of the form under which the control is published.
16894 * @param {string=} required Sets `required` validation error key if the value is not entered.
16895 * @param {boolean=} ngRequired Sets `required` attribute if set to true
16896 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16897 *    minlength.
16898 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16899 *    maxlength.
16900 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16901 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16902 *    patterns defined as scope expressions.
16903 * @param {string=} ngChange Angular expression to be executed when input changes due to user
16904 *    interaction with the input element.
16905 *
16906 * @example
16907    <example name="input-directive">
16908      <file name="index.html">
16909       <script>
16910         function Ctrl($scope) {
16911           $scope.user = {name: 'guest', last: 'visitor'};
16912         }
16913       </script>
16914       <div ng-controller="Ctrl">
16915         <form name="myForm">
16916           User name: <input type="text" name="userName" ng-model="user.name" required>
16917           <span class="error" ng-show="myForm.userName.$error.required">
16918             Required!</span><br>
16919           Last name: <input type="text" name="lastName" ng-model="user.last"
16920             ng-minlength="3" ng-maxlength="10">
16921           <span class="error" ng-show="myForm.lastName.$error.minlength">
16922             Too short!</span>
16923           <span class="error" ng-show="myForm.lastName.$error.maxlength">
16924             Too long!</span><br>
16925         </form>
16926         <hr>
16927         <tt>user = {{user}}</tt><br/>
16928         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
16929         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
16930         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
16931         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
16932         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16933         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16934         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
16935         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
16936       </div>
16937      </file>
16938      <file name="protractor.js" type="protractor">
16939        var user = element(by.binding('{{user}}'));
16940        var userNameValid = element(by.binding('myForm.userName.$valid'));
16941        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
16942        var lastNameError = element(by.binding('myForm.lastName.$error'));
16943        var formValid = element(by.binding('myForm.$valid'));
16944        var userNameInput = element(by.model('user.name'));
16945        var userLastInput = element(by.model('user.last'));
16946
16947        it('should initialize to model', function() {
16948          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
16949          expect(userNameValid.getText()).toContain('true');
16950          expect(formValid.getText()).toContain('true');
16951        });
16952
16953        it('should be invalid if empty when required', function() {
16954          userNameInput.clear();
16955          userNameInput.sendKeys('');
16956
16957          expect(user.getText()).toContain('{"last":"visitor"}');
16958          expect(userNameValid.getText()).toContain('false');
16959          expect(formValid.getText()).toContain('false');
16960        });
16961
16962        it('should be valid if empty when min length is set', function() {
16963          userLastInput.clear();
16964          userLastInput.sendKeys('');
16965
16966          expect(user.getText()).toContain('{"name":"guest","last":""}');
16967          expect(lastNameValid.getText()).toContain('true');
16968          expect(formValid.getText()).toContain('true');
16969        });
16970
16971        it('should be invalid if less than required min length', function() {
16972          userLastInput.clear();
16973          userLastInput.sendKeys('xx');
16974
16975          expect(user.getText()).toContain('{"name":"guest"}');
16976          expect(lastNameValid.getText()).toContain('false');
16977          expect(lastNameError.getText()).toContain('minlength');
16978          expect(formValid.getText()).toContain('false');
16979        });
16980
16981        it('should be invalid if longer than max length', function() {
16982          userLastInput.clear();
16983          userLastInput.sendKeys('some ridiculously long name');
16984
16985          expect(user.getText()).toContain('{"name":"guest"}');
16986          expect(lastNameValid.getText()).toContain('false');
16987          expect(lastNameError.getText()).toContain('maxlength');
16988          expect(formValid.getText()).toContain('false');
16989        });
16990      </file>
16991    </example>
16992 */
16993var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
16994  return {
16995    restrict: 'E',
16996    require: '?ngModel',
16997    link: function(scope, element, attr, ctrl) {
16998      if (ctrl) {
16999        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17000                                                            $browser);
17001      }
17002    }
17003  };
17004}];
17005
17006var VALID_CLASS = 'ng-valid',
17007    INVALID_CLASS = 'ng-invalid',
17008    PRISTINE_CLASS = 'ng-pristine',
17009    DIRTY_CLASS = 'ng-dirty';
17010
17011/**
17012 * @ngdoc type
17013 * @name ngModel.NgModelController
17014 *
17015 * @property {string} $viewValue Actual string value in the view.
17016 * @property {*} $modelValue The value in the model, that the control is bound to.
17017 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17018       the control reads value from the DOM.  Each function is called, in turn, passing the value
17019       through to the next. The last return value is used to populate the model.
17020       Used to sanitize / convert the value as well as validation. For validation,
17021       the parsers should update the validity state using
17022       {@link ngModel.NgModelController#$setValidity $setValidity()},
17023       and return `undefined` for invalid values.
17024
17025 *
17026 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17027       the model value changes. Each function is called, in turn, passing the value through to the
17028       next. Used to format / convert values for display in the control and validation.
17029 *      ```js
17030 *      function formatter(value) {
17031 *        if (value) {
17032 *          return value.toUpperCase();
17033 *        }
17034 *      }
17035 *      ngModel.$formatters.push(formatter);
17036 *      ```
17037 *
17038 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17039 *     view value has changed. It is called with no arguments, and its return value is ignored.
17040 *     This can be used in place of additional $watches against the model value.
17041 *
17042 * @property {Object} $error An object hash with all errors as keys.
17043 *
17044 * @property {boolean} $pristine True if user has not interacted with the control yet.
17045 * @property {boolean} $dirty True if user has already interacted with the control.
17046 * @property {boolean} $valid True if there is no error.
17047 * @property {boolean} $invalid True if at least one error on the control.
17048 *
17049 * @description
17050 *
17051 * `NgModelController` provides API for the `ng-model` directive. The controller contains
17052 * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17053 * purposefully does not contain any logic which deals with DOM rendering or listening to
17054 * DOM events. Such DOM related logic should be provided by other directives which make use of
17055 * `NgModelController` for data-binding.
17056 *
17057 * ## Custom Control Example
17058 * This example shows how to use `NgModelController` with a custom control to achieve
17059 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17060 * collaborate together to achieve the desired result.
17061 *
17062 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17063 * contents be edited in place by the user.  This will not work on older browsers.
17064 *
17065 * <example name="NgModelController" module="customControl">
17066    <file name="style.css">
17067      [contenteditable] {
17068        border: 1px solid black;
17069        background-color: white;
17070        min-height: 20px;
17071      }
17072
17073      .ng-invalid {
17074        border: 1px solid red;
17075      }
17076
17077    </file>
17078    <file name="script.js">
17079      angular.module('customControl', []).
17080        directive('contenteditable', function() {
17081          return {
17082            restrict: 'A', // only activate on element attribute
17083            require: '?ngModel', // get a hold of NgModelController
17084            link: function(scope, element, attrs, ngModel) {
17085              if(!ngModel) return; // do nothing if no ng-model
17086
17087              // Specify how UI should be updated
17088              ngModel.$render = function() {
17089                element.html(ngModel.$viewValue || '');
17090              };
17091
17092              // Listen for change events to enable binding
17093              element.on('blur keyup change', function() {
17094                scope.$apply(read);
17095              });
17096              read(); // initialize
17097
17098              // Write data to the model
17099              function read() {
17100                var html = element.html();
17101                // When we clear the content editable the browser leaves a <br> behind
17102                // If strip-br attribute is provided then we strip this out
17103                if( attrs.stripBr && html == '<br>' ) {
17104                  html = '';
17105                }
17106                ngModel.$setViewValue(html);
17107              }
17108            }
17109          };
17110        });
17111    </file>
17112    <file name="index.html">
17113      <form name="myForm">
17114       <div contenteditable
17115            name="myWidget" ng-model="userContent"
17116            strip-br="true"
17117            required>Change me!</div>
17118        <span ng-show="myForm.myWidget.$error.required">Required!</span>
17119       <hr>
17120       <textarea ng-model="userContent"></textarea>
17121      </form>
17122    </file>
17123    <file name="protractor.js" type="protractor">
17124    it('should data-bind and become invalid', function() {
17125      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17126        // SafariDriver can't handle contenteditable
17127        // and Firefox driver can't clear contenteditables very well
17128        return;
17129      }
17130      var contentEditable = element(by.css('[contenteditable]'));
17131      var content = 'Change me!';
17132
17133      expect(contentEditable.getText()).toEqual(content);
17134
17135      contentEditable.clear();
17136      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17137      expect(contentEditable.getText()).toEqual('');
17138      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17139    });
17140    </file>
17141 * </example>
17142 *
17143 *
17144 */
17145var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17146    function($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17147  this.$viewValue = Number.NaN;
17148  this.$modelValue = Number.NaN;
17149  this.$parsers = [];
17150  this.$formatters = [];
17151  this.$viewChangeListeners = [];
17152  this.$pristine = true;
17153  this.$dirty = false;
17154  this.$valid = true;
17155  this.$invalid = false;
17156  this.$name = $attr.name;
17157
17158  var ngModelGet = $parse($attr.ngModel),
17159      ngModelSet = ngModelGet.assign;
17160
17161  if (!ngModelSet) {
17162    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17163        $attr.ngModel, startingTag($element));
17164  }
17165
17166  /**
17167   * @ngdoc method
17168   * @name ngModel.NgModelController#$render
17169   *
17170   * @description
17171   * Called when the view needs to be updated. It is expected that the user of the ng-model
17172   * directive will implement this method.
17173   */
17174  this.$render = noop;
17175
17176  /**
17177   * @ngdoc method
17178   * @name ngModel.NgModelController#$isEmpty
17179   *
17180   * @description
17181   * This is called when we need to determine if the value of the input is empty.
17182   *
17183   * For instance, the required directive does this to work out if the input has data or not.
17184   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17185   *
17186   * You can override this for input directives whose concept of being empty is different to the
17187   * default. The `checkboxInputType` directive does this because in its case a value of `false`
17188   * implies empty.
17189   *
17190   * @param {*} value Reference to check.
17191   * @returns {boolean} True if `value` is empty.
17192   */
17193  this.$isEmpty = function(value) {
17194    return isUndefined(value) || value === '' || value === null || value !== value;
17195  };
17196
17197  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17198      invalidCount = 0, // used to easily determine if we are valid
17199      $error = this.$error = {};
17199 // keep invalid keys here
17200
17201
17202  // Setup initial state of the control
17203  $element.addClass(PRISTINE_CLASS);
17204  toggleValidCss(true);
17205
17206  // convenience method for easy toggling of classes
17207  function toggleValidCss(isValid, validationErrorKey) {
17208    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17209    $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17210    $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17211  }
17212
17213  /**
17214   * @ngdoc method
17215   * @name ngModel.NgModelController#$setValidity
17216   *
17217   * @description
17218   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17219   * does not notify form if given validator is already marked as invalid).
17220   *
17221   * This method should be called by validators - i.e. the parser or formatter functions.
17222   *
17223   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17224   *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
17225   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17226   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17227   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17228   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17229   */
17230  this.$setValidity = function(validationErrorKey, isValid) {
17231    // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17232    // jshint -W018
17233    if ($error[validationErrorKey] === !isValid) return;
17234    // jshint +W018
17235
17236    if (isValid) {
17237      if ($error[validationErrorKey]) invalidCount--;
17238      if (!invalidCount) {
17239        toggleValidCss(true);
17240        this.$valid = true;
17241        this.$invalid = false;
17242      }
17243    } else {
17244      toggleValidCss(false);
17245      this.$invalid = true;
17246      this.$valid = false;
17247      invalidCount++;
17248    }
17249
17250    $error[validationErrorKey] = !isValid;
17251    toggleValidCss(isValid, validationErrorKey);
17252
17253    parentForm.$setValidity(validationErrorKey, isValid, this);
17254  };
17255
17256  /**
17257   * @ngdoc method
17258   * @name ngModel.NgModelController#$setPristine
17259   *
17260   * @description
17261   * Sets the control to its pristine state.
17262   *
17263   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17264   * state (ng-pristine class).
17265   */
17266  this.$setPristine = function () {
17267    this.$dirty = false;
17268    this.$pristine = true;
17269    $animate.removeClass($element, DIRTY_CLASS);
17270    $animate.addClass($element, PRISTINE_CLASS);
17271  };
17272
17273  /**
17274   * @ngdoc method
17275   * @name ngModel.NgModelController#$setViewValue
17276   *
17277   * @description
17278   * Update the view value.
17279   *
17280   * This method should be called when the view value changes, typically from within a DOM event handler.
17281   * For example {@link ng.directive:input input} and
17282   * {@link ng.directive:select select} directives call it.
17283   *
17284   * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17285   * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17286   * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17287   *
17288   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17289   *
17290   * Note that calling this function does not trigger a `$digest`.
17291   *
17292   * @param {string} value Value from the view.
17293   */
17294  this.$setViewValue = function(value) {
17295    this.$viewValue = value;
17296
17297    // change to dirty
17298    if (this.$pristine) {
17299      this.$dirty = true;
17300      this.$pristine = false;
17301      $animate.removeClass($element, PRISTINE_CLASS);
17302      $animate.addClass($element, DIRTY_CLASS);
17303      parentForm.$setDirty();
17304    }
17305
17306    forEach(this.$parsers, function(fn) {
17307      value = fn(value);
17308    });
17309
17310    if (this.$modelValue !== value) {
17311      this.$modelValue = value;
17312      ngModelSet($scope, value);
17313      forEach(this.$viewChangeListeners, function(listener) {
17314        try {
17315          listener();
17316        } catch(e) {
17317          $exceptionHandler(e);
17318        }
17319      });
17320    }
17321  };
17322
17323  // model -> value
17324  var ctrl = this;
17325
17326  $scope.$watch(function ngModelWatch() {
17327    var value = ngModelGet($scope);
17328
17329    // if scope model value and ngModel value are out of sync
17330    if (ctrl.$modelValue !== value) {
17331
17332      var formatters = ctrl.$formatters,
17333          idx = formatters.length;
17334
17335      ctrl.$modelValue = value;
17336      while(idx--) {
17337        value = formatters[idx](value);
17338      }
17339
17340      if (ctrl.$viewValue !== value) {
17341        ctrl.$viewValue = value;
17342        ctrl.$render();
17343      }
17344    }
17345
17346    return value;
17347  });
17348}];
17349
17350
17351/**
17352 * @ngdoc directive
17353 * @name ngModel
17354 *
17355 * @element input
17356 *
17357 * @description
17358 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17359 * property on the scope using {@link ngModel.NgModelController NgModelController},
17360 * which is created and exposed by this directive.
17361 *
17362 * `ngModel` is responsible for:
17363 *
17364 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17365 *   require.
17366 * - Providing validation behavior (i.e. required, number, email, url).
17367 * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17368 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17369 * - Registering the control with its parent {@link ng.directive:form form}.
17370 *
17371 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17372 * current scope. If the property doesn't already exist on this scope, it will be created
17373 * implicitly and added to the scope.
17374 *
17375 * For best practices on using `ngModel`, see:
17376 *
17377 *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
17378 *
17379 * For basic examples, how to use `ngModel`, see:
17380 *
17381 *  - {@link ng.directive:input input}
17382 *    - {@link input[text] text}
17383 *    - {@link input[checkbox] checkbox}
17384 *    - {@link input[radio] radio}
17385 *    - {@link input[number] number}
17386 *    - {@link input[email] email}
17387 *    - {@link input[url] url}
17388 *  - {@link ng.directive:select select}
17389 *  - {@link ng.directive:textarea textarea}
17390 *
17391 * # CSS classes
17392 * The following CSS classes are added and removed on the associated input/select/textarea element
17393 * depending on the validity of the model.
17394 *
17395 *  - `ng-valid` is set if the model is valid.
17396 *  - `ng-invalid` is set if the model is invalid.
17397 *  - `ng-pristine` is set if the model is pristine.
17398 *  - `ng-dirty` is set if the model is dirty.
17399 *
17400 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
17401 *
17402 * ## Animation Hooks
17403 *
17404 * Animations within models are triggered when any of the associated CSS classes are added and removed
17405 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
17406 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
17407 * The animations that are triggered within ngModel are similar to how they work in ngClass and
17408 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
17409 *
17410 * The following example shows a simple way to utilize CSS transitions to style an input element
17411 * that has been rendered as invalid after it has been validated:
17412 *
17413 * <pre>
17414 * //be sure to include ngAnimate as a module to hook into more
17415 * //advanced animations
17416 * .my-input {
17417 *   transition:0.5s linear all;
17418 *   background: white;
17419 * }
17420 * .my-input.ng-invalid {
17421 *   background: red;
17422 *   color:white;
17423 * }
17424 * </pre>
17425 *
17426 * @example
17427 * <example deps="angular-animate.js" animations="true" fixBase="true">
17428     <file name="index.html">
17429       <script>
17430        function Ctrl($scope) {
17431          $scope.val = '1';
17432        }
17433       </script>
17434       <style>
17435         .my-input {
17436           -webkit-transition:all linear 0.5s;
17437           transition:all linear 0.5s;
17438           background: transparent;
17439         }
17440         .my-input.ng-invalid {
17441           color:white;
17442           background: red;
17443         }
17444       </style>
17445       Update input to see transitions when valid/invalid.
17446       Integer is a valid value.
17447       <form name="testForm" ng-controller="Ctrl">
17448         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
17449       </form>
17450     </file>
17451 * </example>
17452 */
17453var ngModelDirective = function() {
17454  return {
17455    require: ['ngModel', '^?form'],
17456    controller: NgModelController,
17457    link: function(scope, element, attr, ctrls) {
17458      // notify others, especially parent forms
17459
17460      var modelCtrl = ctrls[0],
17461          formCtrl = ctrls[1] || nullFormCtrl;
17462
17463      formCtrl.$addControl(modelCtrl);
17464
17465      scope.$on('$destroy', function() {
17466        formCtrl.$removeControl(modelCtrl);
17467      });
17468    }
17469  };
17470};
17471
17472
17473/**
17474 * @ngdoc directive
17475 * @name ngChange
17476 *
17477 * @description
17478 * Evaluate the given expression when the user changes the input.
17479 * The expression is evaluated immediately, unlike the JavaScript onchange event
17480 * which only triggers at the end of a change (usually, when the user leaves the
17481 * form element or presses the return key).
17482 * The expression is not evaluated when the value change is coming from the model.
17483 *
17484 * Note, this directive requires `ngModel` to be present.
17485 *
17486 * @element input
17487 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17488 * in input value.
17489 *
17490 * @example
17491 * <example name="ngChange-directive">
17492 *   <file name="index.html">
17493 *     <script>
17494 *       function Controller($scope) {
17495 *         $scope.counter = 0;
17496 *         $scope.change = function() {
17497 *           $scope.counter++;
17498 *         };
17499 *       }
17500 *     </script>
17501 *     <div ng-controller="Controller">
17502 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17503 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17504 *       <label for="ng-change-example2">Confirmed</label><br />
17505 *       <tt>debug = {{confirmed}}</tt><br/>
17506 *       <tt>counter = {{counter}}</tt><br/>
17507 *     </div>
17508 *   </file>
17509 *   <file name="protractor.js" type="protractor">
17510 *     var counter = element(by.binding('counter'));
17511 *     var debug = element(by.binding('confirmed'));
17512 *
17513 *     it('should evaluate the expression if changing from view', function() {
17514 *       expect(counter.getText()).toContain('0');
17515 *
17516 *       element(by.id('ng-change-example1')).click();
17517 *
17518 *       expect(counter.getText()).toContain('1');
17519 *       expect(debug.getText()).toContain('true');
17520 *     });
17521 *
17522 *     it('should not evaluate the expression if changing from model', function() {
17523 *       element(by.id('ng-change-example2')).click();
17524
17525 *       expect(counter.getText()).toContain('0');
17526 *       expect(debug.getText()).toContain('true');
17527 *     });
17528 *   </file>
17529 * </example>
17530 */
17531var ngChangeDirective = valueFn({
17532  require: 'ngModel',
17533  link: function(scope, element, attr, ctrl) {
17534    ctrl.$viewChangeListeners.push(function() {
17535      scope.$eval(attr.ngChange);
17536    });
17537  }
17538});
17539
17540
17541var requiredDirective = function() {
17542  return {
17543    require: '?ngModel',
17544    link: function(scope, elm, attr, ctrl) {
17545      if (!ctrl) return;
17546      attr.required = true; // force truthy in case we are on non input element
17547
17548      var validator = function(value) {
17549        if (attr.required && ctrl.$isEmpty(value)) {
17550          ctrl.$setValidity('required', false);
17551          return;
17552        } else {
17553          ctrl.$setValidity('required', true);
17554          return value;
17555        }
17556      };
17557
17558      ctrl.$formatters.push(validator);
17559      ctrl.$parsers.unshift(validator);
17560
17561      attr.$observe('required', function() {
17562        validator(ctrl.$viewValue);
17563      });
17564    }
17565  };
17566};
17567
17568
17569/**
17570 * @ngdoc directive
17571 * @name ngList
17572 *
17573 * @description
17574 * Text input that converts between a delimited string and an array of strings. The delimiter
17575 * can be a fixed string (by default a comma) or a regular expression.
17576 *
17577 * @element input
17578 * @param {string=} ngList optional delimiter that should be used to split the value. If
17579 *   specified in form `/something/` then the value will be converted into a regular expression.
17580 *
17581 * @example
17582    <example name="ngList-directive">
17583      <file name="index.html">
17584       <script>
17585         function Ctrl($scope) {
17586           $scope.names = ['igor', 'misko', 'vojta'];
17587         }
17588       </script>
17589       <form name="myForm" ng-controller="Ctrl">
17590         List: <input name="namesInput" ng-model="names" ng-list required>
17591         <span class="error" ng-show="myForm.namesInput.$error.required">
17592           Required!</span>
17593         <br>
17594         <tt>names = {{names}}</tt><br/>
17595         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
17596         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
17597         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
17598         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
17599        </form>
17600      </file>
17601      <file name="protractor.js" type="protractor">
17602        var listInput = element(by.model('names'));
17603        var names = element(by.binding('{{names}}'));
17604        var valid = element(by.binding('myForm.namesInput.$valid'));
17605        var error = element(by.css('span.error'));
17606
17607        it('should initialize to model', function() {
17608          expect(names.getText()).toContain('["igor","misko","vojta"]');
17609          expect(valid.getText()).toContain('true');
17610          expect(error.getCssValue('display')).toBe('none');
17611        });
17612
17613        it('should be invalid if empty', function() {
17614          listInput.clear();
17615          listInput.sendKeys('');
17616
17617          expect(names.getText()).toContain('');
17618          expect(valid.getText()).toContain('false');
17619          expect(error.getCssValue('display')).not.toBe('none');        });
17620      </file>
17621    </example>
17622 */
17623var ngListDirective = function() {
17624  return {
17625    require: 'ngModel',
17626    link: function(scope, element, attr, ctrl) {
17627      var match = /\/(.*)\//.exec(attr.ngList),
17628          separator = match && new RegExp(match[1]) || attr.ngList || ',';
17629
17630      var parse = function(viewValue) {
17631        // If the viewValue is invalid (say required but empty) it will be `undefined`
17632        if (isUndefined(viewValue)) return;
17633
17634        var list = [];
17635
17636        if (viewValue) {
17637          forEach(viewValue.split(separator), function(value) {
17638            if (value) list.push(trim(value));
17639          });
17640        }
17641
17642        return list;
17643      };
17644
17645      ctrl.$parsers.push(parse);
17646      ctrl.$formatters.push(function(value) {
17647        if (isArray(value)) {
17648          return value.join(', ');
17649        }
17650
17651        return undefined;
17652      });
17653
17654      // Override the standard $isEmpty because an empty array means the input is empty.
17655      ctrl.$isEmpty = function(value) {
17656        return !value || !value.length;
17657      };
17658    }
17659  };
17660};
17661
17662
17663var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
17664/**
17665 * @ngdoc directive
17666 * @name ngValue
17667 *
17668 * @description
17669 * Binds the given expression to the value of `input[select]` or `input[radio]`, so
17670 * that when the element is selected, the `ngModel` of that element is set to the
17671 * bound value.
17672 *
17673 * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
17674 * shown below.
17675 *
17676 * @element input
17677 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
17678 *   of the `input` element
17679 *
17680 * @example
17681    <example name="ngValue-directive">
17682      <file name="index.html">
17683       <script>
17684          function Ctrl($scope) {
17685            $scope.names = ['pizza', 'unicorns', 'robots'];
17686            $scope.my = { favorite: 'unicorns' };
17687          }
17688       </script>
17689        <form ng-controller="Ctrl">
17690          <h2>Which is your favorite?</h2>
17691            <label ng-repeat="name in names" for="{{name}}">
17692              {{name}}
17693              <input type="radio"
17694                     ng-model="my.favorite"
17695                     ng-value="name"
17696                     id="{{name}}"
17697                     name="favorite">
17698            </label>
17699          <div>You chose {{my.favorite}}</div>
17700        </form>
17701      </file>
17702      <file name="protractor.js" type="protractor">
17703        var favorite = element(by.binding('my.favorite'));
17704
17705        it('should initialize to model', function() {
17706          expect(favorite.getText()).toContain('unicorns');
17707        });
17708        it('should bind the values to the inputs', function() {
17709          element.all(by.model('my.favorite')).get(0).click();
17710          expect(favorite.getText()).toContain('pizza');
17711        });
17712      </file>
17713    </example>
17714 */
17715var ngValueDirective = function() {
17716  return {
17717    priority: 100,
17718    compile: function(tpl, tplAttr) {
17719      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
17720        return function ngValueConstantLink(scope, elm, attr) {
17721          attr.$set('value', scope.$eval(attr.ngValue));
17722        };
17723      } else {
17724        return function ngValueLink(scope, elm, attr) {
17725          scope.$watch(attr.ngValue, function valueWatchAction(value) {
17726            attr.$set('value', value);
17727          });
17728        };
17729      }
17730    }
17731  };
17732};
17733
17734/**
17735 * @ngdoc directive
17736 * @name ngBind
17737 * @restrict AC
17738 *
17739 * @description
17740 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
17741 * with the value of a given expression, and to update the text content when the value of that
17742 * expression changes.
17743 *
17744 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
17745 * `{{ expression }}` which is similar but less verbose.
17746 *
17747 * It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
17748 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
17749 * element attribute, it makes the bindings invisible to the user while the page is loading.
17750 *
17751 * An alternative solution to this problem would be using the
17752 * {@link ng.directive:ngCloak ngCloak} directive.
17753 *
17754 *
17755 * @element ANY
17756 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
17757 *
17758 * @example
17759 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
17760   <example>
17761     <file name="index.html">
17762       <script>
17763         function Ctrl($scope) {
17764           $scope.name = 'Whirled';
17765         }
17766       </script>
17767       <div ng-controller="Ctrl">
17768         Enter name: <input type="text" ng-model="name"><br>
17769         Hello <span ng-bind="name"></span>!
17770       </div>
17771     </file>
17772     <file name="protractor.js" type="protractor">
17773       it('should check ng-bind', function() {
17774         var nameInput = element(by.model('name'));
17775
17776         expect(element(by.binding('name')).getText()).toBe('Whirled');
17777         nameInput.clear();
17778         nameInput.sendKeys('world');
17779         expect(element(by.binding('name')).getText()).toBe('world');
17780       });
17781     </file>
17782   </example>
17783 */
17784var ngBindDirective = ngDirective(function(scope, element, attr) {
17785  element.addClass('ng-binding').data('$binding', attr.ngBind);
17786  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
17787    // We are purposefully using == here rather than === because we want to
17788    // catch when value is "null or undefined"
17789    // jshint -W041
17790    element.text(value == undefined ? '' : value);
17791  });
17792});
17793
17794
17795/**
17796 * @ngdoc directive
17797 * @name ngBindTemplate
17798 *
17799 * @description
17800 * The `ngBindTemplate` directive specifies that the element
17801 * text content should be replaced with the interpolation of the template
17802 * in the `ngBindTemplate` attribute.
17803 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
17804 * expressions. This directive is needed since some HTML elements
17805 * (such as TITLE and OPTION) cannot contain SPAN elements.
17806 *
17807 * @element ANY
17808 * @param {string} ngBindTemplate template of form
17809 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
17810 *
17811 * @example
17812 * Try it here: enter text in text box and watch the greeting change.
17813   <example>
17814     <file name="index.html">
17815       <script>
17816         function Ctrl($scope) {
17817           $scope.salutation = 'Hello';
17818           $scope.name = 'World';
17819         }
17820       </script>
17821       <div ng-controller="Ctrl">
17822        Salutation: <input type="text" ng-model="salutation"><br>
17823        Name: <input type="text" ng-model="name"><br>
17824        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
17825       </div>
17826     </file>
17827     <file name="protractor.js" type="protractor">
17828       it('should check ng-bind', function() {
17829         var salutationElem = element(by.binding('salutation'));
17830         var salutationInput = element(by.model('salutation'));
17831         var nameInput = element(by.model('name'));
17832
17833         expect(salutationElem.getText()).toBe('Hello World!');
17834
17835         salutationInput.clear();
17836         salutationInput.sendKeys('Greetings');
17837         nameInput.clear();
17838         nameInput.sendKeys('user');
17839
17840         expect(salutationElem.getText()).toBe('Greetings user!');
17841       });
17842     </file>
17843   </example>
17844 */
17845var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
17846  return function(scope, element, attr) {
17847    // TODO: move this to scenario runner
17848    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
17849    element.addClass('ng-binding').data('$binding', interpolateFn);
17850    attr.$observe('ngBindTemplate', function(value) {
17851      element.text(value);
17852    });
17853  };
17854}];
17855
17856
17857/**
17858 * @ngdoc directive
17859 * @name ngBindHtml
17860 *
17861 * @description
17862 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
17863 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
17864 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
17865 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
17866 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
17867 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
17868 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
17869 *
17870 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
17871 * will have an exception (instead of an exploit.)
17872 *
17873 * @element ANY
17874 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
17875 *
17876 * @example
17877   Try it here: enter text in text box and watch the greeting change.
17878
17879   <example module="ngBindHtmlExample" deps="angular-sanitize.js">
17880     <file name="index.html">
17881       <div ng-controller="ngBindHtmlCtrl">
17882        <p ng-bind-html="myHTML"></p>
17883       </div>
17884     </file>
17885
17886     <file name="script.js">
17887       angular.module('ngBindHtmlExample', ['ngSanitize'])
17888
17889       .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
17890         $scope.myHTML =
17891            'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
17892       }]);
17893     </file>
17894
17895     <file name="protractor.js" type="protractor">
17896       it('should check ng-bind-html', function() {
17897         expect(element(by.binding('myHTML')).getText()).toBe(
17898             'I am an HTMLstring with links! and other stuff');
17899       });
17900     </file>
17901   </example>
17902 */
17903var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
17904  return function(scope, element, attr) {
17905    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
17906
17907    var parsed = $parse(attr.ngBindHtml);
17908    function getStringValue() { return (parsed(scope) || '').toString(); }
17909
17910    scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
17911      element.html($sce.getTrustedHtml(parsed(scope)) || '');
17912    });
17913  };
17914}];
17915
17916function classDirective(name, selector) {
17917  name = 'ngClass' + name;
17918  return ['$animate', function($animate) {
17919    return {
17920      restrict: 'AC',
17921      link: function(scope, element, attr) {
17922        var oldVal;
17923
17924        scope.$watch(attr[name], ngClassWatchAction, true);
17925
17926        attr.$observe('class', function(value) {
17927          ngClassWatchAction(scope.$eval(attr[name]));
17928        });
17929
17930
17931        if (name !== 'ngClass') {
17932          scope.$watch('$index', function($index, old$index) {
17933            // jshint bitwise: false
17934            var mod = $index & 1;
17935            if (mod !== old$index & 1) {
17936              var classes = arrayClasses(scope.$eval(attr[name]));
17937              mod === selector ?
17938                addClasses(classes) :
17939                removeClasses(classes);
17940            }
17941          });
17942        }
17943
17944        function addClasses(classes) {
17945          var newClasses = digestClassCounts(classes, 1);
17946          attr.$addClass(newClasses);
17947        }
17948
17949        function removeClasses(classes) {
17950          var newClasses = digestClassCounts(classes, -1);
17951          attr.$removeClass(newClasses);
17952        }
17953
17954        function digestClassCounts (classes, count) {
17955          var classCounts = element.data('$classCounts') || {};
17956          var classesToUpdate = [];
17957          forEach(classes, function (className) {
17958            if (count > 0 || classCounts[className]) {
17959              classCounts[className] = (classCounts[className] || 0) + count;
17960              if (classCounts[className] === +(count > 0)) {
17961                classesToUpdate.push(className);
17962              }
17963            }
17964          });
17965          element.data('$classCounts', classCounts);
17966          return classesToUpdate.join(' ');
17967        }
17968
17969        function updateClasses (oldClasses, newClasses) {
17970          var toAdd = arrayDifference(newClasses, oldClasses);
17971          var toRemove = arrayDifference(oldClasses, newClasses);
17972          toRemove = digestClassCounts(toRemove, -1);
17973          toAdd = digestClassCounts(toAdd, 1);
17974
17975          if (toAdd.length === 0) {
17976            $animate.removeClass(element, toRemove);
17977          } else if (toRemove.length === 0) {
17978            $animate.addClass(element, toAdd);
17979          } else {
17980            $animate.setClass(element, toAdd, toRemove);
17981          }
17982        }
17983
17984        function ngClassWatchAction(newVal) {
17985          if (selector === true || scope.$index % 2 === selector) {
17986            var newClasses = arrayClasses(newVal || []);
17987            if (!oldVal) {
17988              addClasses(newClasses);
17989            } else if (!equals(newVal,oldVal)) {
17990              var oldClasses = arrayClasses(oldVal);
17991              updateClasses(oldClasses, newClasses);
17992            }
17993          }
17994          oldVal = copy(newVal);
17995        }
17996      }
17997    };
17998
17999    function arrayDifference(tokens1, tokens2) {
18000      var values = [];
18001
18002      outer:
18003      for(var i = 0; i < tokens1.length; i++) {
18004        var token = tokens1[i];
18005        for(var j = 0; j < tokens2.length; j++) {
18006          if(token == tokens2[j]) continue outer;
18007        }
18008        values.push(token);
18009      }
18010      return values;
18011    }
18012
18013    function arrayClasses (classVal) {
18014      if (isArray(classVal)) {
18015        return classVal;
18016      } else if (isString(classVal)) {
18017        return classVal.split(' ');
18018      } else if (isObject(classVal)) {
18019        var classes = [], i = 0;
18020        forEach(classVal, function(v, k) {
18021          if (v) {
18022            classes.push(k);
18023          }
18024        });
18025        return classes;
18026      }
18027      return classVal;
18028    }
18029  }];
18030}
18031
18032/**
18033 * @ngdoc directive
18034 * @name ngClass
18035 * @restrict AC
18036 *
18037 * @description
18038 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18039 * an expression that represents all classes to be added.
18040 *
18041 * The directive operates in three different ways, depending on which of three types the expression
18042 * evaluates to:
18043 *
18044 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18045 * names.
18046 *
18047 * 2. If the expression evaluates to an array, each element of the array should be a string that is
18048 * one or more space-delimited class names.
18049 *
18050 * 3. If the expression evaluates to an object, then for each key-value pair of the
18051 * object with a truthy value the corresponding key is used as a class name.
18052 *
18053 * The directive won't add duplicate classes if a particular class was already set.
18054 *
18055 * When the expression changes, the previously added classes are removed and only then the
18056 * new classes are added.
18057 *
18058 * @animations
18059 * add - happens just before the class is applied to the element
18060 * remove - happens just before the class is removed from the element
18061 *
18062 * @element ANY
18063 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18064 *   of the evaluation can be a string representing space delimited class
18065 *   names, an array, or a map of class names to boolean values. In the case of a map, the
18066 *   names of the properties whose values are truthy will be added as css classes to the
18067 *   element.
18068 *
18069 * @example Example that demonstrates basic bindings via ngClass directive.
18070   <example>
18071     <file name="index.html">
18072       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18073       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18074       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18075       <input type="checkbox" ng-model="error"> error (apply "red" class)
18076       <hr>
18077       <p ng-class="style">Using String Syntax</p>
18078       <input type="text" ng-model="style" placeholder="Type: bold strike red">
18079       <hr>
18080       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18081       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18082       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18083       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18084     </file>
18085     <file name="style.css">
18086       .strike {
18087         text-decoration: line-through;
18088       }
18089       .bold {
18090           font-weight: bold;
18091       }
18092       .red {
18093           color: red;
18094       }
18095     </file>
18096     <file name="protractor.js" type="protractor">
18097       var ps = element.all(by.css('p'));
18098
18099       it('should let you toggle the class', function() {
18100
18101         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18102         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18103
18104         element(by.model('important')).click();
18105         expect(ps.first().getAttribute('class')).toMatch(/bold/);
18106
18107         element(by.model('error')).click();
18108         expect(ps.first().getAttribute('class')).toMatch(/red/);
18109       });
18110
18111       it('should let you toggle string example', function() {
18112         expect(ps.get(1).getAttribute('class')).toBe('');
18113         element(by.model('style')).clear();
18114         element(by.model('style')).sendKeys('red');
18115         expect(ps.get(1).getAttribute('class')).toBe('red');
18116       });
18117
18118       it('array example should have 3 classes', function() {
18119         expect(ps.last().getAttribute('class')).toBe('');
18120         element(by.model('style1')).sendKeys('bold');
18121         element(by.model('style2')).sendKeys('strike');
18122         element(by.model('style3')).sendKeys('red');
18123         expect(ps.last().getAttribute('class')).toBe('bold strike red');
18124       });
18125     </file>
18126   </example>
18127
18128   ## Animations
18129
18130   The example below demonstrates how to perform animations using ngClass.
18131
18132   <example module="ngAnimate" deps="angular-animate.js" animations="true">
18133     <file name="index.html">
18134      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18135      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18136      <br>
18137      <span class="base-class" ng-class="myVar">Sample Text</span>
18138     </file>
18139     <file name="style.css">
18140       .base-class {
18141         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18142         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18143       }
18144
18145       .base-class.my-class {
18146         color: red;
18147         font-size:3em;
18148       }
18149     </file>
18150     <file name="protractor.js" type="protractor">
18151       it('should check ng-class', function() {
18152         expect(element(by.css('.base-class')).getAttribute('class')).not.
18153           toMatch(/my-class/);
18154
18155         element(by.id('setbtn')).click();
18156
18157         expect(element(by.css('.base-class')).getAttribute('class')).
18158           toMatch(/my-class/);
18159
18160         element(by.id('clearbtn')).click();
18161
18162         expect(element(by.css('.base-class')).getAttribute('class')).not.
18163           toMatch(/my-class/);
18164       });
18165     </file>
18166   </example>
18167
18168
18169   ## ngClass and pre-existing CSS3 Transitions/Animations
18170   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18171   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18172   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18173   to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18174   {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18175 */
18176var ngClassDirective = classDirective('', true);
18177
18178/**
18179 * @ngdoc directive
18180 * @name ngClassOdd
18181 * @restrict AC
18182 *
18183 * @description
18184 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18185 * {@link ng.directive:ngClass ngClass}, except they work in
18186 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18187 *
18188 * This directive can be applied only within the scope of an
18189 * {@link ng.directive:ngRepeat ngRepeat}.
18190 *
18191 * @element ANY
18192 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18193 *   of the evaluation can be a string representing space delimited class names or an array.
18194 *
18195 * @example
18196   <example>
18197     <file name="index.html">
18198        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18199          <li ng-repeat="name in names">
18200           <span ng-class-odd="'odd'" ng-class-even="'even'">
18201             {{name}}
18202           </span>
18203          </li>
18204        </ol>
18205     </file>
18206     <file name="style.css">
18207       .odd {
18208         color: red;
18209       }
18210       .even {
18211         color: blue;
18212       }
18213     </file>
18214     <file name="protractor.js" type="protractor">
18215       it('should check ng-class-odd and ng-class-even', function() {
18216         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18217           toMatch(/odd/);
18218         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18219           toMatch(/even/);
18220       });
18221     </file>
18222   </example>
18223 */
18224var ngClassOddDirective = classDirective('Odd', 0);
18225
18226/**
18227 * @ngdoc directive
18228 * @name ngClassEven
18229 * @restrict AC
18230 *
18231 * @description
18232 * The `ngClassOdd` and `ngClassEven` directives work exactly as
18233 * {@link ng.directive:ngClass ngClass}, except they work in
18234 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18235 *
18236 * This directive can be applied only within the scope of an
18237 * {@link ng.directive:ngRepeat ngRepeat}.
18238 *
18239 * @element ANY
18240 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18241 *   result of the evaluation can be a string representing space delimited class names or an array.
18242 *
18243 * @example
18244   <example>
18245     <file name="index.html">
18246        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18247          <li ng-repeat="name in names">
18248           <span ng-class-odd="'odd'" ng-class-even="'even'">
18249             {{name}} &nbsp; &nbsp; &nbsp;
18250           </span>
18251          </li>
18252        </ol>
18253     </file>
18254     <file name="style.css">
18255       .odd {
18256         color: red;
18257       }
18258       .even {
18259         color: blue;
18260       }
18261     </file>
18262     <file name="protractor.js" type="protractor">
18263       it('should check ng-class-odd and ng-class-even', function() {
18264         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18265           toMatch(/odd/);
18266         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18267           toMatch(/even/);
18268       });
18269     </file>
18270   </example>
18271 */
18272var ngClassEvenDirective = classDirective('Even', 1);
18273
18274/**
18275 * @ngdoc directive
18276 * @name ngCloak
18277 * @restrict AC
18278 *
18279 * @description
18280 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18281 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18282 * directive to avoid the undesirable flicker effect caused by the html template display.
18283 *
18284 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18285 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18286 * of the browser view.
18287 *
18288 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18289 * `angular.min.js`.
18290 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18291 *
18292 * ```css
18293 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18294 *   display: none !important;
18295 * }
18296 * ```
18297 *
18298 * When this css rule is loaded by the browser, all html elements (including their children) that
18299 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18300 * during the compilation of the template it deletes the `ngCloak` element attribute, making
18301 * the compiled element visible.
18302 *
18303 * For the best result, the `angular.js` script must be loaded in the head section of the html
18304 * document; alternatively, the css rule above must be included in the external stylesheet of the
18305 * application.
18306 *
18307 * Legacy browsers, like IE7, do not provide attribute selector support (a
18307dded in CSS 2.1) so they
18308 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18309 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18310 *
18311 * @element ANY
18312 *
18313 * @example
18314   <example>
18315     <file name="index.html">
18316        <div id="template1" ng-cloak>{{ 'hello' }}</div>
18317        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18318     </file>
18319     <file name="protractor.js" type="protractor">
18320       it('should remove the template directive and css class', function() {
18321         expect($('#template1').getAttribute('ng-cloak')).
18322           toBeNull();
18323         expect($('#template2').getAttribute('ng-cloak')).
18324           toBeNull();
18325       });
18326     </file>
18327   </example>
18328 *
18329 */
18330var ngCloakDirective = ngDirective({
18331  compile: function(element, attr) {
18332    attr.$set('ngCloak', undefined);
18333    element.removeClass('ng-cloak');
18334  }
18335});
18336
18337/**
18338 * @ngdoc directive
18339 * @name ngController
18340 *
18341 * @description
18342 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18343 * supports the principles behind the Model-View-Controller design pattern.
18344 *
18345 * MVC components in angular:
18346 *
18347 * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
18348 *   are accessed through bindings.
18349 * * View — The template (HTML with data bindings) that is rendered into the View.
18350 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18351 *   logic behind the application to decorate the scope with functions and values
18352 *
18353 * Note that you can also attach controllers to the DOM by declaring it in a route definition
18354 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18355 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18356 * and executed twice.
18357 *
18358 * @element ANY
18359 * @scope
18360 * @param {expression} ngController Name of a globally accessible constructor function or an
18361 *     {@link guide/expression expression} that on the current scope evaluates to a
18362 *     constructor function. The controller instance can be published into a scope property
18363 *     by specifying `as propertyName`.
18364 *
18365 * @example
18366 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18367 * greeting are methods declared on the controller (see source tab). These methods can
18368 * easily be called from the angular markup. Notice that the scope becomes the `this` for the
18369 * controller's instance. This allows for easy access to the view data from the controller. Also
18370 * notice that any changes to the data are automatically reflected in the View without the need
18371 * for a manual update. The example is shown in two different declaration styles you may use
18372 * according to preference.
18373   <example>
18374     <file name="index.html">
18375      <script>
18376        function SettingsController1() {
18377          this.name = "John Smith";
18378          this.contacts = [
18379            {type: 'phone', value: '408 555 1212'},
18380            {type: 'email', value: '[email protected]'} ];
18381          };
18382
18383        SettingsController1.prototype.greet = function() {
18384          alert(this.name);
18385        };
18386
18387        SettingsController1.prototype.addContact = function() {
18388          this.contacts.push({type: 'email', value: '[email protected]'});
18389        };
18390
18391        SettingsController1.prototype.removeContact = function(contactToRemove) {
18392         var index = this.contacts.indexOf(contactToRemove);
18393          this.contacts.splice(index, 1);
18394        };
18395
18396        SettingsController1.prototype.clearContact = function(contact) {
18397          contact.type = 'phone';
18398          contact.value = '';
18399        };
18400      </script>
18401      <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18402        Name: <input type="text" ng-model="settings.name"/>
18403        [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18404        Contact:
18405        <ul>
18406          <li ng-repeat="contact in settings.contacts">
18407            <select ng-model="contact.type">
18408               <option>phone</option>
18409               <option>email</option>
18410            </select>
18411            <input type="text" ng-model="contact.value"/>
18412            [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18413            | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18414          </li>
18415          <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18416       </ul>
18417      </div>
18418     </file>
18419     <file name="protractor.js" type="protractor">
18420       it('should check controller as', function() {
18421         var container = element(by.id('ctrl-as-exmpl'));
18422
18423         expect(container.findElement(by.model('settings.name'))
18424             .getAttribute('value')).toBe('John Smith');
18425
18426         var firstRepeat =
18427             container.findElement(by.repeater('contact in settings.contacts').row(0));
18428         var secondRepeat =
18429             container.findElement(by.repeater('contact in settings.contacts').row(1));
18430
18431         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18432             .toBe('408 555 1212');
18433         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18434             .toBe('[email protected]');
18435
18436         firstRepeat.findElement(by.linkText('clear')).click();
18437
18438         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18439             .toBe('');
18440
18441         container.findElement(by.linkText('add')).click();
18442
18443         expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
18444             .findElement(by.model('contact.value'))
18445             .getAttribute('value'))
18446             .toBe('[email protected]');
18447       });
18448     </file>
18449   </example>
18450    <example>
18451     <file name="index.html">
18452      <script>
18453        function SettingsController2($scope) {
18454          $scope.name = "John Smith";
18455          $scope.contacts = [
18456            {type:'phone', value:'408 555 1212'},
18457            {type:'email', value:'[email protected]'} ];
18458
18459          $scope.greet = function() {
18460           alert(this.name);
18461          };
18462
18463          $scope.addContact = function() {
18464           this.contacts.push({type:'email', value:'[email protected]'});
18465          };
18466
18467          $scope.removeContact = function(contactToRemove) {
18468           var index = this.contacts.indexOf(contactToRemove);
18469           this.contacts.splice(index, 1);
18470          };
18471
18472          $scope.clearContact = function(contact) {
18473           contact.type = 'phone';
18474           contact.value = '';
18475          };
18476        }
18477      </script>
18478      <div id="ctrl-exmpl" ng-controller="SettingsController2">
18479        Name: <input type="text" ng-model="name"/>
18480        [ <a href="" ng-click="greet()">greet</a> ]<br/>
18481        Contact:
18482        <ul>
18483          <li ng-repeat="contact in contacts">
18484            <select ng-model="contact.type">
18485               <option>phone</option>
18486               <option>email</option>
18487            </select>
18488            <input type="text" ng-model="contact.value"/>
18489            [ <a href="" ng-click="clearContact(contact)">clear</a>
18490            | <a href="" ng-click="removeContact(contact)">X</a> ]
18491          </li>
18492          <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18493       </ul>
18494      </div>
18495     </file>
18496     <file name="protractor.js" type="protractor">
18497       it('should check controller', function() {
18498         var container = element(by.id('ctrl-exmpl'));
18499
18500         expect(container.findElement(by.model('name'))
18501             .getAttribute('value')).toBe('John Smith');
18502
18503         var firstRepeat =
18504             container.findElement(by.repeater('contact in contacts').row(0));
18505         var secondRepeat =
18506             container.findElement(by.repeater('contact in contacts').row(1));
18507
18508         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18509             .toBe('408 555 1212');
18510         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18511             .toBe('[email protected]');
18512
18513         firstRepeat.findElement(by.linkText('clear')).click();
18514
18515         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18516             .toBe('');
18517
18518         container.findElement(by.linkText('add')).click();
18519
18520         expect(container.findElement(by.repeater('contact in contacts').row(2))
18521             .findElement(by.model('contact.value'))
18522             .getAttribute('value'))
18523             .toBe('[email protected]');
18524       });
18525     </file>
18526   </example>
18527
18528 */
18529var ngControllerDirective = [function() {
18530  return {
18531    scope: true,
18532    controller: '@',
18533    priority: 500
18534  };
18535}];
18536
18537/**
18538 * @ngdoc directive
18539 * @name ngCsp
18540 *
18541 * @element html
18542 * @description
18543 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
18544 *
18545 * This is necessary when developing things like Google Chrome Extensions.
18546 *
18547 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
18548 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
18549 * any of these restrictions.
18550 *
18551 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
18552 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
18553 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
18554 * be raised.
18555 *
18556 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
18557 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
18558 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
18559 *
18560 * In order to use this feature put the `ngCsp` directive on the root element of the application.
18561 *
18562 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
18563 *
18564 * @example
18565 * This example shows how to apply the `ngCsp` directive to the `html` tag.
18566   ```html
18567     <!doctype html>
18568     <html ng-app ng-csp>
18569     ...
18570     ...
18571     </html>
18572   ```
18573 */
18574
18575// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
18576// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
18577// anywhere in the current doc
18578
18579/**
18580 * @ngdoc directive
18581 * @name ngClick
18582 *
18583 * @description
18584 * The ngClick directive allows you to specify custom behavior when
18585 * an element is clicked.
18586 *
18587 * @element ANY
18588 * @priority 0
18589 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
18590 * click. ({@link guide/expression#-event- Event object is available as `$event`})
18591 *
18592 * @example
18593   <example>
18594     <file name="index.html">
18595      <button ng-click="count = count + 1" ng-init="count=0">
18596        Increment
18597      </button>
18598      count: {{count}}
18599     </file>
18600     <file name="protractor.js" type="protractor">
18601       it('should check ng-click', function() {
18602         expect(element(by.binding('count')).getText()).toMatch('0');
18603         element(by.css('button')).click();
18604         expect(element(by.binding('count')).getText()).toMatch('1');
18605       });
18606     </file>
18607   </example>
18608 */
18609/*
18610 * A directive that allows creation of custom onclick handlers that are defined as angular
18611 * expressions and are compiled and executed within the current scope.
18612 *
18613 * Events that are handled via these handler are always configured not to propagate further.
18614 */
18615var ngEventDirectives = {};
18616forEach(
18617  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
18618  function(name) {
18619    var directiveName = directiveNormalize('ng-' + name);
18620    ngEventDirectives[directiveName] = ['$parse', function($parse) {
18621      return {
18622        compile: function($element, attr) {
18623          var fn = $parse(attr[directiveName]);
18624          return function(scope, element, attr) {
18625            element.on(lowercase(name), function(event) {
18626              scope.$apply(function() {
18627                fn(scope, {$event:event});
18628              });
18629            });
18630          };
18631        }
18632      };
18633    }];
18634  }
18635);
18636
18637/**
18638 * @ngdoc directive
18639 * @name ngDblclick
18640 *
18641 * @description
18642 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
18643 *
18644 * @element ANY
18645 * @priority 0
18646 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
18647 * a dblclick. (The Event object is available as `$event`)
18648 *
18649 * @example
18650   <example>
18651     <file name="index.html">
18652      <button ng-dblclick="count = count + 1" ng-init="count=0">
18653        Increment (on double click)
18654      </button>
18655      count: {{count}}
18656     </file>
18657   </example>
18658 */
18659
18660
18661/**
18662 * @ngdoc directive
18663 * @name ngMousedown
18664 *
18665 * @description
18666 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
18667 *
18668 * @element ANY
18669 * @priority 0
18670 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
18671 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
18672 *
18673 * @example
18674   <example>
18675     <file name="index.html">
18676      <button ng-mousedown="count = count + 1" ng-init="count=0">
18677        Increment (on mouse down)
18678      </button>
18679      count: {{count}}
18680     </file>
18681   </example>
18682 */
18683
18684
18685/**
18686 * @ngdoc directive
18687 * @name ngMouseup
18688 *
18689 * @description
18690 * Specify custom behavior on mouseup event.
18691 *
18692 * @element ANY
18693 * @priority 0
18694 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
18695 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
18696 *
18697 * @example
18698   <example>
18699     <file name="index.html">
18700      <button ng-mouseup="count = count + 1" ng-init="count=0">
18701        Increment (on mouse up)
18702      </button>
18703      count: {{count}}
18704     </file>
18705   </example>
18706 */
18707
18708/**
18709 * @ngdoc directive
18710 * @name ngMouseover
18711 *
18712 * @description
18713 * Specify custom behavior on mouseover event.
18714 *
18715 * @element ANY
18716 * @priority 0
18717 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
18718 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
18719 *
18720 * @example
18721   <example>
18722     <file name="index.html">
18723      <button ng-mouseover="count = count + 1" ng-init="count=0">
18724        Increment (when mouse is over)
18725      </button>
18726      count: {{count}}
18727     </file>
18728   </example>
18729 */
18730
18731
18732/**
18733 * @ngdoc directive
18734 * @name ngMouseenter
18735 *
18736 * @description
18737 * Specify custom behavior on mouseenter event.
18738 *
18739 * @element ANY
18740 * @priority 0
18741 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
18742 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
18743 *
18744 * @example
18745   <example>
18746     <file name="index.html">
18747      <button ng-mouseenter="count = count + 1" ng-init="count=0">
18748        Increment (when mouse enters)
18749      </button>
18750      count: {{count}}
18751     </file>
18752   </example>
18753 */
18754
18755
18756/**
18757 * @ngdoc directive
18758 * @name ngMouseleave
18759 *
18760 * @description
18761 * Specify custom behavior on mouseleave event.
18762 *
18763 * @element ANY
18764 * @priority 0
18765 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
18766 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
18767 *
18768 * @example
18769   <example>
18770     <file name="index.html">
18771      <button ng-mouseleave="count = count + 1" ng-init="count=0">
18772        Increment (when mouse leaves)
18773      </button>
18774      count: {{count}}
18775     </file>
18776   </example>
18777 */
18778
18779
18780/**
18781 * @ngdoc directive
18782 * @name ngMousemove
18783 *
18784 * @description
18785 * Specify custom behavior on mousemove event.
18786 *
18787 * @element ANY
18788 * @priority 0
18789 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
18790 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
18791 *
18792 * @example
18793   <example>
18794     <file name="index.html">
18795      <button ng-mousemove="count = count + 1" ng-init="count=0">
18796        Increment (when mouse moves)
18797      </button>
18798      count: {{count}}
18799     </file>
18800   </example>
18801 */
18802
18803
18804/**
18805 * @ngdoc directive
18806 * @name ngKeydown
18807 *
18808 * @description
18809 * Specify custom behavior on keydown event.
18810 *
18811 * @element ANY
18812 * @priority 0
18813 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
18814 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18815 *
18816 * @example
18817   <example>
18818     <file name="index.html">
18819      <input ng-keydown="count = count + 1" ng-init="count=0">
18820      key down count: {{count}}
18821     </file>
18822   </example>
18823 */
18824
18825
18826/**
18827 * @ngdoc directive
18828 * @name ngKeyup
18829 *
18830 * @description
18831 * Specify custom behavior on keyup event.
18832 *
18833 * @element ANY
18834 * @priority 0
18835 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
18836 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18837 *
18838 * @example
18839   <example>
18840     <file name="index.html">
18841      <input ng-keyup="count = count + 1" ng-init="count=0">
18842      key up count: {{count}}
18843     </file>
18844   </example>
18845 */
18846
18847
18848/**
18849 * @ngdoc directive
18850 * @name ngKeypress
18851 *
18852 * @description
18853 * Specify custom behavior on keypress event.
18854 *
18855 * @element ANY
18856 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
18857 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
18858 * and can be interrogated for keyCode, altKey, etc.)
18859 *
18860 * @example
18861   <example>
18862     <file name="index.html">
18863      <input ng-keypress="count = count + 1" ng-init="count=0">
18864      key press count: {{count}}
18865     </file>
18866   </example>
18867 */
18868
18869
18870/**
18871 * @ngdoc directive
18872 * @name ngSubmit
18873 *
18874 * @description
18875 * Enables binding angular expressions to onsubmit events.
18876 *
18877 * Additionally it prevents the default action (which for form means 
18877sending the request to the
18878 * server and reloading the current page), but only if the form does not contain `action`,
18879 * `data-action`, or `x-action` attributes.
18880 *
18881 * @element form
18882 * @priority 0
18883 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
18884 * ({@link guide/expression#-event- Event object is available as `$event`})
18885 *
18886 * @example
18887   <example>
18888     <file name="index.html">
18889      <script>
18890        function Ctrl($scope) {
18891          $scope.list = [];
18892          $scope.text = 'hello';
18893          $scope.submit = function() {
18894            if ($scope.text) {
18895              $scope.list.push(this.text);
18896              $scope.text = '';
18897            }
18898          };
18899        }
18900      </script>
18901      <form ng-submit="submit()" ng-controller="Ctrl">
18902        Enter text and hit enter:
18903        <input type="text" ng-model="text" name="text" />
18904        <input type="submit" id="submit" value="Submit" />
18905        <pre>list={{list}}</pre>
18906      </form>
18907     </file>
18908     <file name="protractor.js" type="protractor">
18909       it('should check ng-submit', function() {
18910         expect(element(by.binding('list')).getText()).toBe('list=[]');
18911         element(by.css('#submit')).click();
18912         expect(element(by.binding('list')).getText()).toContain('hello');
18913         expect(element(by.input('text')).getAttribute('value')).toBe('');
18914       });
18915       it('should ignore empty strings', function() {
18916         expect(element(by.binding('list')).getText()).toBe('list=[]');
18917         element(by.css('#submit')).click();
18918         element(by.css('#submit')).click();
18919         expect(element(by.binding('list')).getText()).toContain('hello');
18920        });
18921     </file>
18922   </example>
18923 */
18924
18925/**
18926 * @ngdoc directive
18927 * @name ngFocus
18928 *
18929 * @description
18930 * Specify custom behavior on focus event.
18931 *
18932 * @element window, input, select, textarea, a
18933 * @priority 0
18934 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
18935 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
18936 *
18937 * @example
18938 * See {@link ng.directive:ngClick ngClick}
18939 */
18940
18941/**
18942 * @ngdoc directive
18943 * @name ngBlur
18944 *
18945 * @description
18946 * Specify custom behavior on blur event.
18947 *
18948 * @element window, input, select, textarea, a
18949 * @priority 0
18950 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
18951 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
18952 *
18953 * @example
18954 * See {@link ng.directive:ngClick ngClick}
18955 */
18956
18957/**
18958 * @ngdoc directive
18959 * @name ngCopy
18960 *
18961 * @description
18962 * Specify custom behavior on copy event.
18963 *
18964 * @element window, input, select, textarea, a
18965 * @priority 0
18966 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
18967 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
18968 *
18969 * @example
18970   <example>
18971     <file name="index.html">
18972      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
18973      copied: {{copied}}
18974     </file>
18975   </example>
18976 */
18977
18978/**
18979 * @ngdoc directive
18980 * @name ngCut
18981 *
18982 * @description
18983 * Specify custom behavior on cut event.
18984 *
18985 * @element window, input, select, textarea, a
18986 * @priority 0
18987 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
18988 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
18989 *
18990 * @example
18991   <example>
18992     <file name="index.html">
18993      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
18994      cut: {{cut}}
18995     </file>
18996   </example>
18997 */
18998
18999/**
19000 * @ngdoc directive
19001 * @name ngPaste
19002 *
19003 * @description
19004 * Specify custom behavior on paste event.
19005 *
19006 * @element window, input, select, textarea, a
19007 * @priority 0
19008 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19009 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19010 *
19011 * @example
19012   <example>
19013     <file name="index.html">
19014      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19015      pasted: {{paste}}
19016     </file>
19017   </example>
19018 */
19019
19020/**
19021 * @ngdoc directive
19022 * @name ngIf
19023 * @restrict A
19024 *
19025 * @description
19026 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19027 * {expression}. If the expression assigned to `ngIf` evaluates to a false
19028 * value then the element is removed from the DOM, otherwise a clone of the
19029 * element is reinserted into the DOM.
19030 *
19031 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19032 * element in the DOM rather than changing its visibility via the `display` css property.  A common
19033 * case when this difference is significant is when using css selectors that rely on an element's
19034 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
19034s.
19035 *
19036 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19037 * is created when the element is restored.  The scope created within `ngIf` inherits from
19038 * its parent scope using
19039 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
19040 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19041 * a javascript primitive defined in the parent scope. In this case any modifications made to the
19042 * variable within the child scope will override (hide) the value in the parent scope.
19043 *
19044 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19045 * is if an element's class attribute is directly modified after it's compiled, using something like
19046 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19047 * the added class will be lost because the original compiled state is used to regenerate the element.
19048 *
19049 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19050 * and `leave` effects.
19051 *
19052 * @animations
19053 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
19054 * leave - happens just before the ngIf contents are removed from the DOM
19055 *
19056 * @element ANY
19057 * @scope
19058 * @priority 600
19059 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19060 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19061 *     element is added to the DOM tree.
19062 *
19063 * @example
19064  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19065    <file name="index.html">
19066      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19067      Show when checked:
19068      <span ng-if="checked" class="animate-if">
19069        I'm removed when the checkbox is unchecked.
19070      </span>
19071    </file>
19072    <file name="animations.css">
19073      .animate-if {
19074        background:white;
19075        border:1px solid black;
19076        padding:10px;
19077      }
19078
19079      .animate-if.ng-enter, .animate-if.ng-leave {
19080        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19081        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19082      }
19083
19084      .animate-if.ng-enter,
19085      .animate-if.ng-leave.ng-leave-active {
19086        opacity:0;
19087      }
19088
19089      .animate-if.ng-leave,
19090      .animate-if.ng-enter.ng-enter-active {
19091        opacity:1;
19092      }
19093    </file>
19094  </example>
19095 */
19096var ngIfDirective = ['$animate', function($animate) {
19097  return {
19098    transclude: 'element',
19099    priority: 600,
19100    terminal: true,
19101    restrict: 'A',
19102    $$tlb: true,
19103    link: function ($scope, $element, $attr, ctrl, $transclude) {
19104        var block, childScope, previousElements;
19105        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19106
19107          if (toBoolean(value)) {
19108            if (!childScope) {
19109              childScope = $scope.$new();
19110              $transclude(childScope, function (clone) {
19111                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19112                // Note: We only need the first/last node of the cloned nodes.
19113                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19114                // by a directive with templateUrl when it's template arrives.
19115                block = {
19116                  clone: clone
19117                };
19118                $animate.enter(clone, $element.parent(), $element);
19119              });
19120            }
19121          } else {
19122            if(previousElements) {
19123              previousElements.remove();
19124              previousElements = null;
19125            }
19126            if(childScope) {
19127              childScope.$destroy();
19128              childScope = null;
19129            }
19130            if(block) {
19131              previousElements = getBlockElements(block.clone);
19132              $animate.leave(previousElements, function() {
19133                previousElements = null;
19134              });
19135              block = null;
19136            }
19137          }
19138        });
19139    }
19140  };
19141}];
19142
19143/**
19144 * @ngdoc directive
19145 * @name ngInclude
19146 * @restrict ECA
19147 *
19148 * @description
19149 * Fetches, compiles and includes an external HTML fragment.
19150 *
19151 * By default, the template URL is restricted to the same domain and protocol as the
19152 * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19153 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19154 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19155 * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19156 * ng.$sce Strict Contextual Escaping}.
19157 *
19158 * In addition, the browser's
19159 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19160 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19161 * policy may further restrict whether the template is successfully loaded.
19162 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19163 * access on some browsers.
19164 *
19165 * @animations
19166 * enter - animation is used to bring new content into the browser.
19167 * leave - animation is used to animate existing content away.
19168 *
19169 * The enter and leave animation occur concurrently.
19170 *
19171 * @scope
19172 * @priority 400
19173 *
19174 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19175 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19176 * @param {string=} onload Expression to evaluate when a new partial is loaded.
19177 *
19178 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19179 *                  $anchorScroll} to scroll the viewport after the content is loaded.
19180 *
19181 *                  - If the attribute is not set, disable scrolling.
19182 *                  - If the attribute is set without value, enable scrolling.
19183 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19184 *
19185 * @example
19186  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19187    <file name="index.html">
19188     <div ng-controller="Ctrl">
19189       <select ng-model="template" ng-options="t.name for t in templates">
19190        <option value="">(blank)</option>
19191       </select>
19192       url of the template: <tt>{{template.url}}</tt>
19193       <hr/>
19194       <div class="slide-animate-container">
19195         <div class="slide-animate" ng-include="template.url"></div>
19196       </div>
19197     </div>
19198    </file>
19199    <file name="script.js">
19200      function Ctrl($scope) {
19201        $scope.templates =
19202          [ { name: 'template1.html', url: 'template1.html'},
19203            { name: 'template2.html', url: 'template2.html'} ];
19204        $scope.template = $scope.templates[0];
19205      }
19206     </file>
19207    <file name="template1.html">
19208      Content of template1.html
19209    </file>
19210    <file name="template2.html">
19211      Content of template2.html
19212    </file>
19213    <file name="animations.css">
19214      .slide-animate-container {
19215        position:relative;
19216        background:white;
19217        border:1px solid black;
19218        height:40px;
19219        overflow:hidden;
19220      }
19221
19222      .slide-animate {
19223        padding:10px;
19224      }
19225
19226      .slide-animate.ng-enter, .slide-animate.ng-leave {
19227        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19228        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19229
19230        position:absolute;
19231        top:0;
19232        left:0;
19233        right:0;
19234        bottom:0;
19235        display:block;
19236        padding:10px;
19237      }
19238
19239      .slide-animate.ng-enter {
19240        top:-50px;
19241      }
19242      .slide-animate.ng-enter.ng-enter-active {
19243        top:0;
19244      }
19245
19246      .slide-animate.ng-leave {
19247        top:0;
19248      }
19249      .slide-animate.ng-leave.ng-leave-active {
19250        top:50px;
19251      }
19252    </file>
19253    <file name="protractor.js" type="protractor">
19254      var templateSelect = element(by.model('template'));
19255      var includeElem = element(by.css('[ng-include]'));
19256
19257      it('should load template1.html', function() {
19258        expect(includeElem.getText()).toMatch(/Content of template1.html/);
19259      });
19260
19261      it('should load template2.html', function() {
19262        if (browser.params.browser == 'firefox') {
19263          // Firefox can't handle using selects
19264          // See https://github.com/angular/protractor/issues/480
19265          return;
19266        }
19267        templateSelect.click();
19268        templateSelect.element.all(by.css('option')).get(2).click();
19269        expect(includeElem.getText()).toMatch(/Content of template2.html/);
19270      });
19271
19272      it('should change to blank', function() {
19273        if (browser.params.browser == 'firefox') {
19274          // Firefox can't handle using selects
19275          return;
19276        }
19277        templateSelect.click();
19278        templateSelect.element.all(by.css('option')).get(0).click();
19279        expect(includeElem.isPresent()).toBe(false);
19280      });
19281    </file>
19282  </example>
19283 */
19284
19285
19286/**
19287 * @ngdoc event
19288 * @name ngInclude#$includeContentRequested
19289 * @eventType emit on the scope ngInclude was declared in
19290 * @description
19291 * Emitted every time the ngInclude content is requested.
19292 */
19293
19294
19295/**
19296 * @ngdoc event
19297 * @name ngInclude#$includeContentLoaded
19298 * @eventType emit on the current ngInclude scope
19299 * @description
19300 * Emitted every time the ngInclude content is reloaded.
19301 */
19302var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
19303                  function($http,   $templateCache,   $anchorScroll,   $animate,   $sce) {
19304  return {
19305    restrict: 'ECA',
19306    priority: 400,
19307    terminal: true,
19308    transclude: 'element',
19309    controller: angular.noop,
19310    compile: function(element, attr) {
19311      var srcExp = attr.ngInclude || attr.src,
19312          onloadExp = attr.onload || '',
19313          autoScrollExp = attr.autoscroll;
19314
19315      return function(scope, $element, $attr, ctrl, $transclude) {
19316        var changeCounter = 0,
19317            currentScope,
19318            previousElement,
19319            currentElement;
19320
19321        var cleanupLastIncludeContent = function() {
19322          if(previousElement) {
19323            previousElement.remove();
19324            previousElement = null;
19325          }
19326          if(currentScope) {
19327            currentScope.$destroy();
19328            currentScope = null;
19329          }
19330          if(currentElement) {
19331            $animate.leave(currentElement, function() {
19332              previousElement = null;
19333            });
19334            previousElement = currentElement;
19335            currentElement = null;
19336          }
19337        };
19338
19339        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
19340          var afterAnimation = function() {
19341            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
19342              $anchorScroll();
19343            }
19344          };
19345          var thisChangeId = ++changeCounter;
19346
19347          if (src) {
19348            $http.get(src, {cache: $templateCache}).success(function(response) {
19349              if (thisChangeId !== changeCounter) return;
19350              var newScope = scope.$new();
19351              ctrl.template = response;
19352
19353              // Note: This will also link all children of ng-include that were contained in the original
19354              // html. If that content contains controllers, ... they could pollute/change the scope.
19355              // However, using ng-include on an element with additional content does not make sense...
19356              // Note: We can't remove them in the cloneAttchFn of $transclude as that
19357              // function is called before linking the content, which would apply child
19358              // directives to non existing elements.
19359              var clone = $transclude(newScope, function(clone) {
19360                cleanupLastIncludeContent();
19361                $animate.enter(clone, null, $element, afterAnimation);
19362              });
19363
19364              currentScope = newScope;
19365              currentElement = clone;
19366
19367              currentScope.$emit('$includeContentLoaded');
19368              scope.$eval(onloadExp);
19369            }).error(function() {
19370              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
19371            });
19372            scope.$emit('$includeContentRequested');
19373          } else {
19374            cleanupLastIncludeContent();
19375            ctrl.template = null;
19376          }
19377        });
19378      };
19379    }
19380  };
19381}];
19382
19383// This directive is called during the $transclude call of the first `ngInclude` directive.
19384// It will replace and compile the content of the element with the loaded template.
19385// We need this directive so that the element content is already filled when
19386// the link function of another directive on the same element as ngInclude
19387// is called.
19388var ngIncludeFillContentDirective = ['$compile',
19389  function($compile) {
19390    return {
19391      restrict: 'ECA',
19392      priority: -400,
19393      require: 'ngInclude',
19394      link: function(scope, $element, $attr, ctrl) {
19395        $element.html(ctrl.template);
19396        $compile($element.contents())(scope);
19397      }
19398    };
19399  }];
19400
19401/**
19402 * @ngdoc directive
19403 * @name ngInit
19404 * @restrict AC
19405 *
19406 * @description
19407 * The `ngInit` directive allows you to evaluate an expression in the
19408 * current scope.
19409 *
19410 * <div class="alert alert-error">
19411 * The only appropriate use of `ngInit` is for aliasing special properties of
19412 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
19413 * should use {@link guide/controller controllers} rather than `ngInit`
19414 * to initialize values on a scope.
19415 * </div>
19416 * <div class="alert alert-warning">
19417 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
19418 * sure you have parenthesis for correct precedence:
19419 * <pre class="prettyprint">
19420 *   <div ng-init="test1 = (data | orderBy:'name')"></div>
19421 * </pre>
19422 * </div>
19423 *
19424 * @priority 450
19425 *
19426 * @element ANY
19427 * @param {expression} ngInit {@link guide/expression Expression} to eval.
19428 *
19429 * @example
19430   <example>
19431     <file name="index.html">
19432   <script>
19433     function Ctrl($scope) {
19434       $scope.list = [['a', 'b'], ['c', 'd']];
19435     }
19436   </script>
19437   <div ng-controller="Ctrl">
19438     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
19439       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
19440          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
19441       </div>
19442     </div>
19443   </div>
19444     </file>
19445     <file name="protractor.js" type="protractor">
19446       it('should alias index positions', function() {
19447         var elements = element.all(by.css('.example-init'));
19448         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
19449         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
19450         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
19451         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
19452       });
19453     </file>
19454   </example>
19455 */
19456var ngInitDirective = ngDirective({
19457  priority: 450,
19458  compile: function() {
19459    return {
19460      pre: function(scope, element, attrs) {
19461        scope.$eval(attrs.ngInit);
19462      }
19463    };
19464  }
19465});
19466
19467/**
19468 * @ngdoc directive
19469 * @name ngNonBindable
19470 * @restrict AC
19471 * @priority 1000
19472 *
19473 * @description
19474 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
19475 * DOM element. This is useful if the element contains what appears to be Angular directives and
19476 * bindings but which should be ignored by Angular. This could be the case if you have a site that
19477 * displays snippets of code, for instance.
19478 *
19479 * @element ANY
19480 *
19481 * @example
19482 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
19483 * but the one wrapped in `ngNonBindable` is left alone.
19484 *
19485 * @example
19486    <example>
19487      <file name="index.html">
19488        <div>Normal: {{1 + 2}}</div>
19489        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
19490      </file>
19491      <file name="protractor.js" type="protractor">
19492       it('should check ng-non-bindable', function() {
19493         expect(element(by.binding('1 + 2')).getText()).toContain('3');
19494         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
19495       });
19496      </file>
19497    </example>
19498 */
19499var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
19500
19501/**
19502 * @ngdoc directive
19503 * @name ngPluralize
19504 * @restrict EA
19505 *
19506 * @description
19507 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
19508 * These rules are bundled with angular.js, but can be overridden
19509 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
19510 * by specifying the mappings between
19511 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19512 * and the strings to be displayed.
19513 *
19514 * # Plural categories and explicit number rules
19515 * There are two
19516 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19517 * in Angular's default en-US locale: "one" and "other".
19518 *
19519 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
19520 * any number that is not 1), an explicit number rule can only match one number. For example, the
19521 * explicit number rule for "3" matches the number 3. There are examples of plural categories
19522 * and explicit number rules throughout the rest of this documentation.
19523 *
19524 * # Configuring ngPluralize
19525 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
19526 * You can also provide an optional attribute, `offset`.
19527 *
19528 * The value of the `count` attribute can be either a string or an {@link guide/expression
19529 * Angular expression}; these are evaluated on the current scope for its bound value.
19530 *
19531 * The `when` attribute specifies the mappings between plural categories and the actual
19532 * string to be displayed. The value of the attribute should be a JSON object.
19533 *
19534 * The following example shows how to configure ngPluralize:
19535 *
19536 * ```html
19537 * <ng-pluralize count="personCount"
19538                 when="{'0': 'Nobody is viewing.',
19539 *                      'one': '1 person is viewing.',
19540 *                      'other': '{} people are viewing.'}">
19541 * </ng-pluralize>
19542 *```
19543 *
19544 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
19545 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
19546 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
19547 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
19548 * show "a dozen people are viewing".
19549 *
19550 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
19551 * into pluralized strings. In the previous example, Angular will replace `{}` with
19552 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
19553 * for <span ng-non-bindable>{{numberExpression}}</span>.
19554 *
19555 * # Configuring ngPluralize with offset
19556 * The `offset` attribute allows further customization of pluralized text, which can result in
19557 * a better user experience. For example, instead of the message "4 people are viewing this document",
19558 * you might display "John, Kate and 2 others are viewing this document".
19559 * The offset attribute allows you to offset a number by any desired value.
19560 * Let's take a look at an example:
19561 *
19562 * ```html
19563 * <ng-pluralize count="personCount" offset=2
19564 *               when="{'0': 'Nobody is viewing.',
19565 *                      '1': '{{person1}} is viewing.',
19566 *                      '2': '{{person1}} and {{person2}} are viewing.',
19567 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
19568 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19569 * </ng-pluralize>
19570 * ```
19571 *
19572 * Notice that we are still using two plural categories(one, other), but we added
19573 * three explicit number rules 0, 1 and 2.
19574 * When one person, perhaps John, views the document, "John is viewing" will be shown.
19575 * When three people view the document, no explicit number rule is found, so
19576 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
19577 * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
19578 * is shown.
19579 *
19580 * Note that when you specify offsets, you must provide explicit number rules for
19581 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
19582 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
19583 * plural categories "one" and "other".
19584 *
19585 * @param {string|expression} count The variable to be bound to.
19586 * @param {string} when The mapping between plural category to its corresponding strings.
19587 * @param {number=} offset Offset to deduct from the total number.
19588 *
19589 * @example
19590    <example>
19591      <file name="index.html">
19592        <script>
19593          function Ctrl($scope) {
19594            $scope.person1 = 'Igor';
19595            $scope.person2 = 'Misko';
19596            $scope.personCount = 1;
19597          }
19598        </script>
19599        <div ng-controller="Ctrl">
19600          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
19601          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
19602          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
19603
19604          <!--- Example with simple pluralization rules for en locale --->
19605          Without Offset:
19606          <ng-pluralize count="personCount"
19607                        when="{'0': 'Nobody is viewing.',
19608                               'one': '1 person is viewing.',
19609                               'other': '{} people are viewing.'}">
19610          </ng-pluralize><br>
19611
19612          <!--- Example with offset --->
19613          With Offset(2):
19614          <ng-pluralize count="personCount" offset=2
19615                        when="{'0': 'Nobody is viewing.',
19616                               '1': '{{person1}} is viewing.',
19617                               '2': '{{person1}} and {{person2}} are viewing.',
19618                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
19619                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19620          </ng-pluralize>
19621        </div>
19622      </file>
19623      <file name="protractor.js" type="protractor">
19624        it('should show correct pluralized string', function() {
19625          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
19626          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19627          var countInput = element(by.model('personCount'));
19628
19629          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
19630          expect(withOffset.getText()).toEqual('Igor is viewing.');
19631
19632          countInput.clear();
19633          countInput.sendKeys('0');
19634
19635          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
19636          expect(withOffset.getText()).toEqual('Nobody is viewing.');
19637
19638          countInput.clear();
19639          countInput.sendKeys('2');
19640
19641          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
19642          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
19643
19644          countInput.clear();
19645          countInput.sendKeys('3');
19646
19647          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
19648          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
19649
19650          countInput.clear();
19651          countInput.sendKeys('4');
19652
19653          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
19654          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
19655        });
19656        it('should show data-bound names', function() {
19657          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19658          var personCount = element(by.model('personCount'));
19659          var person1 = element(by.model('person1'));
19660          var person2 = element(by.model('person2'));
19661          personCount.clear();
19662          personCount.sendKeys('4');
19663          person1.clear();
19664          person1.sendKeys('Di');
19665          person2.clear();
19666          person2.sendKeys('Vojta');
19667          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
19668        });
19669      </file>
19670    </example>
19671 */
19672var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
19673  var BRACE = /{}/g;
19674  return {
19675    restrict: 'EA',
19676    link: function(scope, element, attr) {
19677      var numberExp = attr.count,
19678          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
19679          offset = attr.offset || 0,
19680          whens = scope.$eval(whenExp) || {},
19681          whensExpFns = {},
19682          startSymbol = $interpolate.startSymbol(),
19683          endSymbol = $interpolate.endSymbol(),
19684          isWhen = /^when(Minus)?(.+)$/;
19685
19686      forEach(attr, function(expression, attributeName) {
19687        if (isWhen.test(attributeName)) {
19688          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
19689            element.attr(attr.$attr[attributeName]);
19690        }
19691      });
19692      forEach(whens, function(expression, key) {
19693        whensExpFns[key] =
19694          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
19695            offset + endSymbol));
19696      });
19697
19698      scope.$watch(function ngPluralizeWatch() {
19699        var value = parseFloat(scope.$eval(numberExp));
19700
19701        if (!isNaN(value)) {
19702          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
19703          //check it against pluralization rules in $locale service
19704          if (!(value in whens)) value = $locale.pluralCat(value - offset);
19705           return whensExpFns[value](scope, element, true);
19706        } else {
19707          return '';
19708        }
19709      }, function ngPluralizeWatchAction(newVal) {
19710        element.text(newVal);
19711      });
19712    }
19713  };
19714}];
19715
19716/**
19717 * @ngdoc directive
19718 * @name ngRepeat
19719 *
19720 * @description
19721 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
19722 * instance gets its own scope, where the given loop variable is set to the current collection item,
19723 * and `$index` is set to the item index or key.
19724 *
19725 * Special properties are exposed on the local scope of each template instance, including:
19726 *
19727 * | Variable  | Type            | Details                                                                     |
19728 * |-----------|-----------------|-----------------------------------------------------------------------------|
19729 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
19730 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
19731 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
19732 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
19733 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
19734 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
19735 *
19736 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
19737 * This may be useful when, for instance, nesting ngRepeats.
19738 *
19739 * # Special repeat start and end points
19740 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
19741 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
19742 * 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)
19743 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
19744 *
19745 * The example below makes use of this feature:
19746 * ```html
19747 *   <header ng-repeat-start="item in items">
19748 *     Header {{ item }}
19749 *   </header>
19750 *   <div class="body">
19751 *     Body {{ item }}
19752 *   </div>
19753 *   <footer ng-repeat-end>
19754 *     Footer {{ item }}
19755 *   </footer>
19756 * ```
19757 *
19758 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
19759 * ```html
19760 *   <header>
19761 *     Header A
19762 *   </header>
19763 *   <div class="body">
19764 *     Body A
19765 *   </div>
19766 *   <footer>
19767 *     Footer A
19768 *   </footer>
19769 *   <header>
19770 *     Header B
19771 *   </header>
19772 *   <div class="body">
19773 *     Body B
19774 *   </div>
19775 *   <footer>
19776 *     Footer B
19777 *   </footer>
19778 * ```
19779 *
19780 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
19781 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
19782 *
19783 * @animations
19784 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
19785 *
19786 * **.leave** - when an item is removed from the list or when an item is filtered out
19787 *
19788 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
19789 *
19790 * @element ANY
19791 * @scope
19792 * @priority 1000
19793 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
19794 *   formats are currently supported:
19795 *
19796 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
19797 *     is a scope expression giving the collection to enumerate.
19798 *
19799 *     For example: `album in artist.albums`.
19800 *
19801 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
19802 *     and `expression` is the scope expression giving the collection to enumerate.
19803 *
19804 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
19805 *
19806 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
19807 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
19808 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
19809 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
19810 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
19811 *     before specifying a tracking expression.
19812 *
19813 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
19814 *     will be associated by item identity in the array.
19815 *
19816 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
19817 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
19818 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
19819 *     element in the same way in the DOM.
19820 *
19821 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
19822 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
19823 *     property is same.
19824 *
19825 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
19826 *     to items in conjunction with a tracking expression.
19827 *
19828 * @example
19829 * This example initializes the scope to a list of names and
19830 * then uses `ngRepeat` to display every person:
19831  <example module="ngAnimate" deps="angular-animate.js" animations="true">
19832    <file name="index.html">
19833      <div ng-init="friends = [
19834        {name:'John', age:25, gender:'boy'},
19835        {name:'Jessie', age:30, gender:'girl'},
19836        {name:'Johanna', age:28, gender:'girl'},
19837        {name:'Joy', age:15, gender:'girl'},
19838        {name:'Mary', age:28, gender:'girl'},
19839        {name:'Peter', age:95, gender:'boy'},
19840        {name:'Sebastian', age:50, gender:'boy'},
19841        {name:'Erika', age:27, gender:'girl'},
19842        {name:'Patrick', age:40, gender:'boy'},
19843        {name:'Samantha', age:60, gender:'girl'}
19844      ]">
19845        I have {{friends.length}} friends. They are:
19846        <input type="search" ng-model="q" placeholder="filter friends..." />
19847        <ul class="example-animate-container">
19848          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
19849            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
19850          </li>
19851        </ul>
19852      </div>
19853    </file>
19854    <file name="animations.css">
19855      .example-animate-container {
19856        background:white;
19857        border:1px solid black;
19858        list-style:none;
19859        margin:0;
19860        padding:0 10px;
19861      }
19862
19863      .animate-repeat {
19864        line-height:40px;
19865        list-style:none;
19866        box-sizing:border-box;
19867      }
19868
19869      .animate-repeat.ng-move,
19870      .animate-repeat.ng-enter,
19871      .animate-repeat.ng-leave {
19872        -webkit-transition:all linear 0.5s;
19873        transition:all linear 0.5s;
19874      }
19875
19876      .animate-repeat.ng-leave.ng-leave-active,
19877      .animate-repeat.ng-move,
19878      .animate-repeat.ng-enter {
19879        opacity:0;
19880        max-height:0;
19881      }
19882
19883      .animate-repeat.ng-leave,
19884      .animate-repeat.ng-move.ng-move-active,
19885      .animate-repeat.ng-enter.ng-enter-active {
19886        opacity:1;
19887        max-height:40px;
19888      }
19889    </file>
19890    <file name="protractor.js" type="protractor">
19891      var friends = element.all(by.repeater('friend in friends'));
19892
19893      it('should render initial data set', function() {
19894        expect(friends.count()).toBe(10);
19895        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
19896        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
19897        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
19898        expect(element(by.binding('friends.length')).getText())
19899            .toMatch("I have 10 friends. They are:");
19900      });
19901
19902       it('should update repeater when filter predicate changes', function() {
19903         expect(friends.count()).toBe(10);
19904
19905         element(by.model('q')).sendKeys('ma');
19906
19907         expect(friends.count()).toBe(2);
19908         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
19909         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
19910       });
19911      </file>
19912    </example>
19913 */
19914var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
19915  var NG_REMOVED = '$$NG_REMOVED';
19916  var ngRepeatMinErr = minErr('ngRepeat');
19917  return {
19918    transclude: 'element',
19919    priority: 1000,
19920    terminal: true,
19921    $$tlb: true,
19922    link: function($scope, $element, $attr, ctrl, $transclude){
19923        var expression = $attr.ngRepeat;
19924        var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
19925          trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
19926          lhs, rhs, valueIdentifier, keyIdentifier,
19927          hashFnLocals = {$id: hashKey};
19928
19929        if (!match) {
19930          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
19931            expression);
19932        }
19933
19934        lhs = match[1];
19935        rhs = match[2];
19936        trackByExp = match[3];
19937
19938        if (trackByExp) {
19939          trackByExpGetter = $parse(trackByExp);
19940          trackByIdExpFn = function(key, value, index) {
19941            // assign key, value, and $index to the locals so that they can be used in hash functions
19942            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
19943            hashFnLocals[valueIdentifier] = value;
19944            hashFnLocals.$index = index;
19945            return trackByExpGetter($scope, hashFnLocals);
19946          };
19947        } else {
19948          trackByIdArrayFn = function(key, value) {
19949            return hashKey(value);
19950          };
19951          trackByIdObjFn = function(key) {
19952            return key;
19953          };
19954        }
19955
19956        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
19957        if (!match) {
19958          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
19959                                                                    lhs);
19960        }
19961        valueIdentifier = match[3] || match[1];
19962        keyIdentifier = match[2];
19963
19964        // Store a list of elements from previous run. This is a hash where key is the item from the
19965        // iterator, and the value is objects with following properties.
19966        //   - scope: bound scope
19967        //   - element: previous element.
19968        //   - index: position
19969        var lastBlockMap = {};
19970
19971        //watch props
19972        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
19973          var index, length,
19974              previousNode = $element[0],     // current position of the node
19975              nextNode,
19976              // Same as lastBlockMap but it has the current state. It will become the
19977              // lastBlockMap on the next iteration.
19978              nextBlockMap = {},
19979              arrayLength,
19980              childScope,
19981              key, value, // key/value of iteration
19982              trackById,
19983              trackByIdFn,
19984              collectionKeys,
19985              block,       // last object information {scope, element, id}
19986              nextBlockOrder = [],
19987              elementsToRemove;
19988
19989
19990          if (isArrayLike(collection)) {
19991            collectionKeys = collection;
19992            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
19993          } else {
19994            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
19995            // if object, extract keys, sort them and use to determine order of iteration over obj props
19996            collectionKeys = [];
19997            for (key in collection) {
19998              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
19999                collectionKeys.push(key);
20000              }
20001            }
20002            collectionKeys.sort();
20003          }
20004
20005          arrayLength = collectionKeys.length;
20006
20007          // locate existing items
20008          length = nextBlockOrder.length = collectionKeys.length;
20009          for(index = 0; index < length; index++) {
20010           key = (collection === collectionKeys) ? index : collectionKeys[index];
20011           value = collection[key];
20012           trackById = trackByIdFn(key, value, index);
20013           assertNotHasOwnProperty(trackById, '`track by` id');
20014           if(lastBlockMap.hasOwnProperty(trackById)) {
20015             block = lastBlockMap[trackById];
20016             delete lastBlockMap[trackById];
20017             nextBlockMap[trackById] = block;
20018             nextBlockOrder[index] = block;
20019           } else if (nextBlockMap.hasOwnProperty(trackById)) {
20020             // restore lastBlockMap
20021             forEach(nextBlockOrder, function(block) {
20022               if (block && block.scope) lastBlockMap[block.id] = block;
20023             });
20024             // This is a duplicate and we need to throw an error
20025             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
20026                                                                                                                                                    expression,       trackById);
20027           } else {
20028             // new never before seen block
20029             nextBlockOrder[index] = { id: trackById };
20030             nextBlockMap[trackById] = false;
20031           }
20032         }
20033
20034          // remove existing items
20035          for (key in lastBlockMap) {
20036            // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20037            if (lastBlockMap.hasOwnProperty(key)) {
20038              block = lastBlockMap[key];
20039              elementsToRemove = getBlockElements(block.clone);
20040              $animate.leave(elementsToRemove);
20041              forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
20042              block.scope.$destroy();
20043            }
20044          }
20045
20046          // we are not using forEach for perf reasons (trying to avoid #call)
20047          for (index = 0, length = collectionKeys.length; index < length; index++) {
20048            key = (collection === collectionKeys) ? index : collectionKeys[index];
20049            value = collection[key];
20050            block = nextBlockOrder[index];
20051            if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20052
20053            if (block.scope) {
20054              // if we have already seen this object, then we need to reuse the
20055              // associated scope/element
20056              childScope = block.scope;
20057
20058              nextNode = previousNode;
20059              do {
20060                nextNode = nextNode.nextSibling;
20061              } while(nextNode && nextNode[NG_REMOVED]);
20062
20063              if (getBlockStart(block) != nextNode) {
20064                // existing item which got moved
20065                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20066              }
20067              previousNode = getBlockEnd(block);
20068            } else {
20069              // new item which we don't know about
20070              childScope = $scope.$new();
20071            }
20072
20073            childScope[valueIdentifier] = value;
20074            if (keyIdentifier) childScope[keyIdentifier] = key;
20075            childScope.$index = index;
20076            childScope.$first = (index === 0);
20077            childScope.$last = (index === (arrayLength - 1));
20078            childScope.$middle = !(childScope.$first || childScope.$last);
20079            // jshint bitwise: false
20080            childScope.$odd = !(childScope.$even = (index&1) === 0);
20081            // jshint bitwise: true
20082
20083            if (!block.scope) {
20084              $transclude(childScope, function(clone) {
20085                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20086                $animate.enter(clone, null, jqLite(previousNode));
20087                previousNode = clone;
20088                block.scope = childScope;
20089                // Note: We only need the first/last node of the cloned nodes.
20090                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20091                // by a directive with templateUrl when it's template arrives.
20092                block.clone = clone;
20093                nextBlockMap[block.id] = block;
20094              });
20095            }
20096          }
20097          lastBlockMap = nextBlockMap;
20098        });
20099    }
20100  };
20101
20102  function getBlockStart(block) {
20103    return block.clone[0];
20104  }
20105
20106  function getBlockEnd(block) {
20107    return block.clone[block.clone.length - 1];
20108  }
20109}];
20110
20111/**
20112 * @ngdoc directive
20113 * @name ngShow
20114 *
20115 * @description
20116 * The `ngShow` directive shows or hides the given HTML element based on the expression
20117 * provided to the ngShow attribute. The element is shown or hidden by removing or adding
20118 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20119 * in AngularJS and sets the display style to none (using an !important flag).
20120 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20121 *
20122 * ```html
20123 * <!-- when $scope.myValue is truthy (element is visible) -->
20124 * <div ng-show="myValue"></div>
20125 *
20126 * <!-- when $scope.myValue is falsy (element is hidden) -->
20127 * <div ng-show="myValue" class="ng-hide"></div>
20128 * ```
20129 *
20130 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
20131 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20132 * from the element causing the element not to appear hidden.
20133 *
20134 * ## Why is !important used?
20135 *
20136 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20137 * can be easily overridden by heavier selectors. For example, something as simple
20138 * as changing the display style on a HTML list item would make hidden elements appear visible.
20139 * This also becomes a bigger issue when dealing with CSS frameworks.
20140 *
20141 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20142 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20143 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20144 *
20145 * ### Overriding .ng-hide
20146 *
20147 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20148 * restating the styles for the .ng-hide class in CSS:
20149 * ```css
20150 * .ng-hide {
20151 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20152 *   display:block!important;
20153 *
20154 *   //this is just another form of hiding an element
20155 *   position:absolute;
20156 *   top:-9999px;
20157 *   left:-9999px;
20158 * }
20159 * ```
20160 *
20161 * Just remember to include the important flag so the CSS override will function.
20162 *
20163 * <div class="alert alert-warning">
20164 * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20165 * "f" / "0" / "false" / "no" / "n" / "[]"
20166 * </div>
20167 *
20168 * ## A note about animations with ngShow
20169 *
20170 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20171 * is true and false. This system works like the animation system present with ngClass except that
20172 * you must also include the !important flag to override the display property
20173 * so that you can perform an animation when the element is hidden during the time of the animation.
20174 *
20175 * ```css
20176 * //
20177 * //a working example can be found at the bottom of this page
20178 * //
20179 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20180 *   transition:0.5s linear all;
20181 *   display:block!important;
20182 * }
20183 *
20184 * .my-element.ng-hide-add { ... }
20185 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20186 * .my-element.ng-hide-remove { ... }
20187 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20188 * ```
20189 *
20190 * @animations
20191 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20192 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
20193 *
20194 * @element ANY
20195 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20196 *     then the element is shown or hidden respectively.
20197 *
20198 * @example
20199  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20200    <file name="index.html">
20201      Click me: <input type="checkbox" ng-model="checked"><br/>
20202      <div>
20203        Show:
20204        <div class="check-element animate-show" ng-show="checked">
20205          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20206        </div>
20207      </div>
20208      <div>
20209        Hide:
20210        <div class="check-element animate-show" ng-hide="checked">
20211          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20212        </div>
20213      </div>
20214    </file>
20215    <file name="glyphicons.css">
20216      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20217    </file>
20218    <file name="animations.css">
20219      .animate-show {
20220        -webkit-transition:all linear 0.5s;
20221        transition:all linear 0.5s;
20222        line-height:20px;
20223        opacity:1;
20224        padding:10px;
20225        border:1px solid black;
20226        background:white;
20227      }
20228
20229      .animate-show.ng-hide-add,
20230      .animate-show.ng-hide-remove {
20231        display:block!important;
20232      }
20233
20234      .animate-show.ng-hide {
20235        line-height:0;
20236        opacity:0;
20237        padding:0 10px;
20238      }
20239
20240      .check-element {
20241        padding:10px;
20242        border:1px solid black;
20243        background:white;
20244      }
20245    </file>
20246    <file name="protractor.js" type="protractor">
20247      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20248      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20249
20250      it('should check ng-show / ng-hide', function() {
20251        expect(thumbsUp.isDisplayed()).toBeFalsy();
20252        expect(thumbsDown.isDisplayed()).toBeTruthy();
20253
20254        element(by.model('checked')).click();
20255
20256        expect(thumbsUp.isDisplayed()).toBeTruthy();
20257        expect(thumbsDown.isDisplayed()).toBeFalsy();
20258      });
20259    </file>
20260  </example>
20261 */
20262var ngShowDirective = ['$animate', function($animate) {
20263  return function(scope, element, attr) {
20264    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
20265      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20266    });
20267  };
20268}];
20269
20270
20271/**
20272 * @ngdoc directive
20273 * @name ngHide
20274 *
20275 * @description
20276 * The `ngHide` directive shows or hides the given HTML element based on the expression
20277 * provided to the ngHide attribute. The element is shown or hidden by removing or adding
20278 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20279 * in AngularJS and sets the display style to none (using an !important flag).
20280 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20281 *
20282 * ```html
20283 * <!-- when $scope.myValue is truthy (element is hidden) -->
20284 * <div ng-hide="myValue"></div>
20285 *
20286 * <!-- when $scope.myValue is falsy (element is visible) -->
20287 * <div ng-hide="myValue" class="ng-hide"></div>
20288 * ```
20289 *
20290 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20291 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20292 * from the element causing the element not to appear hidden.
20293 *
20294 * ## Why is !important used?
20295 *
20296 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20297 * can be easily overridden by heavier selectors. For example, something as simple
20298 * as changing the display style on a HTML list item would make hidden elements appear visible.
20299 * This also becomes a bigger issue when dealing with CSS frameworks.
20300 *
20301 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20302 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20303 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20304 *
20305 * ### Overriding .ng-hide
20306 *
20307 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20308 * restating the styles for the .ng-hide class in CSS:
20309 * ```css
20310 * .ng-hide {
20311 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20312 *   display:block!important;
20313 *
20314 *   //this is just another form of hiding an element
20315 *   position:absolute;
20316 *   top:-9999px;
20317 *   left:-9999px;
20318 * }
20319 * ```
20320 *
20321 * Just remember to include the important flag so the CSS override will function.
20322 *
20323 * <div class="alert alert-warning">
20324 * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20325 * "f" / "0" / "false" / "no" / "n" / "[]"
20326 * </div>
20327 *
20328 * ## A note about animations with ngHide
20329 *
20330 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20331 * is true and false. This system works like the animation system present with ngClass, except that
20332 * you must also include the !important flag to override the display property so
20333 * that you can perform an animation when the element is hidden during the time of the animation.
20334 *
20335 * ```css
20336 * //
20337 * //a working example can be found at the bottom of this page
20338 * //
20339 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20340 *   transition:0.5s linear all;
20341 *   display:block!important;
20342 * }
20343 *
20344 * .my-element.ng-hide-add { ... }
20345 * .my-element.ng-hide-add.ng-hide-add-active { ... }
20346 * .my-element.ng-hide-remove { ... }
20347 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20348 * ```
20349 *
20350 * @animations
20351 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20352 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
20353 *
20354 * @element ANY
20355 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
20356 *     the element is shown or hidden respectively.
20357 *
20358 * @example
20359  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20360    <file name="index.html">
20361      Click me: <input type="checkbox" ng-model="checked"><br/>
20362      <div>
20363        Show:
20364        <div class="check-element animate-hide" ng-show="checked">
20365          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20366        </div>
20367      </div>
20368      <div>
20369        Hide:
20370        <div class="check-element animate-hide" ng-hide="checked">
20371          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20372        </div>
20373      </div>
20374    </file>
20375    <file name="glyphicons.css">
20376      @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20377    </file>
20378    <file name="animations.css">
20379      .animate-hide {
20380        -webkit-transition:all linear 0.5s;
20381        transition:all linear 0.5s;
20382        line-height:20px;
20383        opacity:1;
20384        padding:10px;
20385        border:1px solid black;
20386        background:white;
20387      }
20388
20389      .animate-hide.ng-hide-add,
20390      .animate-hide.ng-hide-remove {
20391        display:block!important;
20392      }
20393
20394      .animate-hide.ng-hide {
20395        line-height:0;
20396        opacity:0;
20397        padding:0 10px;
20398      }
20399
20400      .check-element {
20401        padding:10px;
20402        border:1px solid black;
20403        background:white;
20404      }
20405    </file>
20406    <file name="protractor.js" type="protractor">
20407      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20408      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20409
20410      it('should check ng-show / ng-hide', function() {
20411        expect(thumbsUp.isDisplayed()).toBeFalsy();
20412        expect(thumbsDown.isDisplayed()).toBeTruthy();
20413
20414        element(by.model('checked')).click();
20415
20416        expect(thumbsUp.isDisplayed()).toBeTruthy();
20417        expect(thumbsDown.isDisplayed()).toBeFalsy();
20418      });
20419    </file>
20420  </example>
20421 */
20422var ngHideDirective = ['$animate', function($animate) {
20423  return function(scope, element, attr) {
20424    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
20425      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
20426    });
20427  };
20428}];
20429
20430/**
20431 * @ngdoc directive
20432 * @name ngStyle
20433 * @restrict AC
20434 *
20435 * @description
20436 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20437 *
20438 * @element ANY
20439 * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
20440 *      object whose keys are CSS style names and values are corresponding values for those CSS
20441 *      keys.
20442 *
20443 * @example
20444   <example>
20445     <file name="index.html">
20446        <input type="button" value="set" ng-click="myStyle={color:'red'}">
20447        <input type="button" value="clear" ng-click="myStyle={}">
20448        <br/>
20449        <span ng-style="myStyle">Sample Text</span>
20450        <pre>myStyle={{myStyle}}</pre>
20451     </file>
20452     <file name="style.css">
20453       span {
20454         color: black;
20455       }
20456     </file>
20457     <file name="protractor.js" type="protractor">
20458       var colorSpan = element(by.css('span'));
20459
20460       it('should check ng-style', function() {
20461         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20462         element(by.css('input[value=set]')).click();
20463         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
20464         element(by.css('input[value=clear]')).click();
20465         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20466       });
20467     </file>
20468   </example>
20469 */
20470var ngStyleDirective = ngDirective(function(scope, element, attr) {
20471  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
20472    if (oldStyles && (newStyles !== oldStyles)) {
20473      forEach(oldStyles, function(val, style) { element.css(style, '');});
20474    }
20475    if (newStyles) element.css(newStyles);
20476  }, true);
20477});
20478
20479/**
20480 * @ngdoc directive
20481 * @name ngSwitch
20482 * @restrict EA
20483 *
20484 * @description
20485 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
20486 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
20487 * as specified in the template.
20488 *
20489 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
20490 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
20491 * matches the value obtained from the evaluated expression. In other words, you define a container element
20492 * (where you place the directive), place an expression on the **`on="..."` attribute**
20493 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
20494 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
20495 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
20496 * attribute is displayed.
20497 *
20498 * <div class="alert alert-info">
20499 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
20500 * as literal string values to match against.
20501 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
20501omeVal"` not against the
20502 * value of the expression `$scope.someVal`.
20503 * </div>
20504
20505 * @animations
20506 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
20507 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
20508 *
20509 * @usage
20510 * <ANY ng-switch="expression">
20511 *   <ANY ng-switch-when="matchValue1">...</ANY>
20512 *   <ANY ng-switch-when="matchValue2">...</ANY>
20513 *   <ANY ng-switch-default>...</ANY>
20514 * </ANY>
20515 *
20516 *
20517 * @scope
20518 * @priority 800
20519 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
20520 * On child elements add:
20521 *
20522 * * `ngSwitchWhen`: the case statement to match against. If match then this
20523 *   case will be displayed. If the same match appears multiple times, all the
20524 *   elements will be displayed.
20525 * * `ngSwitchDefault`: the default case when no other case match. If there
20526 *   are multiple default cases, all of them will be displayed when no other
20527 *   case match.
20528 *
20529 *
20530 * @example
20531  <example module="ngAnimate" deps="angular-animate.js" animations="true">
20532    <file name="index.html">
20533      <div ng-controller="Ctrl">
20534        <select ng-model="selection" ng-options="item for item in items">
20535        </select>
20536        <tt>selection={{selection}}</tt>
20537        <hr/>
20538        <div class="animate-switch-container"
20539          ng-switch on="selection">
20540            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
20541            <div class="animate-switch" ng-switch-when="home">Home Span</div>
20542            <div class="animate-switch" ng-switch-default>default</div>
20543        </div>
20544      </div>
20545    </file>
20546    <file name="script.js">
20547      function Ctrl($scope) {
20548        $scope.items = ['settings', 'home', 'other'];
20549        $scope.selection = $scope.items[0];
20550      }
20551    </file>
20552    <file name="animations.css">
20553      .animate-switch-container {
20554        position:relative;
20555        background:white;
20556        border:1px solid black;
20557        height:40px;
20558        overflow:hidden;
20559      }
20560
20561      .animate-switch {
20562        padding:10px;
20563      }
20564
20565      .animate-switch.ng-animate {
20566        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20567        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20568
20569        position:absolute;
20570        top:0;
20571        left:0;
20572        right:0;
20573        bottom:0;
20574      }
20575
20576      .animate-switch.ng-leave.ng-leave-active,
20577      .animate-switch.ng-enter {
20578        top:-50px;
20579      }
20580      .animate-switch.ng-leave,
20581      .animate-switch.ng-enter.ng-enter-active {
20582        top:0;
20583      }
20584    </file>
20585    <file name="protractor.js" type="protractor">
20586      var switchElem = element(by.css('[ng-switch]'));
20587      var select = element(by.model('selection'));
20588
20589      it('should start in settings', function() {
20590        expect(switchElem.getText()).toMatch(/Settings Div/);
20591      });
20592      it('should change to home', function() {
20593        select.element.all(by.css('option')).get(1).click();
20594        expect(switchElem.getText()).toMatch(/Home Span/);
20595      });
20596      it('should select default', function() {
20597        select.element.all(by.css('option')).get(2).click();
20598        expect(switchElem.getText()).toMatch(/default/);
20599      });
20600    </file>
20601  </example>
20602 */
20603var ngSwitchDirective = ['$animate', function($animate) {
20604  return {
20605    restrict: 'EA',
20606    require: 'ngSwitch',
20607
20608    // asks for $scope to fool the BC controller module
20609    controller: ['$scope', function ngSwitchController() {
20610     this.cases = {};
20611    }],
20612    link: function(scope, element, attr, ngSwitchController) {
20613      var watchExpr = attr.ngSwitch || attr.on,
20614          selectedTranscludes,
20615          selectedElements,
20616          previousElements,
20617          selectedScopes = [];
20618
20619      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
20620        var i, ii = selectedScopes.length;
20621        if(ii > 0) {
20622          if(previousElements) {
20623            for (i = 0; i < ii; i++) {
20624              previousElements[i].remove();
20625            }
20626            previousElements = null;
20627          }
20628
20629          previousElements = [];
20630          for (i= 0; i<ii; i++) {
20631            var selected = selectedElements[i];
20632            selectedScopes[i].$destroy();
20633            previousElements[i] = selected;
20634            $animate.leave(selected, function() {
20635              previousElements.splice(i, 1);
20636              if(previousElements.length === 0) {
20637                previousElements = null;
20638              }
20639            });
20640          }
20641        }
20642
20643        selectedElements = [];
20644        selectedScopes = [];
20645
20646        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
20647          scope.$eval(attr.change);
20648          forEach(selectedTranscludes, function(selectedTransclude) {
20649            var selectedScope = scope.$new();
20650            selectedScopes.push(selectedScope);
20651            selectedTransclude.transclude(selectedScope, function(caseElement) {
20652              var anchor = selectedTransclude.element;
20653
20654              selectedElements.push(caseElement);
20655              $animate.enter(caseElement, anchor.parent(), anchor);
20656            });
20657          });
20658        }
20659      });
20660    }
20661  };
20662}];
20663
20664var ngSwitchWhenDirective = ngDirective({
20665  transclude: 'element',
20666  priority: 800,
20667  require: '^ngSwitch',
20668  link: function(scope, element, attrs, ctrl, $transclude) {
20669    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
20670    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
20671  }
20672});
20673
20674var ngSwitchDefaultDirective = ngDirective({
20675  transclude: 'element',
20676  priority: 800,
20677  require: '^ngSwitch',
20678  link: function(scope, element, attr, ctrl, $transclude) {
20679    ctrl.cases['?'] = (ctrl.cases['?'] || []);
20680    ctrl.cases['?'].push({ transclude: $transclude, element: element });
20681   }
20682});
20683
20684/**
20685 * @ngdoc directive
20686 * @name ngTransclude
20687 * @restrict AC
20688 *
20689 * @description
20690 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
20691 *
20692 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
20693 *
20694 * @element ANY
20695 *
20696 * @example
20697   <example module="transclude">
20698     <file name="index.html">
20699       <script>
20700         function Ctrl($scope) {
20701           $scope.title = 'Lorem Ipsum';
20702           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
20703         }
20704
20705         angular.module('transclude', [])
20706          .directive('pane', function(){
20707             return {
20708               restrict: 'E',
20709               transclude: true,
20710               scope: { title:'@' },
20711               template: '<div style="border: 1px solid black;">' +
20712                           '<div style="background-color: gray">{{title}}</div>' +
20713                           '<div ng-transclude></div>' +
20714                         '</div>'
20715             };
20716         });
20717       </script>
20718       <div ng-controller="Ctrl">
20719         <input ng-model="title"><br>
20720         <textarea ng-model="text"></textarea> <br/>
20721         <pane title="{{title}}">{{text}}</pane>
20722       </div>
20723     </file>
20724     <file name="protractor.js" type="protractor">
20725        it('should have transcluded', function() {
20726          var titleElement = element(by.model('title'));
20727          titleElement.clear();
20728          titleElement.sendKeys('TITLE');
20729          var textElement = element(by.model('text'));
20730          textElement.clear();
20731          textElement.sendKeys('TEXT');
20732          expect(element(by.binding('title')).getText()).toEqual('TITLE');
20733          expect(element(by.binding('text')).getText()).toEqual('TEXT');
20734        });
20735     </file>
20736   </example>
20737 *
20738 */
20739var ngTranscludeDirective = ngDirective({
20740  link: function($scope, $element, $attrs, controller, $transclude) {
20741    if (!$transclude) {
20742      throw minErr('ngTransclude')('orphan',
20743       'Illegal use of ngTransclude directive in the template! ' +
20744       'No parent directive that requires a transclusion found. ' +
20745       'Element: {0}',
20746       startingTag($element));
20747    }
20748
20749    $transclude(function(clone) {
20750      $element.empty();
20751      $element.append(clone);
20752    });
20753  }
20754});
20755
20756/**
20757 * @ngdoc directive
20758 * @name script
20759 * @restrict E
20760 *
20761 * @description
20762 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
20763 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
20764 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
20765 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
20766 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
20767 *
20768 * @param {string} type Must be set to `'text/ng-template'`.
20769 * @param {string} id Cache name of the template.
20770 *
20771 * @example
20772  <example>
20773    <file name="index.html">
20774      <script type="text/ng-template" id="/tpl.html">
20775        Content of the template.
20776      </script>
20777
20778      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
20779      <div id="tpl-content" ng-include src="currentTpl"></div>
20780    </file>
20781    <file name="protractor.js" type="protractor">
20782      it('should load template defined inside script tag', function() {
20783        element(by.css('#tpl-link')).click();
20784        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
20785      });
20786    </file>
20787  </example>
20788 */
20789var scriptDirective = ['$templateCache', function($templateCache) {
20790  return {
20791    restrict: 'E',
20792    terminal: true,
20793    compile: function(element, attr) {
20794      if (attr.type == 'text/ng-template') {
20795        var templateUrl = attr.id,
20796            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
20797            text = element[0].text;
20798
20799        $templateCache.put(templateUrl, text);
20800      }
20801    }
20802  };
20803}];
20804
20805var ngOptionsMinErr = minErr('ngOptions');
20806/**
20807 * @ngdoc directive
20808 * @name select
20809 * @restrict E
20810 *
20811 * @description
20812 * HTML `SELECT` element with angular data-binding.
20813 *
20814 * # `ngOptions`
20815 *
20816 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
20817 * elements for the `<select>` element using the array or object obtained by evaluating the
20818 * `ngOptions` comprehension_expression.
20819 *
20820 * When an item in the `<select>` menu is selected, the array element or object property
20821 * represented by the selected option will be bound to the model identified by the `ngModel`
20822 * directive.
20823 *
20824 * <div class="alert alert-warning">
20825 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
20826 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
20827 * </div>
20828 *
20829 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
20830 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
20831 * option. See example below for demonstration.
20832 *
20833 * <div class="alert alert-warning">
20834 * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
20835 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
20836 * `select` model to be bound to a non-string value. This is because an option element can only
20837 * be bound to string values at present.
20838 * </div>
20839 *
20840 * @param {string} ngModel Assignable angular expression to data-bind to.
20841 * @param {string=} name Property name of the form under which the control is published.
20842 * @param {string=} required The control is considered valid only if value is entered.
20843 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20844 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20845 *    `required` when you want to data-bind to the `required` attribute.
20846 * @param {comprehension_expression=} ngOptions in one of the following forms:
20847 *
20848 *   * for array data sources:
20849 *     * `label` **`for`** `value` **`in`** `array`
20850 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
20851 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
20852 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
20853 *   * for object data sources:
20854 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20855 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20856 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
20857 *     * `select` **`as`** `label` **`group by`** `group`
20858 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
20859 *
20860 * Where:
20861 *
20862 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
20863 *   * `value`: local variable which will refer to each item in the `array` or each property value
20864 *      of `object` during iteration.
20865 *   * `key`: local variable which will refer to a property name in `object` during iteration.
20866 *   * `label`: The result of this expression will be the label for `<option>` element. The
20867 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
20868 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
20869 *      element. If not specified, `select` expression will default to `value`.
20870 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
20871 *      DOM element.
20872 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
20873 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
20874 *     `value` variable (e.g. `value.propertyName`).
20875 *
20876 * @example
20877    <example>
20878      <file name="index.html">
20879        <script>
20880        function MyCntrl($scope) {
20881          $scope.colors = [
20882            {name:'black', shade:'dark'},
20883            {name:'white', shade:'light'},
20884            {name:'red', shade:'dark'},
20885            {name:'blue', shade:'dark'},
20886            {name:'yellow', shade:'light'}
20887          ];
20888          $scope.color = $scope.colors[2]; // red
20889        }
20890        </script>
20891        <div ng-controller="MyCntrl">
20892          <ul>
20893            <li ng-repeat="color in colors">
20894              Name: <input ng-model="color.name">
20895              [<a href ng-click="colors.splice($index, 1)">X</a>]
20896            </li>
20897            <li>
20898              [<a href ng-click="colors.push({})">add</a>]
20899            </li>
20900          </ul>
20901          <hr/>
20902          Color (null not allowed):
20903          <select ng-model="color" ng-options="c.name for c in colors"></select><br>
20904
20905          Color (null allowed):
20906          <span  class="nullable">
20907            <select ng-model="color" ng-options="c.name for c in colors">
20908              <option value="">-- choose color --</option>
20909            </select>
20910          </span><br/>
20911
20912          Color grouped by shade:
20913          <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
20914          </select><br/>
20915
20916
20917          Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
20918          <hr/>
20919          Currently selected: {{ {selected_color:color}  }}
20920          <div style="border:solid 1px black; height:20px"
20921               ng-style="{'background-color':color.name}">
20922          </div>
20923        </div>
20924      </file>
20925      <file name="protractor.js" type="protractor">
20926         it('should check ng-options', function() {
20927           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
20928           element.all(by.select('color')).first().click();
20929           element.all(by.css('select[ng-model="color"] option')).first().click();
20930           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
20931           element(by.css('.nullable select[ng-model="color"]')).click();
20932           element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
20933           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
20934         });
20935      </file>
20936    </example>
20937 */
20938
20939var ngOptionsDirective = valueFn({ terminal: true });
20940// jshint maxlen: false
20941var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
20942                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
20943  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]+?))?$/,
20944      nullModelCtrl = {$setViewValue: noop};
20945// jshint maxlen: 100
20946
20947  return {
20948    restrict: 'E',
20949    require: ['select', '?ngModel'],
20950    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
20951      var self = this,
20952          optionsMap = {},
20953          ngModelCtrl = nullModelCtrl,
20954          nullOption,
20955          unknownOption;
20956
20957
20958      self.databound = $attrs.ngModel;
20959
20960
20961      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
20962        ngModelCtrl = ngModelCtrl_;
20963        nullOption = nullOption_;
20964        unknownOption = unknownOption_;
20965      };
20966
20967
20968      self.addOption = function(value) {
20969        assertNotHasOwnProperty(value, '"option value"');
20970        optionsMap[value] = true;
20971
20972        if (ngModelCtrl.$viewValue == value) {
20973          $element.val(value);
20974          if (unknownOption.parent()) unknownOption.remove();
20975        }
20976      };
20977
20978
20979      self.removeOption = function(value) {
20980        if (this.hasOption(value)) {
20981          delete optionsMap[value];
20982          if (ngModelCtrl.$viewValue == value) {
20983            this.renderUnknownOption(value);
20984          }
20985        }
20986      };
20987
20988
20989      self.renderUnknownOption = function(val) {
20990        var unknownVal = '? ' + hashKey(val) + ' ?';
20991        unknownOption.val(unknownVal);
20992        $element.prepend(unknownOption);
20993        $element.val(unknownVal);
20994        unknownOption.prop('selected', true); // needed for IE
20995      };
20996
20997
20998      self.hasOption = function(value) {
20999        return optionsMap.hasOwnProperty(value);
21000      };
21001
21002      $scope.$on('$destroy', function() {
21003        // disable unknown option so that we don't do work when the whole select is being destroyed
21004        self.renderUnknownOption = noop;
21005      });
21006    }],
21007
21008    link: function(scope, element, attr, ctrls) {
21009      // if ngModel is not defined, we don't need to do anything
21010      if (!ctrls[1]) return;
21011
21012      var selectCtrl = ctrls[0],
21013          ngModelCtrl = ctrls[1],
21014          multiple = attr.multiple,
21015          optionsExp = attr.ngOptions,
21016          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21017          emptyOption,
21018          // we can't just jqLite('<option>') since jqLite is not smart enough
21019          // to create it in <select> and IE barfs otherwise.
21020          optionTemplate = jqLite(document.createElement('option')),
21021          optGroupTemplate =jqLite(document.createElement('optgroup')),
21022          unknownOption = optionTemplate.clone();
21023
21024      // find "null" option
21025      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21026        if (children[i].value === '') {
21027          emptyOption = nullOption = children.eq(i);
21028          break;
21029        }
21030      }
21031
21032      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21033
21034      // required validator
21035      if (multiple) {
21036        ngModelCtrl.$isEmpty = function(value) {
21037          return !value || value.length === 0;
21038        };
21039      }
21040
21041      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21042      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21043      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21044
21045
21046      ////////////////////////////
21047
21048
21049
21050      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21051        ngModelCtrl.$render = function() {
21052          var viewValue = ngModelCtrl.$viewValue;
21053
21054          if (selectCtrl.hasOption(viewValue)) {
21055            if (unknownOption.parent()) unknownOption.remove();
21056            selectElement.val(viewValue);
21057            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21058          } else {
21059            if (isUndefined(viewValue) && emptyOption) {
21060              selectElement.val('');
21061            } else {
21062              selectCtrl.renderUnknownOption(viewValue);
21063            }
21064          }
21065        };
21066
21067        selectElement.on('change', function() {
21068          scope.$apply(function() {
21069            if (unknownOption.parent()) unknownOption.remove();
21070            ngModelCtrl.$setViewValue(selectElement.val());
21071          });
21072        });
21073      }
21074
21075      function setupAsMultiple(scope, selectElement, ctrl) {
21076        var lastView;
21077        ctrl.$render = function() {
21078          var items = new HashMap(ctrl.$viewValue);
21079          forEach(selectElement.find('option'), function(option) {
21080            option.selected = isDefined(items.get(option.value));
21081          });
21082        };
21083
21084        // we have to do it on each watch since ngModel watches reference, but
21085        // we need to work of an array, so we need to see if anything was inserted/removed
21086        scope.$watch(function selectMultipleWatch() {
21087          if (!equals(lastView, ctrl.$viewValue)) {
21088            lastView = copy(ctrl.$viewValue);
21089            ctrl.$render();
21090          }
21091        });
21092
21093        selectElement.on('change', function() {
21094          scope.$apply(function() {
21095            var array = [];
21096            forEach(selectElement.find('option'), function(option) {
21097              if (option.selected) {
21098                array.push(option.value);
21099              }
21100            });
21101            ctrl.$setViewValue(array);
21102          });
21103        });
21104      }
21105
21106      function setupAsOptions(scope, selectElement, ctrl) {
21107        var match;
21108
21109        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21110          throw ngOptionsMinErr('iexp',
21111            "Expected expression in form of " +
21112            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21113            " but got '{0}'. Element: {1}",
21114            optionsExp, startingTag(selectElement));
21115        }
21116
21117        var displayFn = $parse(match[2] || match[1]),
21118            valueName = match[4] || match[6],
21119            keyName = match[5],
21120            groupByFn = $parse(match[3] || ''),
21121            valueFn = $parse(match[2] ? match[1] : valueName),
21122            valuesFn = $parse(match[7]),
21123            track = match[8],
21124            trackFn = track ? $parse(match[8]) : null,
21125            // This is an array of array of existing option groups in DOM.
21126            // We try to reuse these if possible
21127            // - optionGroupsCache[0] is the options with no option group
21128            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21129            optionGroupsCache = [[{element: selectElement, label:''}]];
21130
21131        if (nullOption) {
21132          // compile the element since there might be bindings in it
21133          $compile(nullOption)(scope);
21134
21135          // remove the class, which is added automatically because we recompile the element and it
21136          // becomes the compilation root
21137          nullOption.removeClass('ng-scope');
21138
21139          // we need to remove it before calling selectElement.empty() because otherwise IE will
21140          // remove the label from the element. wtf?
21141          nullOption.remove();
21142        }
21143
21144        // clear contents, we'll add what's needed based on the model
21145        selectElement.empty();
21146
21147        selectElement.on('change', function() {
21148          scope.$apply(function() {
21149            var optionGroup,
21150                collection = valuesFn(scope) || [],
21151                locals = {},
21152                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21153
21154            if (multiple) {
21155              value = [];
21156              for (groupIndex = 0, groupLength = optionGroupsCache.length;
21157                   groupIndex < groupLength;
21158                   groupIndex++) {
21159                // list of options for that group. (first item has the parent)
21160                optionGroup = optionGroupsCache[groupIndex];
21161
21162                for(index = 1, length = optionGroup.length; index < length; index++) {
21163                  if ((optionElement = optionGroup[index].element)[0].selected) {
21164                    key = optionElement.val();
21165                    if (keyName) locals[keyName] = key;
21166                    if (trackFn) {
21167                      for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21168                        locals[valueName] = collection[trackIndex];
21169                        if (trackFn(scope, locals) == key) break;
21170                      }
21171                    } else {
21172                      locals[valueName] = collection[key];
21173                    }
21174                    value.push(valueFn(scope, locals));
21175                  }
21176                }
21177              }
21178            } else {
21179              key = selectElement.val();
21180              if (key == '?') {
21181                value = undefined;
21182              } else if (key === ''){
21183                value = null;
21184              } else {
21185                if (trackFn) {
21186                  for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21187                    locals[valueName] = collection[trackIndex];
21188                    if (trackFn(scope, locals) == key) {
21189                      value = valueFn(scope, locals);
21190                      break;
21191                    }
21192                  }
21193                } else {
21194                  locals[valueName] = collection[key];
21195                  if (keyName) locals[keyName] = key;
21196                  value = valueFn(scope, locals);
21197                }
21198              }
21199              // Update the null option's selected property here so $render cleans it up correctly
21200              if (optionGroupsCache[0].length > 1) {
21201                if (optionGroupsCache[0][1].id !== key) {
21202                  optionGroupsCache[0][1].selected = false;
21203                }
21204              }
21205            }
21206            ctrl.$setViewValue(value);
21207          });
21208        });
21209
21210        ctrl.$render = render;
21211
21212        // TODO(vojta): can't we optimize this ?
21213        scope.$watch(render);
21214
21215        function render() {
21216              // Temporary location for the option groups before we render them
21217          var optionGroups = {'':[]},
21218              optionGroupNames = [''],
21219              optionGroupName,
21220              optionGroup,
21221              option,
21222              existingParent, existingOptions, existingOption,
21223              modelValue = ctrl.$modelValue,
21224              values = valuesFn(scope) || [],
21225              keys = keyName ? sortedKeys(values) : values,
21226              key,
21227              groupLength, length,
21228              groupIndex, index,
21229              locals = {},
21230              selected,
21231              selectedSet = false, // nothing is selected yet
21232              lastElement,
21233              element,
21234              label;
21235
21236          if (multiple) {
21237            if (trackFn && isArray(modelValue)) {
21238              selectedSet = new HashMap([]);
21239              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21240                locals[valueName] = modelValue[trackIndex];
21241                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21242              }
21243            } else {
21244              selectedSet = new HashMap(modelValue);
21245            }
21246          }
21247
21248          // We now build up the list of options we need (we merge later)
21249          for (index = 0; length = keys.length, index < length; index++) {
21250
21251            key = index;
21252            if (keyName) {
21253              key = keys[index];
21254              if ( key.charAt(0) === '$' ) continue;
21255              locals[keyName] = key;
21256            }
21257
21258            locals[valueName] = values[key];
21259
21260            optionGroupName = groupByFn(scope, locals) || '';
21261            if (!(optionGroup = optionGroups[optionGroupName])) {
21262              optionGroup = optionGroups[optionGroupName] = [];
21263              optionGroupNames.push(optionGroupName);
21264            }
21265            if (multiple) {
21266              selected = isDefined(
21267                selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21268              );
21269            } else {
21270              if (trackFn) {
21271                var modelCast = {};
21272                modelCast[valueName] = modelValue;
21273                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21274              } else {
21275                selected = modelValue === valueFn(scope, locals);
21276              }
21277              selectedSet = selectedSet || selected; // see if at least one item is selected
21278            }
21279            label = displayFn(scope, locals); // what will be seen by the user
21280
21281            // doing displayFn(scope, locals) || '' overwrites zero values
21282            label = isDefined(label) ? label : '';
21283            optionGroup.push({
21284              // either the index into array or key from object
21285              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
21286              label: label,
21287              selected: selected                   // determine if we should be selected
21288            });
21289          }
21290          if (!multiple) {
21291            if (nullOption || modelValue === null) {
21292              // insert null option if we have a placeholder, or the model is null
21293              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
21294            } else if (!selectedSet) {
21295              // option could not be found, we have to insert the undefined item
21296              optionGroups[''].unshift({id:'?', label:'', selected:true});
21297            }
21298          }
21299
21300          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
21301          for (groupIndex = 0, groupLength = optionGroupNames.length;
21302               groupIndex < groupLength;
21303               groupIndex++) {
21304            // current option group name or '' if no group
21305            optionGroupName = optionGroupNames[groupIndex];
21306
21307            // list of options for that group. (first item has the parent)
21308            optionGroup = optionGroups[optionGroupName];
21309
21310            if (optionGroupsCache.length <= groupIndex) {
21311              // we need to grow the optionGroups
21312              existingParent = {
21313                element: optGroupTemplate.clone().attr('label', optionGroupName),
21314                label: optionGroup.label
21315              };
21316              existingOptions = [existingParent];
21317              optionGroupsCache.push(existingOptions);
21318              selectElement.append(existingParent.element);
21319            } else {
21320              existingOptions = optionGroupsCache[groupIndex];
21321              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
21322
21323              // update the OPTGROUP label if not the same.
21324              if (existingParent.label != optionGroupName) {
21325                existingParent.element.attr('label', existingParent.label = optionGroupName);
21326              }
21327            }
21328
21329            lastElement = null;  // start at the beginning
21330            for(index = 0, length = optionGroup.length; index < length; index++) {
21331              option = optionGroup[index];
21332              if ((existingOption = existingOptions[index+1])) {
21333                // reuse elements
21334                lastElement = existingOption.element;
21335                if (existingOption.label !== option.label) {
21336                  lastElement.text(existingOption.label = option.label);
21337                }
21338                if (existingOption.id !== option.id) {
21339                  lastElement.val(existingOption.id = option.id);
21340                }
21341                // lastElement.prop('selected') provided by jQuery has side-effects
21342                if (existingOption.selected !== option.selected) {
21343                  lastElement.prop('selected', (existingOption.selected = option.selected));
21344                }
21345              } else {
21346                // grow elements
21347
21348                // if it's a null option
21349                if (option.id === '' && nullOption) {
21350                  // put back the pre-compiled element
21351                  element = nullOption;
21352                } else {
21353                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
21354                  // in this version of jQuery on some browser the .text() returns a string
21355                  // rather then the element.
21356                  (element = optionTemplate.clone())
21357                      .val(option.id)
21358                      .attr('selected', option.selected)
21359                      .text(option.label);
21360                }
21361
21362                existingOptions.push(existingOption = {
21363                    element: element,
21364                    label: option.label,
21365                    id: option.id,
21366                    selected: option.selected
21367                });
21368                if (lastElement) {
21369                  lastElement.after(element);
21370                } else {
21371                  existingParent.element.append(element);
21372                }
21373                lastElement = element;
21374              }
21375            }
21376            // remove any excessive OPTIONs in a group
21377            index++; // increment since the existingOptions[0] is parent element not OPTION
21378            while(existingOptions.length > index) {
21379              existingOptions.pop().element.remove();
21380            }
21381          }
21382          // remove any excessive OPTGROUPs from select
21383          while(optionGroupsCache.length > groupIndex) {
21384            optionGroupsCache.pop()[0].element.remove();
21385          }
21386        }
21387      }
21388    }
21389  };
21390}];
21391
21392var optionDirective = ['$interpolate', function($interpolate) {
21393  var nullSelectCtrl = {
21394    addOption: noop,
21395    removeOption: noop
21396  };
21397
21398  return {
21399    restrict: 'E',
21400    priority: 100,
21401    compile: function(element, attr) {
21402      if (isUndefined(attr.value)) {
21403        var interpolateFn = $interpolate(element.text(), true);
21404        if (!interpolateFn) {
21405          attr.$set('value', element.text());
21406        }
21407      }
21408
21409      return function (scope, element, attr) {
21410        var selectCtrlName = '$selectController',
21411            parent = element.parent(),
21412            selectCtrl = parent.data(selectCtrlName) ||
21413              parent.parent().data(selectCtrlName); // in case we are in optgroup
21414
21415        if (selectCtrl && selectCtrl.databound) {
21416          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
21417          // We don't want the view to drive the initialization of the model anyway.
21418          element.prop('selected', false);
21419        } else {
21420          selectCtrl = nullSelectCtrl;
21421        }
21422
21423        if (interpolateFn) {
21424          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
21425            attr.$set('value', newVal);
21426            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
21427            selectCtrl.addOption(newVal);
21428          });
21429        } else {
21430          selectCtrl.addOption(attr.value);
21431        }
21432
21433        element.on('$destroy', function() {
21434          selectCtrl.removeOption(attr.value);
21435        });
21436      };
21437    }
21438  };
21439}];
21440
21441var styleDirective = valueFn({
21442  restrict: 'E',
21443  terminal: true
21444});
21445
21446  if (window.angular.bootstrap) {
21447    //AngularJS is already loaded, so we can return here...
21448    console.log('WARNING: Tried to load angular more than once.');
21449    return;
21450  }
21451
21452  //try to bind to jquery now so that one can write angular.element().read()
21453  //but we will rebind on bootstrap again.
21454  bindJQuery();
21455
21456  publishExternalAPI(angular);
21457
21458  jqLite(document).ready(function() {
21459    angularInit(document, bootstrap);
21460  });
21461
21462})(window, document);
21463
21464!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.