PageSourceSearch

https://borroweraccess.ecmc.org/ba2/resources/javascript/angular.js

js ecmc.org collected 2026-10-01 12:27:38 UTC 952,626 bytes, 26,130 lines download raw bytes

1/**
2 * @license AngularJS v1.3.12
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 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
34 *   error from returned function, for cases when a particular type of error is useful.
35 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
36 */
37
38function minErr(module, ErrorConstructor) {
39  ErrorConstructor = ErrorConstructor || Error;
40  return function() {
41    var code = arguments[0],
42      prefix = '[' + (module ? module + ':' : '') + code + '] ',
43      template = arguments[1],
44      templateArgs = arguments,
45
46      message, i;
47
48    message = prefix + template.replace(/\{\d+\}/g, function(match) {
49      var index = +match.slice(1, -1), arg;
50
51      if (index + 2 < templateArgs.length) {
52        return toDebugString(templateArgs[index + 2]);
53      }
54      return match;
55    });
56
57    message = message + '\nhttp://errors.angularjs.org/1.3.12/' +
58      (module ? module + '/' : '') + code;
59    for (i = 2; i < arguments.length; i++) {
60      message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
61        encodeURIComponent(toDebugString(arguments[i]));
62    }
63    return new ErrorConstructor(message);
64  };
65}
66
67/* We need to tell jshint what variables are being exported */
68/* global angular: true,
69  msie: true,
70  jqLite: true,
71  jQuery: true,
72  slice: true,
73  splice: true,
74  push: true,
75  toString: true,
76  ngMinErr: true,
77  angularModule: true,
78  uid: true,
79  REGEX_STRING_REGEXP: true,
80  VALIDITY_STATE_PROPERTY: true,
81
82  lowercase: true,
83  uppercase: true,
84  manualLowercase: true,
85  manualUppercase: true,
86  nodeName_: true,
87  isArrayLike: true,
88  forEach: true,
89  sortedKeys: true,
90  forEachSorted: true,
91  reverseParams: true,
92  nextUid: true,
93  setHashKey: true,
94  extend: true,
95  int: true,
96  inherit: true,
97  noop: true,
98  identity: true,
99  valueFn: true,
100  isUndefined: true,
101  isDefined: true,
102  isObject: true,
103  isString: true,
104  isNumber: true,
105  isDate: true,
106  isArray: true,
107  isFunction: true,
108  isRegExp: true,
109  isWindow: true,
110  isScope: true,
111  isFile: true,
112  isFormData: true,
113  isBlob: true,
114  isBoolean: true,
115  isPromiseLike: true,
116  trim: true,
117  escapeForRegexp: true,
118  isElement: true,
119  makeMap: true,
120  includes: true,
121  arrayRemove: true,
122  copy: true,
123  shallowCopy: true,
124  equals: true,
125  csp: true,
126  concat: true,
127  sliceArgs: true,
128  bind: true,
129  toJsonReplacer: true,
130  toJson: true,
131  fromJson: true,
132  startingTag: true,
133  tryDecodeURIComponent: true,
134  parseKeyValue: true,
135  toKeyValue: true,
136  encodeUriSegment: true,
137  encodeUriQuery: true,
138  angularInit: true,
139  bootstrap: true,
140  getTestability: true,
141  snake_case: true,
142  bindJQuery: true,
143  assertArg: true,
144  assertArgFn: true,
145  assertNotHasOwnProperty: true,
146  getter: true,
147  getBlockNodes: true,
148  hasOwnProperty: true,
149  createMap: true,
150
151  NODE_TYPE_ELEMENT: true,
152  NODE_TYPE_TEXT: true,
153  NODE_TYPE_COMMENT: true,
154  NODE_TYPE_DOCUMENT: true,
155  NODE_TYPE_DOCUMENT_FRAGMENT: true,
156*/
157
158////////////////////////////////////
159
160/**
161 * @ngdoc module
162 * @name ng
163 * @module ng
164 * @description
165 *
166 * # ng (core module)
167 * The ng module is loaded by default when an AngularJS application is started. The module itself
168 * contains the essential components for an AngularJS application to function. The table below
169 * lists a high level breakdown of each of the services/factories, filters, directives and testing
170 * components available within this core module.
171 *
172 * <div doc-module-components="ng"></div>
173 */
174
175var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
176
177// The name of a form control's ValidityState property.
178// This is used so that it's possible for internal tests to create mock ValidityStates.
179var VALIDITY_STATE_PROPERTY = 'validity';
180
181/**
182 * @ngdoc function
183 * @name angular.lowercase
184 * @module ng
185 * @kind function
186 *
187 * @description Converts the specified string to lowercase.
188 * @param {string} string String to be converted to lowercase.
189 * @returns {string} Lowercased string.
190 */
191var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
192var hasOwnProperty = Object.prototype.hasOwnProperty;
193
194/**
195 * @ngdoc function
196 * @name angular.uppercase
197 * @module ng
198 * @kind function
199 *
200 * @description Converts the specified string to uppercase.
201 * @param {string} string String to be converted to uppercase.
202 * @returns {string} Uppercased string.
203 */
204var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
205
206
207var manualLowercase = function(s) {
208  /* jshint bitwise: false */
209  return isString(s)
210      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
211      : s;
212};
213var manualUppercase = function(s) {
214  /* jshint bitwise: false */
215  return isString(s)
216      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
217      : s;
218};
219
220
221// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
222// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
223// with correct but slower alternatives.
224if ('i' !== 'I'.toLowerCase()) {
225  lowercase = manualLowercase;
226  uppercase = manualUppercase;
227}
228
229
230var
231    msie,             // holds major version number for IE, or NaN if UA is not IE.
232    jqLite,           // delay binding since jQuery could be loaded after us.
233    jQuery,           // delay binding
234    slice             = [].slice,
235    splice            = [].splice,
236    push              = [].push,
237    toString          = Object.prototype.toString,
238    ngMinErr          = minErr('ng'),
239
240    /** @name angular */
241    angular           = window.angular || (window.angular = {}),
242    angularModule,
243    uid               = 0;
244
245/**
246 * documentMode is an IE-only property
247 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
248 */
249msie = document.documentMode;
250
251
252/**
253 * @private
254 * @param {*} obj
255 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
256 *                   String ...)
257 */
258function isArrayLike(obj) {
259  if (obj == null || isWindow(obj)) {
260    return false;
261  }
262
263  var length = obj.length;
264
265  if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
266    return true;
267  }
268
269  return isString(obj) || isArray(obj) || length === 0 ||
270         typeof length === 'number' && length > 0 && (length - 1) in obj;
271}
272
273/**
274 * @ngdoc function
275 * @name angular.forEach
276 * @module ng
277 * @kind function
278 *
279 * @description
280 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
281 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
282 * is the value of an object property or an array element, `key` is the object property key or
283 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
284 *
285 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
286 * using the `hasOwnProperty` method.
287 *
288 * Unlike ES262's
289 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
290 * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
291 * return the value provided.
292 *
293   ```js
294     var values = {name: 'misko', gender: 'male'};
295     var log = [];
296     angular.forEach(values, function(value, key) {
297       this.push(key + ': ' + value);
298     }, log);
299     expect(log).toEqual(['name: misko', 'gender: male']);
300   ```
301 *
302 * @param {Object|Array} obj Object to iterate over.
303 * @param {Function} iterator Iterator function.
304 * @param {Object=} context Object to become context (`this`) for the iterator function.
305 * @returns {Object|Array} Reference to `obj`.
306 */
307
308function forEach(obj, iterator, context) {
309  var key, length;
310  if (obj) {
311    if (isFunction(obj)) {
312      for (key in obj) {
313        // Need to check if hasOwnProperty exists,
314        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
315        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
316          iterator.call(context, obj[key], key, obj);
317        }
318      }
319    } else if (isArray(obj) || isArrayLike(obj)) {
320      var isPrimitive = typeof obj !== 'object';
321      for (key = 0, length = obj.length; key < length; key++) {
322        if (isPrimitive || key in obj) {
323          iterator.call(context, obj[key], key, obj);
324        }
325      }
326    }
vendor: 8,671 bytes, lines 326-720
326 else if (obj.forEach && obj.forEach !== forEach) {
327        obj.forEach(iterator, context, obj);
328    } else {
329      for (key in obj) {
330        if (obj.hasOwnProperty(key)) {
331          iterator.call(context, obj[key], key, obj);
332        }
333      }
334    }
335  }
336  return obj;
337}
338
339function sortedKeys(obj) {
340  return Object.keys(obj).sort();
341}
342
343function forEachSorted(obj, iterator, context) {
344  var keys = sortedKeys(obj);
345  for (var i = 0; i < keys.length; i++) {
346    iterator.call(context, obj[keys[i]], keys[i]);
347  }
348  return keys;
349}
350
351
352/**
353 * when using forEach the params are value, key, but it is often useful to have key, value.
354 * @param {function(string, *)} iteratorFn
355 * @returns {function(*, string)}
356 */
357function reverseParams(iteratorFn) {
358  return function(value, key) { iteratorFn(key, value); };
359}
360
361/**
362 * A consistent way of creating unique IDs in angular.
363 *
364 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
365 * we hit number precision issues in JavaScript.
366 *
367 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
368 *
369 * @returns {number} an unique alpha-numeric string
370 */
371function nextUid() {
372  return ++uid;
373}
374
375
376/**
377 * Set or clear the hashkey for an object.
378 * @param obj object
379 * @param h the hashkey (!truthy to delete the hashkey)
380 */
381function setHashKey(obj, h) {
382  if (h) {
383    obj.$$hashKey = h;
384  } else {
385    delete obj.$$hashKey;
386  }
387}
388
389/**
390 * @ngdoc function
391 * @name angular.extend
392 * @module ng
393 * @kind function
394 *
395 * @description
396 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
397 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
398 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
399 * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
400 *
401 * @param {Object} dst Destination object.
402 * @param {...Object} src Source object(s).
403 * @returns {Object} Reference to `dst`.
404 */
405function extend(dst) {
406  var h = dst.$$hashKey;
407
408  for (var i = 1, ii = arguments.length; i < ii; i++) {
409    var obj = arguments[i];
410    if (obj) {
411      var keys = Object.keys(obj);
412      for (var j = 0, jj = keys.length; j < jj; j++) {
413        var key = keys[j];
414        dst[key] = obj[key];
415      }
416    }
417  }
418
419  setHashKey(dst, h);
420  return dst;
421}
422
423function int(str) {
424  return parseInt(str, 10);
425}
426
427
428function inherit(parent, extra) {
429  return extend(Object.create(parent), extra);
430}
431
432/**
433 * @ngdoc function
434 * @name angular.noop
435 * @module ng
436 * @kind function
437 *
438 * @description
439 * A function that performs no operations. This function can be useful when writing code in the
440 * functional style.
441   ```js
442     function foo(callback) {
443       var result = calculateResult();
444       (callback || angular.noop)(result);
445     }
446   ```
447 */
448function noop() {}
449noop.$inject = [];
450
451
452/**
453 * @ngdoc function
454 * @name angular.identity
455 * @module ng
456 * @kind function
457 *
458 * @description
459 * A function that returns its first argument. This function is useful when writing code in the
460 * functional style.
461 *
462   ```js
463     function transformer(transformationFn, value) {
464       return (transformationFn || angular.identity)(value);
465     };
466   ```
467  * @param {*} value to be returned.
468  * @returns {*} the value passed in.
469 */
470function identity($) {return $;}
471identity.$inject = [];
472
473
474function valueFn(value) {return function() {return value;};}
475
476/**
477 * @ngdoc function
478 * @name angular.isUndefined
479 * @module ng
480 * @kind function
481 *
482 * @description
483 * Determines if a reference is undefined.
484 *
485 * @param {*} value Reference to check.
486 * @returns {boolean} True if `value` is undefined.
487 */
488function isUndefined(value) {return typeof value === 'undefined';}
489
490
491/**
492 * @ngdoc function
493 * @name angular.isDefined
494 * @module ng
495 * @kind function
496 *
497 * @description
498 * Determines if a reference is defined.
499 *
500 * @param {*} value Reference to check.
501 * @returns {boolean} True if `value` is defined.
502 */
503function isDefined(value) {return typeof value !== 'undefined';}
504
505
506/**
507 * @ngdoc function
508 * @name angular.isObject
509 * @module ng
510 * @kind function
511 *
512 * @description
513 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
514 * considered to be objects. Note that JavaScript arrays are objects.
515 *
516 * @param {*} value Reference to check.
517 * @returns {boolean} True if `value` is an `Object` but not `null`.
518 */
519function isObject(value) {
520  // http://jsperf.com/isobject4
521  return value !== null && typeof value === 'object';
522}
523
524
525/**
526 * @ngdoc function
527 * @name angular.isString
528 * @module ng
529 * @kind function
530 *
531 * @description
532 * Determines if a reference is a `String`.
533 *
534 * @param {*} value Reference to check.
535 * @returns {boolean} True if `value` is a `String`.
536 */
537function isString(value) {return typeof value === 'string';}
538
539
540/**
541 * @ngdoc function
542 * @name angular.isNumber
543 * @module ng
544 * @kind function
545 *
546 * @description
547 * Determines if a reference is a `Number`.
548 *
549 * @param {*} value Reference to check.
550 * @returns {boolean} True if `value` is a `Number`.
551 */
552function isNumber(value) {return typeof value === 'number';}
553
554
555/**
556 * @ngdoc function
557 * @name angular.isDate
558 * @module ng
559 * @kind function
560 *
561 * @description
562 * Determines if a value is a date.
563 *
564 * @param {*} value Reference to check.
565 * @returns {boolean} True if `value` is a `Date`.
566 */
567function isDate(value) {
568  return toString.call(value) === '[object Date]';
569}
570
571
572/**
573 * @ngdoc function
574 * @name angular.isArray
575 * @module ng
576 * @kind function
577 *
578 * @description
579 * Determines if a reference is an `Array`.
580 *
581 * @param {*} value Reference to check.
582 * @returns {boolean} True if `value` is an `Array`.
583 */
584var isArray = Array.isArray;
585
586/**
587 * @ngdoc function
588 * @name angular.isFunction
589 * @module ng
590 * @kind function
591 *
592 * @description
593 * Determines if a reference is a `Function`.
594 *
595 * @param {*} value Reference to check.
596 * @returns {boolean} True if `value` is a `Function`.
597 */
598function isFunction(value) {return typeof value === 'function';}
599
600
601/**
602 * Determines if a value is a regular expression object.
603 *
604 * @private
605 * @param {*} value Reference to check.
606 * @returns {boolean} True if `value` is a `RegExp`.
607 */
608function isRegExp(value) {
609  return toString.call(value) === '[object RegExp]';
610}
611
612
613/**
614 * Checks if `obj` is a window object.
615 *
616 * @private
617 * @param {*} obj Object to check
618 * @returns {boolean} True if `obj` is a window obj.
619 */
620function isWindow(obj) {
621  return obj && obj.window === obj;
622}
623
624
625function isScope(obj) {
626  return obj && obj.$evalAsync && obj.$watch;
627}
628
629
630function isFile(obj) {
631  return toString.call(obj) === '[object File]';
632}
633
634
635function isFormData(obj) {
636  return toString.call(obj) === '[object FormData]';
637}
638
639
640function isBlob(obj) {
641  return toString.call(obj) === '[object Blob]';
642}
643
644
645function isBoolean(value) {
646  return typeof value === 'boolean';
647}
648
649
650function isPromiseLike(obj) {
651  return obj && isFunction(obj.then);
652}
653
654
655var trim = function(value) {
656  return isString(value) ? value.trim() : value;
657};
658
659// Copied from:
660// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
661// Prereq: s is a string.
662var escapeForRegexp = function(s) {
663  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
664           replace(/\x08/g, '\\x08');
665};
666
667
668/**
669 * @ngdoc function
670 * @name angular.isElement
671 * @module ng
672 * @kind function
673 *
674 * @description
675 * Determines if a reference is a DOM element (or wrapped jQuery element).
676 *
677 * @param {*} value Reference to check.
678 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
679 */
680function isElement(node) {
681  return !!(node &&
682    (node.nodeName  // we are a direct element
683    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
684}
685
686/**
687 * @param str 'key1,key2,...'
688 * @returns {object} in the form of {key1:true, key2:true, ...}
689 */
690function makeMap(str) {
691  var obj = {}, items = str.split(","), i;
692  for (i = 0; i < items.length; i++)
693    obj[items[i]] = true;
694  return obj;
695}
696
697
698function nodeName_(element) {
699  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
700}
701
702function includes(array, obj) {
703  return Array.prototype.indexOf.call(array, obj) != -1;
704}
705
706function arrayRemove(array, value) {
707  var index = array.indexOf(value);
708  if (index >= 0)
709    array.splice(index, 1);
710  return value;
711}
712
713/**
714 * @ngdoc function
715 * @name angular.copy
716 * @module ng
717 * @kind function
718 *
719 * @description
720 * Creates a deep copy of `source`, which should be an object or an array.
721 *
722 * * If no destination is supplied, a copy of the object or array is created.
723 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
724 *   are deleted and then all elements/properties from the source are copied to it.
725 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
726 * * If `source` is identical to 'destination' an exception will be thrown.
727 *
728 * @param {*} source The source that will be used to make a copy.
729 *                   Can be any type, including primitives, `null`, and `undefined`.
730 * @param {(Object|Array)=} destination Destination into which the source is copied. If
731 *     provided, must be of the same type as `source`.
732 * @returns {*} The copy or updated `destination`, if `destination` was specified.
733 *
734 * @example
735 <example module="copyExample">
736 <file name="index.html">
737 <div ng-controller="ExampleController">
738 <form novalidate class="simple-form">
739 Name: <input type="text" ng-model="user.name" /><br />
740 E-mail: <input type="email" ng-model="user.email" /><br />
741 Gender: <input type="radio" ng-model="user.gender" value="male" />male
742 <input type="radio" ng-model="user.gender" value="female" />female<br />
743 <button ng-click="reset()">RESET</button>
744 <button ng-click="update(user)">SAVE</button>
745 </form>
746 <pre>form = {{user | json}}</pre>
747 <pre>master = {{master | json}}</pre>
748 </div>
749
750 <script>
751  angular.module('copyExample', [])
752    .controller('ExampleController', ['$scope', function($scope) {
753      $scope.master= {};
754
755      $scope.update = function(user) {
756        // Example with 1 argument
757        $scope.master= angular.copy(user);
758      };
759
760      $scope.reset = function() {
761        // Example with 2 arguments
762        angular.copy($scope.master, $scope.user);
763      };
764
765      $scope.reset();
766    }]);
767 </script>
768 </file>
769 </example>
770 */
771function copy(source, destination, stackSource, stackDest) {
772  if (isWindow(source) || isScope(source)) {
773    throw ngMinErr('cpws',
774      "Can't copy! Making copies of Window or Scope instances is not supported.");
775  }
776
777  if (!destination) {
778    destination = source;
779    if (source) {
780      if (isArray(source)) {
781        destination = copy(source, [], stackSource, stackDest);
782      } else if (isDate(source)) {
783        destination = new Date(source.getTime());
784      } else if (isRegExp(source)) {
785        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
786        destination.lastIndex = source.lastIndex;
787      } else if (isObject(source)) {
788        var emptyObject = Object.create(Object.getPrototypeOf(source));
789        destination = copy(source, emptyObject, stackSource, stackDest);
790      }
791    }
792  } else {
793    if (source === destination) throw ngMinErr('cpi',
794      "Can't copy! Source and destination are identical.");
795
796    stackSource = stackSource || [];
797    stackDest = stackDest || [];
798
799    if (isObject(source)) {
800      var index = stackSource.indexOf(source);
801      if (index !== -1) return stackDest[index];
802
803      stackSource.push(source);
804      stackDest.push(destination);
805    }
806
807    var result;
808    if (isArray(source)) {
809      destination.length = 0;
810      for (var i = 0; i < source.length; i++) {
811        result = copy(source[i], null, stackSource, stackDest);
812        if (isObject(source[i])) {
813          stackSource.push(source[i]);
814          stackDest.push(result);
815        }
816        destination.push(result);
817      }
818    } else {
819      var h = destination.$$hashKey;
820      if (isArray(destination)) {
821        destination.length = 0;
822      } else {
823        forEach(destination, function(value, key) {
824          delete destination[key];
825        });
826      }
827      for (var key in source) {
828        if (source.hasOwnProperty(key)) {
829          result = copy(source[key], null, stackSource, stackDest);
830          if (isObject(source[key])) {
831            stackSource.push(source[key]);
832            stackDest.push(result);
833          }
834          destination[key] = result;
835        }
836      }
837      setHashKey(destination,h);
838    }
839
840  }
841  return destination;
842}
843
844/**
845 * Creates a shallow copy of an object, an array or a primitive.
846 *
847 * Assumes that there are no proto properties for objects.
848 */
849function shallowCopy(src, dst) {
850  if (isArray(src)) {
851    dst = dst || [];
852
853    for (var i = 0, ii = src.length; i < ii; i++) {
854      dst[i] = src[i];
855    }
856  } else if (isObject(src)) {
857    dst = dst || {};
858
859    for (var key in src) {
860      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
861        dst[key] = src[key];
862      }
863    }
864  }
865
866  return dst || src;
867}
868
869
870/**
871 * @ngdoc function
872 * @name angular.equals
873 * @module ng
874 * @kind function
875 *
876 * @description
877 * Determines if two objects or two values are equivalent. Supports value types, regular
878 * expressions, arrays and objects.
879 *
880 * Two objects or values are considered equivalent if at least one of the following is true:
881 *
882 * * Both objects or values pass `===` comparison.
883 * * Both objects or values are of the same type and all of their properties are equal by
884 *   comparing them with `angular.equals`.
885 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
886 * * Both values represent the same regular expression (In JavaScript,
887 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
888 *   representation matches).
889 *
890 * During a property comparison, properties of `function` type and properties with names
891 * that begin with `$` are ignored.
892 *
893 * Scope and DOMWindow objects are being compared only by identify (`===`).
894 *
895 * @param {*} o1 Object or value to compare.
896 * @param {*} o2 Object or value to compare.
897 * @returns {boolean} True if arguments are equal.
898 */
899function equals(o1, o2) {
900  if (o1 === o2) return true;
901  if (o1 === null || o2 === null) return false;
902  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
903  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
904  if (t1 == t2) {
905    if (t1 == 'object') {
906      if (isArray(o1)) {
907        if (!isArray(o2)) return false;
908        if ((length = o1.length) == o2.length) {
909          for (key = 0; key < length; key++) {
910            if (!equals(o1[key], o2[key])) return false;
911          }
912          return true;
913        }
914      } else if (isDate(o1)) {
915        if (!isDate(o2)) return false;
916        return equals(o1.getTime(), o2.getTime());
917      } else if (isRegExp(o1) && isRegExp(o2)) {
918        return o1.toString() == o2.toString();
919      } else {
920        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
921        keySet = {};
922        for (key in o1) {
923          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
924          if (!equals(o1[key], o2[key])) return false;
925          keySet[key] = true;
926        }
927        for (key in o2) {
928          if (!keySet.hasOwnProperty(key) &&
929              key.charAt(0) !== '$' &&
930              o2[key] !== undefined &&
931              !isFunction(o2[key])) return false;
932        }
933        return true;
934      }
935    }
936  }
937  return false;
938}
939
940var csp = function() {
941  if (isDefined(csp.isActive_)) return csp.isActive_;
942
943  var active = !!(document.querySelector('[ng-csp]') ||
944                  document.querySelector('[data-ng-csp]'));
945
946  if (!active) {
947    try {
948      /* jshint -W031, -W054 */
949      new Function('');
950      /* jshint +W031, +W054 */
951    } catch (e) {
952      active = true;
953    }
954  }
955
956  return (csp.isActive_ = active);
957};
958
959
960
961function concat(array1, array2, index) {
962  return array1.concat(slice.call(array2, index));
963}
964
965function sliceArgs(args, startIndex) {
966  return slice.call(args, startIndex || 0);
967}
968
969
970/* jshint -W101 */
971/**
972 * @ngdoc function
973 * @name angular.bind
974 * @module ng
975 * @kind function
976 *
977 * @description
978 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
979 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
980 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
981 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
982 *
983 * @param {Object} self Context which `fn` should be evaluated in.
984 * @param {function()} fn Function to be bound.
985 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
986 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
987 */
988/* jshint +W101 */
989function bind(self, fn) {
990  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
991  if (isFunction(fn) && !(fn instanceof RegExp)) {
992    return curryArgs.length
993      ? function() {
994          return arguments.length
995            ? fn.apply(self, concat(curryArgs, arguments, 0))
996            : fn.apply(self, curryArgs);
997        }
998      : function() {
999          return arguments.length
1000            ? fn.apply(self, arguments)
1001            : fn.call(self);
1002        };
1003  } else {
1004    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1005    return fn;
1006  }
1007}
1008
1009
1010function toJsonReplacer(key, value) {
1011  var val = value;
1012
1013  if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1014    val = undefined;
1015  } else if (isWindow(value)) {
1016    val = '$WINDOW';
1017  } else if (value &&  document === value) {
1018    val = '$DOCUMENT';
1019  } else if (isScope(value)) {
1020    val = '$SCOPE';
1021  }
1022
1023  return val;
1024}
1025
1026
1027/**
1028 * @ngdoc function
1029 * @name angular.toJson
1030 * @module ng
1031 * @kind function
1032 *
1033 * @description
1034 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1035 * stripped since angular uses this notation internally.
1036 *
1037 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1038 * @param {boolean|number=}
1038 pretty If set to true, the JSON output will contain newlines and whitespace.
1039 *    If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2).
1040 * @returns {string|undefined} JSON-ified string representing `obj`.
1041 */
1042function toJson(obj, pretty) {
1043  if (typeof obj === 'undefined') return undefined;
1044  if (!isNumber(pretty)) {
1045    pretty = pretty ? 2 : null;
1046  }
1047  return JSON.stringify(obj, toJsonReplacer, pretty);
1048}
1049
1050
1051/**
1052 * @ngdoc function
1053 * @name angular.fromJson
1054 * @module ng
1055 * @kind function
1056 *
1057 * @description
1058 * Deserializes a JSON string.
1059 *
1060 * @param {string} json JSON string to deserialize.
1061 * @returns {Object|Array|string|number} Deserialized JSON string.
1062 */
1063function fromJson(json) {
1064  return isString(json)
1065      ? JSON.parse(json)
1066      : json;
1067}
1068
1069
1070/**
1071 * @returns {string} Returns the string representation of the element.
1072 */
1073function startingTag(element) {
1074  element = jqLite(element).clone();
1075  try {
1076    // turns out IE does not let you set .html() on elements which
1077    // are not allowed to have children. So we just ignore it.
1078    element.empty();
1079  } catch (e) {}
1080  var elemHtml = jqLite('<div>').append(element).html();
1081  try {
1082    return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1083        elemHtml.
1084          match(/^(<[^>]+>)/)[1].
1085          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1086  } catch (e) {
1087    return lowercase(elemHtml);
1088  }
1089
1090}
1091
1092
1093/////////////////////////////////////////////////
1094
1095/**
1096 * Tries to decode the URI component without throwing an exception.
1097 *
1098 * @private
1099 * @param str value potential URI component to check.
1100 * @returns {boolean} True if `value` can be decoded
1101 * with the decodeURIComponent function.
1102 */
1103function tryDecodeURIComponent(value) {
1104  try {
1105    return decodeURIComponent(value);
1106  } catch (e) {
1107    // Ignore any invalid uri component
1108  }
1109}
1110
1111
1112/**
1113 * Parses an escaped url query string into key-value pairs.
1114 * @returns {Object.<string,boolean|Array>}
1115 */
1116function parseKeyValue(/**string*/keyValue) {
1117  var obj = {}, key_value, key;
1118  forEach((keyValue || "").split('&'), function(keyValue) {
1119    if (keyValue) {
1120      key_value = keyValue.replace(/\+/g,'%20').split('=');
1121      key = tryDecodeURIComponent(key_value[0]);
1122      if (isDefined(key)) {
1123        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1124        if (!hasOwnProperty.call(obj, key)) {
1125          obj[key] = val;
1126        } else if (isArray(obj[key])) {
1127          obj[key].push(val);
1128        } else {
1129          obj[key] = [obj[key],val];
1130        }
1131      }
1132    }
1133  });
1134  return obj;
1135}
1136
1137function toKeyValue(obj) {
1138  var parts = [];
1139  forEach(obj, function(value, key) {
1140    if (isArray(value)) {
1141      forEach(value, function(arrayValue) {
1142        parts.push(encodeUriQuery(key, true) +
1143                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1144      });
1145    } else {
1146    parts.push(encodeUriQuery(key, true) +
1147               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1148    }
1149  });
1150  return parts.length ? parts.join('&') : '';
1151}
1152
1153
1154/**
1155 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1156 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1157 * segments:
1158 *    segment       = *pchar
1159 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1160 *    pct-encoded   = "%" HEXDIG HEXDIG
1161 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1162 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1163 *                     / "*" / "+" / "," / ";" / "="
1164 */
1165function encodeUriSegment(val) {
1166  return encodeUriQuery(val, true).
1167             replace(/%26/gi, '&').
1168             replace(/%3D/gi, '=').
1169             replace(/%2B/gi, '+');
1170}
1171
1172
1173/**
1174 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1175 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1176 * encoded per http://tools.ietf.org/html/rfc3986:
1177 *    query       = *( pchar / "/" / "?" )
1178 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1179 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1180 *    pct-encoded   = "%" HEXDIG HEXDIG
1181 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1182 *                     / "*" / "+" / "," / ";" / "="
1183 */
1184function encodeUriQuery(val, pctEncodeSpaces) {
1185  return encodeURIComponent(val).
1186             replace(/%40/gi, '@').
1187             replace(/%3A/gi, ':').
1188             replace(/%24/g, '$').
1189             replace(/%2C/gi, ',').
1190             replace(/%3B/gi, ';').
1191             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1192}
1193
1194var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1195
1196function getNgAttribute(element, ngAttr) {
1197  var attr, i, ii = ngAttrPrefixes.length;
1198  element = jqLite(element);
1199  for (i = 0; i < ii; ++i) {
1200    attr = ngAttrPrefixes[i] + ngAttr;
1201    if (isString(attr = element.attr(attr))) {
1202      return attr;
1203    }
1204  }
1205  return null;
1206}
1207
1208/**
1209 * @ngdoc directive
1210 * @name ngApp
1211 * @module ng
1212 *
1213 * @element ANY
1214 * @param {angular.Module} ngApp an optional application
1215 *   {@link angular.module module} name to load.
1216 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1217 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1218 *   do not use explicit function annotation (and are thus unsuitable for minification), as de
1218scribed
1219 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1220 *   tracking down the root of these bugs.
1221 *
1222 * @description
1223 *
1224 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1225 * designates the **root element** of the application and is typically placed near the root element
1226 * of the page - e.g. on the `<body>` or `<html>` tags.
1227 *
1228 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1229 * found in the document will be used to define the root element to auto-bootstrap as an
1230 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1231 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1232 *
1233 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1234 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1235 * should contain the application code needed or have dependencies on other modules that will
1236 * contain the code. See {@link angular.module} for more information.
1237 *
1238 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1239 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1240 * would not be resolved to `3`.
1241 *
1242 * `ngApp` is the easiest, and most common way to bootstrap an application.
1243 *
1244 <example module="ngAppDemo">
1245   <file name="index.html">
1246   <div ng-controller="ngAppDemoController">
1247     I can add: {{a}} + {{b}} =  {{ a+b }}
1248   </div>
1249   </file>
1250   <file name="script.js">
1251   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1252     $scope.a = 1;
1253     $scope.b = 2;
1254   });
1255   </file>
1256 </example>
1257 *
1258 * Using `ngStrictDi`, you would see something like this:
1259 *
1260 <example ng-app-included="true">
1261   <file name="index.html">
1262   <div ng-app="ngAppStrictDemo" ng-strict-di>
1263       <div ng-controller="GoodController1">
1264           I can add: {{a}} + {{b}} =  {{ a+b }}
1265
1266           <p>This renders because the controller does not fail to
1267              instantiate, by using explicit annotation style (see
1268              script.js for details)
1269           </p>
1270       </div>
1271
1272       <div ng-controller="GoodController2">
1273           Name: <input ng-model="name"><br />
1274           Hello, {{name}}!
1275
1276           <p>This renders because the controller does not fail to
1277              instantiate, by using explicit annotation style
1278              (see script.js for details)
1279           </p>
1280       </div>
1281
1282       <div ng-controller="BadController">
1283           I can add: {{a}} + {{b}} =  {{ a+b }}
1284
1285           <p>The controller could not be instantiated, due to relying
1286              on automatic function annotations (which are disabled in
1287              strict mode). As such, the content of this section is not
1288              interpolated, and there should be an error in your web console.
1289           </p>
1290       </div>
1291   </div>
1292   </file>
1293   <file name="script.js">
1294   angular.module('ngAppStrictDemo', [])
1295     // BadController will fail to instantiate, due to relying on automatic function annotation,
1296     // rather than an explicit annotation
1297     .controller('BadController', function($scope) {
1298       $scope.a = 1;
1299       $scope.b = 2;
1300     })
1301     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1302     // due to using explicit annotations using the array style and $inject property, respectively.
1303     .controller('GoodController1', ['$scope', function($scope) {
1304       $scope.a = 1;
1305       $scope.b = 2;
1306     }])
1307     .controller('GoodController2', GoodController2);
1308     function GoodController2($scope) {
1309       $scope.name = "World";
1310     }
1311     GoodController2.$inject = ['$scope'];
1312   </file>
1313   <file name="style.css">
1314   div[ng-controller] {
1315       margin-bottom: 1em;
1316       -webkit-border-radius: 4px;
1317       border-radius: 4px;
1318       border: 1px solid;
1319       padding: .5em;
1320   }
1321   div[ng-controller^=Good] {
1322       border-color: #d6e9c6;
1323       background-color: #dff0d8;
1324       color: #3c763d;
1325   }
1326   div[ng-controller^=Bad] {
1327       border-color: #ebccd1;
1328       background-color: #f2dede;
1329       color: #a94442;
1330       margin-bottom: 0;
1331   }
1332   </file>
1333 </example>
1334 */
1335function angularInit(element, bootstrap) {
1336  var appElement,
1337      module,
1338      config = {};
1339
1340  // The element `element` has priority over any other element
1341  forEach(ngAttrPrefixes, function(prefix) {
1342    var name = prefix + 'app';
1343
1344    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1345      appElement = element;
1346      module = element.getAttribute(name);
1347    }
1348  });
1349  forEach(ngAttrPrefixes, function(prefix) {
1350    var name = prefix + 'app';
1351    var candidate;
1352
1353    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1354      appElement = candidate;
1355      module = candidate.getAttribute(name);
1356    }
1357  });
1358  if (appElement) {
1359    config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1360    bootstrap(appElement, module ? [module] : [], config);
1361  }
1362}
1363
1364/**
1365 * @ngdoc function
1366 * @name angular.bootstrap
1367 * @module ng
1368 * @description
1369 * Use this function to manually start up angular application.
1370 *
1371 * See: {@link guide/bootstrap Bootstrap}
1372 *
1373 * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1374 * They must use {@link ng.directive:ngApp ngApp}.
1375 *
1376 * Angular will detect if it has been loaded into the browser more than once and only allow the
1377 * first loaded script to be bootstrapped and will report a warning to the browser console for
1378 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1379 * multiple instances of Angular try to work on the DOM.
1380 *
1381 * ```html
1382 * <!doctype html>
1383 * <html>
1384 * <body>
1385 * <div ng-controller="WelcomeController">
1386 *   {{greeting}}
1387 * </div>
1388 *
1389 * <script src="angular.js"></script>
1390 * <script>
1391 *   var app = angular.module('demo', [])
1392 *   .controller('WelcomeController', function($scope) {
1393 *       $scope.greeting = 'Welcome!';
1394 *   });
1395 *   angular.bootstrap(document, ['demo']);
1396 * </script>
1397 * </body>
1398 * </html>
1399 * ```
1400 *
1401 * @param {DOMElement} element DOM element which is the root of angular application.
1402 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1403 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1404 *     function that will be invoked by the injector as a `config` block.
1405 *     See: {@link angular.module modules}
1406 * @param {Object=} config an object for defining configuration options for the application. The
1407 *     following keys are supported:
1408 *
1409 * * `strictDi` - disable automatic function annotation for the application. This is meant to
1410 *   assist in finding bugs which break minified code. Defaults to `false`.
1411 *
1412 * @returns {auto.$injector} Returns the newly created injector for this app.
1413 */
1414function bootstrap(element, modules, config) {
1415  if (!isObject(config)) config = {};
1416  var defaultConfig = {
1417    strictDi: false
1418  };
1419  config = extend(defaultConfig, config);
1420  var doBootstrap = function() {
1421    element = jqLite(element);
1422
1423    if (element.injector()) {
1424      var tag = (element[0] === document) ? 'document' : startingTag(element);
1425      //Encode angle brackets to prevent input from being sanitized to empty string #8683
1426      throw ngMinErr(
1427          'btstrpd',
1428          "App Already Bootstrapped with this Element '{0}'",
1429          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1430    }
1431
1432    modules = modules || [];
1433    modules.unshift(['$provide', function($provide) {
1434      $provide.value('$rootElement', element);
1435    }]);
1436
1437    if (config.debugInfoEnabled) {
1438      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1439      modules.push(['$compileProvider', function($compileProvider) {
1440        $compileProvider.debugInfoEnabled(true);
1441      }]);
1442    }
1443
1444    modules.unshift('ng');
1445    var injector = createInjector(modules, config.strictDi);
1446    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1447       function bootstrapApply(scope, element, compile, injector) {
1448        scope.$apply(function() {
1449          element.data('$injector', injector);
1450          compile(element)(scope);
1451        });
1452      }]
1453    );
1454    return injector;
1455  };
1456
1457  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1458  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1459
1460  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1461    config.debugInfoEnabled = true;
1462    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1463  }
1464
1465  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1466    return doBootstrap();
1467  }
1468
1469  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1470  angular.resumeBootstrap = function(extraModules) {
1471    forEach(extraModules, function(module) {
1472      modules.push(module);
1473    });
1474    return doBootstrap();
1475  };
1476
1477  if (isFunction(angular.resumeDeferredBootstrap)) {
1478    angular.resumeDeferredBootstrap();
1479  }
1480}
1481
1482/**
1483 * @ngdoc function
1484 * @name angular.reloadWithDebugInfo
1485 * @module ng
1486 * @description
1487 * Use this function to reload the current application with debug information turned on.
1488 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1489 *
1490 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1491 */
1492function reloadWithDebugInfo() {
1493  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1494  window.location.reload();
1495}
1496
1497/**
1498 * @name angular.getTestability
1499 * @module ng
1500 * @description
1501 * Get the testability service for the instance of Angular on the given
1502 * element.
1503 * @param {DOMElement} element DOM element which is the root of angular application.
1504 */
1505function getTestability(rootElement) {
1506  var injector = angular.element(rootElement).injector();
1507  if (!injector) {
1508    throw ngMinErr('test',
1509      'no injector found for element argument to getTestability');
1510  }
1511  return injector.get('$$testability');
1512}
1513
1514var SNAKE_CASE_REGEXP = /[A-Z]/g;
1515function snake_case(name, separator) {
1516  separator = separator || '_';
1517  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1518    return (pos ? separator : '') + letter.toLowerCase();
1519  });
1520}
1521
1522var bindJQueryFired = false;
1523var skipDestroyOnNextJQueryCleanData;
1524function bindJQuery() {
1525  var originalCleanData;
1526
1527  if (bindJQueryFired) {
1528    return;
1529  }
1530
1531  // bind to jQuery if present;
1532  jQuery = window.jQuery;
1533  // Use jQuery if it exists with proper functionality, otherwise default to us.
1534  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1535  // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1536  // versions. It will not work for sure with jQuery <1.7, though.
1537  if (jQuery && jQuery.fn.on) {
1538    jqLite = jQuery;
1539    extend(jQuery.fn, {
1540      scope: JQLitePrototype.scope,
1541      isolateScope: JQLitePrototype.isolateScope,
1542      controller: JQLitePrototype.controller,
1543      injector: JQLitePrototype.injector,
1544      inheritedData: JQLitePrototype.inheritedData
1545    });
1546
1547    // All nodes removed from the DOM via various jQuery APIs like .remove()
1548    // are passed through jQuery.cleanData. Monkey-patch this method to fire
1549    // the $destroy event on all removed nodes.
1550    originalCleanData = jQuery.cleanData;
1551    jQuery.cleanData = function(elems) {
1552      var events;
1553      if (!skipDestroyOnNextJQueryCleanData) {
1554        for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1555          events = jQuery._data(elem, "events");
1556          if (events && events.$destroy) {
1557            jQuery(elem).triggerHandler('$destroy');
1558          }
1559        }
1560      } else {
1561        skipDestroyOnNextJQueryCleanData = false;
1562      }
1563      originalCleanData(elems);
1564    };
1565  } else {
1566    jqLite = JQLite;
1567  }
1568
1569  angular.element = jqLite;
1570
1571  // Prevent double-proxying.
1572  bindJQueryFired = true;
1573}
1574
1575/**
1576 * throw error if the argument is falsy.
1577 */
1578function assertArg(arg, name, reason) {
1579  if (!arg) {
1580    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1581  }
1582  return arg;
1583}
1584
1585function assertArgFn(arg, name, acceptArrayAnnotation) {
1586  if (acceptArrayAnnotation && isArray(arg)) {
1587      arg = arg[arg.length - 1];
1588  }
1589
1590  assertArg(isFunction(arg), name, 'not a function, got ' +
1591      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1592  return arg;
1593}
1594
1595/**
1596 * throw error if the name given is hasOwnProperty
1597 * @param  {String} name    the name to test
1598 * @param  {String} context the context in which the name is used, such as module or directive
1599 */
1600function assertNotHasOwnProperty(name, context) {
1601  if (name === 'hasOwnProperty') {
1602    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1603  }
1604}
1605
1606/**
1607 * Return the value accessible from the object by path. Any undefined traversals are ignored
1608 * @param {Object} obj starting object
1609 * @param {String} path path to traverse
1610 * @param {boolean} [bindFnToScope=true]
1611 * @returns {Object} value as accessible by path
1612 */
1613//TODO(misko): this function needs to be removed
1614function getter(obj, path, bindFnToScope) {
1615  if (!path) return obj;
1616  var keys = path.split('.');
1617  var key;
1618  var lastInstance = obj;
1619  var len = keys.length;
1620
1621  for (var i = 0; i < len; i++) {
1622    key = keys[i];
1623    if (obj) {
1624      obj = (lastInstance = obj)[key];
1625    }
1626  }
1627  if (!bindFnToScope && isFunction(obj)) {
1628    return bind(lastInstance, obj);
1629  }
1630  return obj;
1631}
1632
1633/**
1634 * Return the DOM siblings between the first and last node in the given array.
1635 * @param {Array} array like object
1636 * @returns {jqLite} jqLite collection containing the nodes
1637 */
1638function getBlockNodes(nodes) {
1639  // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
1640  //             collection, otherwise update the original collection.
1641  var node = nodes[0];
1642  var endNode = nodes[nodes.length - 1];
1643  var blockNodes = [node];
1644
1645  do {
1646    node = node.nextSibling;
1647    if (!node) break;
1648    blockNodes.push(node);
1649  } while (node !== endNode);
1650
1651  return jqLite(blockNodes);
1652}
1653
1654
1655/**
1656 * Creates a new object without a prototype. This object is useful for lookup without having to
1657 * guard against prototypically inherited properties via hasOwnProperty.
1658 *
1659 * Related micro-benchmarks:
1660 * - http://jsperf.com/object-create2
1661 * - http://jsperf.com/proto-map-lookup/2
1662 * - http://jsperf.com/for-in-vs-object-keys2
1663 *
1664 * @returns {Object}
1665 */
1666function createMap() {
1667  return Object.create(null);
1668}
1669
1670var NODE_TYPE_ELEMENT = 1;
1671var NODE_TYPE_TEXT = 3;
1672var NODE_TYPE_COMMENT = 8;
1673var NODE_TYPE_DOCUMENT = 9;
1674var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1675
1676/**
1677 * @ngdoc type
1678 * @name angular.Module
1679 * @module ng
1680 * @description
1681 *
1682 * Interface for configuring angular {@link angular.module modules}.
1683 */
1684
1685function setupModuleLoader(window) {
1686
1687  var $injectorMinErr = minErr('$injector');
1688  var ngMinErr = minErr('ng');
1689
1690  function ensure(obj, name, factory) {
vendor: 4,138 bytes, lines 1691-1805
1691    return obj[name] || (obj[name] = factory());
1692  }
1693
1694  var angular = ensure(window, 'angular', Object);
1695
1696  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1697  angular.$$minErr = angular.$$minErr || minErr;
1698
1699  return ensure(angular, 'module', function() {
1700    /** @type {Object.<string, angular.Module>} */
1701    var modules = {};
1702
1703    /**
1704     * @ngdoc function
1705     * @name angular.module
1706     * @module ng
1707     * @description
1708     *
1709     * The `angular.module` is a global place for creating, registering and retrieving Angular
1710     * modules.
1711     * All modules (angular core or 3rd party) that should be available to an application must be
1712     * registered using this mechanism.
1713     *
1714     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1715     * existing module (the name passed as the first argument to `module`) is retrieved.
1716     *
1717     *
1718     * # Module
1719     *
1720     * A module is a collection of services, directives, controllers, filters, and configuration information.
1721     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1722     *
1723     * ```js
1724     * // Create a new module
1725     * var myModule = angular.module('myModule', []);
1726     *
1727     * // register a new service
1728     * myModule.value('appName', 'MyCoolApp');
1729     *
1730     * // configure existing services inside initialization blocks.
1731     * myModule.config(['$locationProvider', function($locationProvider) {
1732     *   // Configure existing providers
1733     *   $locationProvider.hashPrefix('!');
1734     * }]);
1735     * ```
1736     *
1737     * Then you can create an injector and load your modules like this:
1738     *
1739     * ```js
1740     * var injector = angular.injector(['ng', 'myModule'])
1741     * ```
1742     *
1743     * However it's more likely that you'll just use
1744     * {@link ng.directive:ngApp ngApp} or
1745     * {@link angular.bootstrap} to simplify this process for you.
1746     *
1747     * @param {!string} name The name of the module to create or retrieve.
1748     * @param {!Array.<string>=} requires If specified then new module is being created. If
1749     *        unspecified then the module is being retrieved for further configuration.
1750     * @param {Function=} configFn Optional configuration function for the module. Same as
1751     *        {@link angular.Module#config Module#config()}.
1752     * @returns {module} new module with the {@link angular.Module} api.
1753     */
1754    return function module(name, requires, configFn) {
1755      var assertNotHasOwnProperty = function(name, context) {
1756        if (name === 'hasOwnProperty') {
1757          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1758        }
1759      };
1760
1761      assertNotHasOwnProperty(name, 'module');
1762      if (requires && modules.hasOwnProperty(name)) {
1763        modules[name] = null;
1764      }
1765      return ensure(modules, name, function() {
1766        if (!requires) {
1767          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1768             "the module name or forgot to load it. If registering a module ensure that you " +
1769             "specify the dependencies as the second argument.", name);
1770        }
1771
1772        /** @type {!Array.<Array.<*>>} */
1773        var invokeQueue = [];
1774
1775        /** @type {!Array.<Function>} */
1776        var configBlocks = [];
1777
1778        /** @type {!Array.<Function>} */
1779        var runBlocks = [];
1780
1781        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
1782
1783        /** @type {angular.Module} */
1784        var moduleInstance = {
1785          // Private state
1786          _invokeQueue: invokeQueue,
1787          _configBlocks: configBlocks,
1788          _runBlocks: runBlocks,
1789
1790          /**
1791           * @ngdoc property
1792           * @name angular.Module#requires
1793           * @module ng
1794           *
1795           * @description
1796           * Holds the list of modules which the injector will load before the current module is
1797           * loaded.
1798           */
1799          requires: requires,
1800
1801          /**
1802           * @ngdoc property
1803           * @name angular.Module#name
1804           * @module ng
1805           *
1806           * @description
1807           * Name of the module.
1808           */
1809          name: name,
1810
1811
1812          /**
1813           * @ngdoc method
1814           * @name angular.Module#provider
1815           * @module ng
1816           * @param {string} name service name
1817           * @param {Function} providerType Construction function for creating new instance of the
1818           *                                service.
1819           * @description
1820           * See {@link auto.$provide#provider $provide.provider()}.
1821           */
1822          provider: invokeLater('$provide', 'provider'),
1823
1824          /**
1825           * @ngdoc method
1826           * @name angular.Module#factory
1827           * @module ng
1828           * @param {string} name service name
1829           * @param {Function} providerFunction Function for creating new instance of the service.
1830           * @description
1831           * See {@link auto.$provide#factory $provide.factory()}.
1832           */
1833          factory: invokeLater('$provide', 'factory'),
1834
1835          /**
1836           * @ngdoc method
1837           * @name angular.Module#service
1838           * @module ng
1839           * @param {string} name service name
1840           * @param {Function} constructor A constructor function that will be instantiated.
1841           * @description
1842           * See {@link auto.$provide#service $provide.service()}.
1843           */
1844          service: invokeLater('$provide', 'service'),
1845
1846          /**
1847           * @ngdoc method
1848           * @name angular.Module#value
1849           * @module ng
1850           * @param {string} name service name
1851           * @param {*} object Service instance object.
1852           * @description
1853           * See {@link auto.$provide#value $provide.value()}.
1854           */
1855          value: invokeLater('$provide', 'value'),
1856
1857          /**
1858           * @ngdoc method
1859           * @name angular.Module#constant
1860           * @module ng
1861           * @param {string} name constant name
1862           * @param {*} object Constant value.
1863           * @description
1864           * Because the constant are fixed, they get applied before other provide methods.
1865           * See {@link auto.$provide#constant $provide.constant()}.
1866           */
1867          constant: invokeLater('$provide', 'constant', 'unshift'),
1868
1869          /**
1870           * @ngdoc method
1871           * @name angular.Module#animation
1872           * @module ng
1873           * @param {string} name animation name
1874           * @param {Function} animationFactory Factory function for creating new instance of an
1875           *                                    animation.
1876           * @description
1877           *
1878           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1879           *
1880           *
1881           * Defines an animation hook that can be later used with
1882           * {@link ngAnimate.$animate $animate} service and directives that use this service.
1883           *
1884           * ```js
1885           * module.animation('.animation-name', function($inject1, $inject2) {
1886           *   return {
1887           *     eventName : function(element, done) {
1888           *       //code to run the animation
1889           *       //once complete, then run done()
1890           *       return function cancellationFunction(element) {
1891           *         //code to cancel the animation
1892           *       }
1893           *     }
1894           *   }
1895           * })
1896           * ```
1897           *
1898           * See {@link ng.$animateProvider#register $animateProvider.register()} and
1899           * {@link ngAnimate ngAnimate module} for more information.
1900           */
1901          animation: invokeLater('$animateProvider', 'register'),
1902
1903          /**
1904           * @ngdoc method
1905           * @name angular.Module#filter
1906           * @module ng
1907           * @param {string} name Filter name.
1908           * @param {Function} filterFactory Factory function for creating new instance of filter.
1909           * @description
1910           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1911           */
1912          filter: invokeLater('$filterProvider', 'register'),
1913
1914          /**
1915           * @ngdoc method
1916           * @name angular.Module#controller
1917           * @module ng
1918           * @param {string|Object} name Controller name, or an object map of controllers where the
1919           *    keys are the names and the values are the constructors.
1920           * @param {Function} constructor Controller constructor function.
vendor: 4,201 bytes, lines 1921-2078
1921           * @description
1922           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1923           */
1924          controller: invokeLater('$controllerProvider', 'register'),
1925
1926          /**
1927           * @ngdoc method
1928           * @name angular.Module#directive
1929           * @module ng
1930           * @param {string|Object} name Directive name, or an object map of directives where the
1931           *    keys are the names and the values are the factories.
1932           * @param {Function} directiveFactory Factory function for creating new instance of
1933           * directives.
1934           * @description
1935           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1936           */
1937          directive: invokeLater('$compileProvider', 'directive'),
1938
1939          /**
1940           * @ngdoc method
1941           * @name angular.Module#config
1942           * @module ng
1943           * @param {Function} configFn Execute this function on module load. Useful for service
1944           *    configuration.
1945           * @description
1946           * Use this method to register work which needs to be performed on module loading.
1947           * For more about how to configure services, see
1948           * {@link providers#provider-recipe Provider Recipe}.
1949           */
1950          config: config,
1951
1952          /**
1953           * @ngdoc method
1954           * @name angular.Module#run
1955           * @module ng
1956           * @param {Function} initializationFn Execute this function after injector creation.
1957           *    Useful for application initialization.
1958           * @description
1959           * Use this method to register work which should be performed when the injector is done
1960           * loading all modules.
1961           */
1962          run: function(block) {
1963            runBlocks.push(block);
1964            return this;
1965          }
1966        };
1967
1968        if (configFn) {
1969          config(configFn);
1970        }
1971
1972        return moduleInstance;
1973
1974        /**
1975         * @param {string} provider
1976         * @param {string} method
1977         * @param {String=} insertMethod
1978         * @returns {angular.Module}
1979         */
1980        function invokeLater(provider, method, insertMethod, queue) {
1981          if (!queue) queue = invokeQueue;
1982          return function() {
1983            queue[insertMethod || 'push']([provider, method, arguments]);
1984            return moduleInstance;
1985          };
1986        }
1987      });
1988    };
1989  });
1990
1991}
1992
1993/* global: toDebugString: true */
1994
1995function serializeObject(obj) {
1996  var seen = [];
1997
1998  return JSON.stringify(obj, function(key, val) {
1999    val = toJsonReplacer(key, val);
2000    if (isObject(val)) {
2001
2002      if (seen.indexOf(val) >= 0) return '<<already seen>>';
2003
2004      seen.push(val);
2005    }
2006    return val;
2007  });
2008}
2009
2010function toDebugString(obj) {
2011  if (typeof obj === 'function') {
2012    return obj.toString().replace(/ \{[\s\S]*$/, '');
2013  } else if (typeof obj === 'undefined') {
2014    return 'undefined';
2015  } else if (typeof obj !== 'string') {
2016    return serializeObject(obj);
2017  }
2018  return obj;
2019}
2020
2021/* global angularModule: true,
2022  version: true,
2023
2024  $LocaleProvider,
2025  $CompileProvider,
2026
2027  htmlAnchorDirective,
2028  inputDirective,
2029  inputDirective,
2030  formDirective,
2031  scriptDirective,
2032  selectDirective,
2033  styleDirective,
2034  optionDirective,
2035  ngBindDirective,
2036  ngBindHtmlDirective,
2037  ngBindTemplateDirective,
2038  ngClassDirective,
2039  ngClassEvenDirective,
2040  ngClassOddDirective,
2041  ngCspDirective,
2042  ngCloakDirective,
2043  ngControllerDirective,
2044  ngFormDirective,
2045  ngHideDirective,
2046  ngIfDirective,
2047  ngIncludeDirective,
2048  ngIncludeFillContentDirective,
2049  ngInitDirective,
2050  ngNonBindableDirective,
2051  ngPluralizeDirective,
2052  ngRepeatDirective,
2053  ngShowDirective,
2054  ngStyleDirective,
2055  ngSwitchDirective,
2056  ngSwitchWhenDirective,
2057  ngSwitchDefaultDirective,
2058  ngOptionsDirective,
2059  ngTranscludeDirective,
2060  ngModelDirective,
2061  ngListDirective,
2062  ngChangeDirective,
2063  patternDirective,
2064  patternDirective,
2065  requiredDirective,
2066  requiredDirective,
2067  minlengthDirective,
2068  minlengthDirective,
2069  maxlengthDirective,
2070  maxlengthDirective,
2071  ngValueDirective,
2072  ngModelOptionsDirective,
2073  ngAttributeAliasDirectives,
2074  ngEventDirectives,
2075
2076  $AnchorScrollProvider,
2077  $AnimateProvider,
2078  $BrowserProvider,
2079  $CacheFactoryProvider,
2080  $ControllerProvider,
2081  $DocumentProvider,
2082  $ExceptionHandlerProvider,
2083  $FilterProvider,
2084  $InterpolateProvider,
2085  $IntervalProvider,
2086  $HttpProvider,
2087  $HttpBackendProvider,
2088  $LocationProvider,
2089  $LogProvider,
2090  $ParseProvider,
2091  $RootScopeProvider,
2092  $QProvider,
2093  $$QProvider,
2094  $$SanitizeUriProvider,
2095  $SceProvider,
2096  $SceDelegateProvider,
2097  $SnifferProvider,
2098  $TemplateCacheProvider,
2099  $TemplateRequestProvider,
2100  $$TestabilityProvider,
2101  $TimeoutProvider,
2102  $$RAFProvider,
2103  $$AsyncCallbackProvider,
2104  $WindowProvider,
2105  $$jqLiteProvider
2106*/
2107
2108
2109/**
2110 * @ngdoc object
2111 * @name angular.version
2112 * @module ng
2113 * @description
2114 * An object that contains information about the current AngularJS version. This object has the
2115 * following properties:
2116 *
2117 * - `full` – `{string}` – Full version string, such as "0.9.18".
2118 * - `major` – `{number}` – Major version number, such as "0".
2119 * - `minor` – `{number}` – Minor version number, such as "9".
2120 * - `dot` – `{number}` – Dot version number, such as "18".
2121 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2122 */
2123var version = {
2124  full: '1.3.12',    // all of these placeholder strings will be replaced by grunt's
2125  major: 1,    // package task
2126  minor: 3,
2127  dot: 12,
2128  codeName: 'outlandish-knitting'
2129};
2130
2131
2132function publishExternalAPI(angular) {
2133  extend(angular, {
2134    'bootstrap': bootstrap,
2135    'copy': copy,
2136    'extend': extend,
2137    'equals': equals,
2138    'element': jqLite,
2139    'forEach': forEach,
2140    'injector': createInjector,
2141    'noop': noop,
2142    'bind': bind,
2143    'toJson': toJson,
2144    'fromJson': fromJson,
2145    'identity': identity,
2146    'isUndefined': isUndefined,
2147    'isDefined': isDefined,
2148    'isString': isString,
2149    'isFunction': isFunction,
2150    'isObject': isObject,
2151    'isNumber': isNumber,
2152    'isElement': isElement,
2153    'isArray': isArray,
2154    'version': version,
2155    'isDate': isDate,
2156    'lowercase': lowercase,
2157    'uppercase': uppercase,
2158    'callbacks': {counter: 0},
2159    'getTestability': getTestability,
2160    '$$minErr': minErr,
2161    '$$csp': csp,
2162    'reloadWithDebugInfo': reloadWithDebugInfo
2163  });
2164
2165  angularModule = setupModuleLoader(window);
2166  try {
2167    angularModule('ngLocale');
2168  } catch (e) {
2169    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2170  }
2171
2172  angularModule('ng', ['ngLocale'], ['$provide',
2173    function ngModule($provide) {
2174      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2175      $provide.provider({
2176        $$sanitizeUri: $$SanitizeUriProvider
2177      });
2178      $provide.provider('$compile', $CompileProvider).
2179        directive({
2180            a: htmlAnchorDirective,
2181            input: inputDirective,
2182            textarea: inputDirective,
2183            form: formDirective,
2184            script: scriptDirective,
2185            select: selectDirective,
2186            style: styleDirective,
2187            option: optionDirective,
2188            ngBind: ngBindDirective,
2189            ngBindHtml: ngBindHtmlDirective,
2190            ngBindTemplate: ngBindTemplateDirective,
2191            ngClass: ngClassDirective,
2192            ngClassEven: ngClassEvenDirective,
2193            ngClassOdd: ngClassOddDirective,
2194            ngCloak: ngCloakDirective,
2195            ngController: ngControllerDirective,
2196            ngForm: ngFormDirective,
2197            ngHide: ngHideDirective,
2198            ngIf: ngIfDirective,
2199            ngInclude: ngIncludeDirective,
2200            ngInit: ngInitDirective,
2201            ngNonBindable: ngNonBindableDirective,
2202            ngPluralize: ngPluralizeDirective,
2203            ngRepeat: ngRepeatDirective,
2204            ngShow: ngShowDirective,
2205            ngStyle: ngStyleDirective,
2206            ngSwitch: ngSwitchDirective,
2207            ngSwitchWhen: ngSwitchWhenDirective,
2208            ngSwitchDefault: ngSwitchDefaultDirective,
2209            ngOptions: ngOptionsDirective,
2210            ngTransclude: ngTranscludeDirective,
2211            ngModel: ngModelDirective,
2212            ngList: ngListDirective,
2213            ngChange: ngChangeDirective,
2214            pattern: patternDirective,
2215            ngPattern: patternDirective,
2216            required: requiredDirective,
2217            ngRequired: requiredDirective,
2218            minlength: minlengthDirective,
2219            ngMinlength: minlengthDirective,
2220            maxlength: maxlengthDirective,
2221            ngMaxlength: maxlengthDirective,
2222            ngValue: ngValueDirective,
2223            ngModelOptions: ngModelOptionsDirective
2224        }).
2225        directive({
2226          ngInclude: ngIncludeFillContentDirective
2227        }).
2228        directive(ngAttributeAliasDirectives).
2229        directive(ngEventDirectives);
2230      $provide.provider({
2231        $anchorScroll: $AnchorScrollProvider,
2232        $animate: $AnimateProvider,
2233        $browser: $BrowserProvider,
2234        $cacheFactory: $CacheFactoryProvider,
2235        $controller: $ControllerProvider,
2236        $document: $DocumentProvider,
2237        $exceptionHandler: $ExceptionHandlerProvider,
2238        $filter: $FilterProvider,
2239        $interpolate: $InterpolateProvider,
2240        $interval: $IntervalProvider,
2241        $http: $HttpProvider,
2242        $httpBackend: $HttpBackendProvider,
2243        $location: $LocationProvider,
2244        $log: $LogProvider,
2245        $parse: $ParseProvider,
2246        $rootScope: $RootScopeProvider,
2247        $q: $QProvider,
2248        $$q: $$QProvider,
2249        $sce: $SceProvider,
2250        $sceDelegate: $SceDelegateProvider,
2251        $sniffer: $SnifferProvider,
2252        $templateCache: $TemplateCacheProvider,
2253        $templateRequest: $TemplateRequestProvider,
2254        $$testability: $$TestabilityProvider,
2255        $timeout: $TimeoutProvider,
2256        $window: $WindowProvider,
2257        $$rAF: $$RAFProvider,
2258        $$asyncCallback: $$AsyncCallbackProvider,
2259        $$jqLite: $$jqLiteProvider
2260      });
2261    }
2262  ]);
2263}
2264
2265/* global JQLitePrototype: true,
2266  addEventListenerFn: true,
2267  removeEventListenerFn: true,
2268  BOOLEAN_ATTR: true,
2269  ALIASED_ATTR: true,
2270*/
2271
2272//////////////////////////////////
2273//JQLite
2274//////////////////////////////////
2275
2276/**
2277 * @ngdoc function
2278 * @name angular.element
2279 * @module ng
2280 * @kind function
2281 *
2282 * @description
2283 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2284 *
2285 * If jQuery is available, `angular.element` is an alias for the
2286 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2287 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2288 *
2289 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2290 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2291 * commonly needed functionality with the goal of having a very small footprint.</div>
2292 *
2293 * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2294 *
2295 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2296 * jqLite; they are never raw DOM references.</div>
2297 *
2298 * ## Angular's jqLite
2299 * jqLite provides only the following jQuery methods:
2300 *
2301 * - [`addClass()`](http://api.jquery.com/addClass/)
2302 * - [`after()`](http://api.jquery.com/after/)
2303 * - [`append()`](http://api.jquery.com/append/)
2304 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2305 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2306 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2307 * - [`clone()`](http://api.jquery.com/clone/)
2308 * - [`contents()`](http://api.jquery.com/contents/)
2309 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`
2310 * - [`data()`](http://api.jquery.com/data/)
2311 * - [`detach()`](http://api.jquery.com/detach/)
2312 * - [`empty()`](http://api.jquery.com/empty/)
2313 * - [`eq()`](http://api.jquery.com/eq/)
2314 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2315 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2316 * - [`html()`](http://api.jquery.com/html/)
2317 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2318 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2319 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2320 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2321 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2322 * - [`prepend()`](http://api.jquery.com/prepend/)
2323 * - [`prop()`](http://api.jquery.com/prop/)
2324 * - [`ready()`](http://api.jquery.com/ready/)
2325 * - [`remove()`](http://api.jquery.com/remove/)
2326 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2327 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2328 * - [`removeData()`](http://api.jquery.com/removeData/)
2329 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2330 * - [`text()`](http://api.jquery.com/text/)
2331 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2332 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2333 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2334 * - [`val()`](http://api.jquery.com/val/)
2335 * - [`wrap()`](http://api.jquery.com/wrap/)
2336 *
2337 * ## jQuery/jqLite Extras
2338 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2339 *
2340 * ### Events
2341 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2341pis and fires this event
2342 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2343 *    element before it is removed.
2344 *
2345 * ### Methods
2346 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2347 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2348 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2349 *   `'ngModel'`).
2350 * - `injector()` - retrieves the injector of the current element or its parent.
2351 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2352 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2353 *   be enabled.
2354 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2355 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2356 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2357 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2358 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2359 *   parent element is reached.
2360 *
2361 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2362 * @returns {Object} jQuery object.
2363 */
2364
2365JQLite.expando = 'ng339';
2366
2367var jqCache = JQLite.cache = {},
2368    jqId = 1,
2369    addEventListenerFn = function(element, type, fn) {
2370      element.addEventListener(type, fn, false);
2371    },
2372    removeEventListenerFn = function(element, type, fn) {
2373      element.removeEventListener(type, fn, false);
2374    };
2375
2376/*
2377 * !!! This is an undocumented "private" function !!!
2378 */
2379JQLite._data = function(node) {
2380  //jQuery always returns an object on cache miss
2381  return this.cache[node[this.expando]] || {};
2382};
2383
2384function jqNextId() { return ++jqId; }
2385
2386
2387var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2388var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2389var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2390var jqLiteMinErr = minErr('jqLite');
2391
2392/**
2393 * Converts snake_case to camelCase.
2394 * Also there is special case for Moz prefix starting with upper case letter.
2395 * @param name Name to normalize
2396 */
2397function camelCase(name) {
2398  return name.
2399    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2400      return offset ? letter.toUpperCase() : letter;
2401    }).
2402    replace(MOZ_HACK_REGEXP, 'Moz$1');
2403}
2404
2405var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2406var HTML_REGEXP = /<|&#?\w+;/;
2407var TAG_NAME_REGEXP = /<([\w:]+)/;
2408var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2409
2410var wrapMap = {
2411  'option': [1, '<select multiple="multiple">', '</select>'],
2412
2413  'thead': [1, '<table>', '</table>'],
2414  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2415  'tr': [2, '<table><tbody>', '</tbody></table>'],
2416  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2417  '_default': [0, "", ""]
2418};
2419
2420wrapMap.optgroup = wrapMap.option;
2421wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2422wrapMap.th = wrapMap.td;
2423
2424
2425function jqLiteIsTextNode(html) {
2426  return !HTML_REGEXP.test(html);
2427}
2428
2429function jqLiteAcceptsData(node) {
2430  // The window object can accept data but has no nodeType
2431  // Otherwise we are only interested in elements (1) and documents (9)
2432  var nodeType = node.nodeType;
2433  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2434}
2435
2436function jqLiteBuildFragment(html, context) {
2437  var tmp, tag, wrap,
2438      fragment = context.createDocumentFragment(),
2439      nodes = [], i;
2440
2441  if (jqLiteIsTextNode(html)) {
2442    // Convert non-html into a text node
2443    nodes.push(context.createTextNode(html));
2444  } else {
2445    // Convert html into DOM nodes
2446    tmp = tmp || fragment.appendChild(context.createElement("div"));
2447    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2448    wrap = wrapMap[tag] || wrapMap._default;
2449    tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2450
2451    // Descend through wrappers to the right content
2452    i = wrap[0];
2453    while (i--) {
2454      tmp = tmp.lastChild;
2455    }
2456
2457    nodes = concat(nodes, tmp.childNodes);
2458
2459    tmp = fragment.firstChild;
2460    tmp.textContent = "";
2461  }
2462
2463  // Remove wrapper from fragment
2464  fragment.textContent = "";
2465  fragment.innerHTML = ""; // Clear inner HTML
2466  forEach(nodes, function(node) {
2467    fragment.appendChild(node);
2468  });
2469
2470  return fragment;
2471}
2472
2473function jqLiteParseHTML(html, context) {
2474  context = context || document;
2475  var parsed;
2476
2477  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2478    return [context.createElement(parsed[1])];
2479  }
2480
2481  if ((parsed = jqLiteBuildFragment(html, context))) {
2482    return parsed.childNodes;
2483  }
2484
2485  return [];
2486}
2487
vendor: 1,065 bytes, lines 2488-2529
2488/////////////////////////////////////////////
2489function JQLite(element) {
2490  if (element instanceof JQLite) {
2491    return element;
2492  }
2493
2494  var argIsString;
2495
2496  if (isString(element)) {
2497    element = trim(element);
2498    argIsString = true;
2499  }
2500  if (!(this instanceof JQLite)) {
2501    if (argIsString && element.charAt(0) != '<') {
2502      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2503    }
2504    return new JQLite(element);
2505  }
2506
2507  if (argIsString) {
2508    jqLiteAddNodes(this, jqLiteParseHTML(element));
2509  } else {
2510    jqLiteAddNodes(this, element);
2511  }
2512}
2513
2514function jqLiteClone(element) {
2515  return element.cloneNode(true);
2516}
2517
2518function jqLiteDealoc(element, onlyDescendants) {
2519  if (!onlyDescendants) jqLiteRemoveData(element);
2520
2521  if (element.querySelectorAll) {
2522    var descendants = element.querySelectorAll('*');
2523    for (var i = 0, l = descendants.length; i < l; i++) {
2524      jqLiteRemoveData(descendants[i]);
2525    }
2526  }
2527}
2528
2529function jqLiteOff(element, type, fn, unsupported) {
2530  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2531
2532  var expandoStore = jqLiteExpandoStore(element);
2533  var events = expandoStore && expandoStore.events;
2534  var handle = expandoStore && expandoStore.handle;
2535
2536  if (!handle) return; //no listeners registered
2537
2538  if (!type) {
2539    for (type in events) {
2540      if (type !== '$destroy') {
2541        removeEventListenerFn(element, type, handle);
2542      }
2543      delete events[type];
2544    }
2545  } else {
2546    forEach(type.split(' '), function(type) {
2547      if (isDefined(fn)) {
2548        var listenerFns = events[type];
2549        arrayRemove(listenerFns || [], fn);
2550        if (listenerFns && listenerFns.length > 0) {
2551          return;
2552        }
2553      }
2554
2555      removeEventListenerFn(element, type, handle);
2556      delete events[type];
2557    });
2558  }
2559}
2560
2561function jqLiteRemoveData(element, name) {
2562  var expandoId = element.ng339;
2563  var expandoStore = expandoId && jqCache[expandoId];
2564
2565  if (expandoStore) {
2566    if (name) {
2567      delete expandoStore.data[name];
2568      return;
2569    }
2570
2571    if (expandoStore.handle) {
2572      if (expandoStore.events.$destroy) {
2573        expandoStore.handle({}, '$destroy');
2574      }
2575      jqLiteOff(element);
2576    }
2577    delete jqCache[expandoId];
2578    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2579  }
2580}
2581
2582
2583function jqLiteExpandoStore(element, createIfNecessary) {
2584  var expandoId = element.ng339,
2585      expandoStore = expandoId && jqCache[expandoId];
2586
2587  if (createIfNecessary && !expandoStore) {
2588    element.ng339 = expandoId = jqNextId();
2589    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2590  }
2591
2592  return expandoStore;
2593}
2594
2595
2596function jqLiteData(element, key, value) {
2597  if (jqLiteAcceptsData(element)) {
2598
2599    var isSimpleSetter = isDefined(value);
2600    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2601    var massGetter = !key;
2602    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2603    var data = expandoStore && expandoStore.data;
2604
2605    if (isSimpleSetter) { // data('key', value)
2606      data[key] = value;
2607    } else {
2608      if (massGetter) {  // data()
2609        return data;
2610      } else {
2611        if (isSimpleGetter) { // data('key')
2612          // don't force creation of expandoStore if it doesn't exist yet
2613          return data && data[key];
2614        } else { // mass-setter: data({key1: val1, key2: val2})
2615          extend(data, key);
2616        }
2617      }
2618    }
2619  }
2620}
2621
2622function jqLiteHasClass(element, selector) {
2623  if (!element.getAttribute) return false;
2624  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2625      indexOf(" " + selector + " ") > -1);
2626}
2627
2628function jqLiteRemoveClass(element, cssClasses) {
2629  if (cssClasses && element.setAttribute) {
2630    forEach(cssClasses.split(' '), function(cssClass) {
2631      element.setAttribute('class', trim(
2632          (" " + (element.getAttribute('class') || '') + " ")
2633          .replace(/[\n\t]/g, " ")
2634          .replace(" " + trim(cssClass) + " ", " "))
2635      );
2636    });
2637  }
2638}
2639
2640function jqLiteAddClass(element, cssClasses) {
2641  if (cssClasses && element.setAttribute) {
2642    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2643                            .replace(/[\n\t]/g, " ");
2644
2645    forEach(cssClasses.split(' '), function(cssClass) {
2646      cssClass = trim(cssClass);
2647      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2648        existingClasses += cssClass + ' ';
2649      }
2650    });
2651
2652    element.setAttribute('class', trim(existingClasses));
2653  }
2654}
2655
2656
2657function jqLiteAddNodes(root, elements) {
2658  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
2659
2660  if (elements) {
2661
2662    // if a Node (the most common case)
2663    if (elements.nodeType) {
2664      root[root.length++] = elements;
2665    } else {
2666      var length = elements.length;
2667
2668      // if an Array or NodeList and not a Window
2669      if (typeof length === 'number' && elements.window !== elements) {
2670        if (length) {
2671          for (var i = 0; i < length; i++) {
2672            root[root.length++] = elements[i];
2673          }
2674        }
2675      } else {
2676        root[root.length++] = elements;
2677      }
2678    }
2679  }
2680}
2681
2682
2683function jqLiteController(element, name) {
2684  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
2685}
2686
2687function jqLiteInheritedData(element, name, value) {
2688  // if element is the document object work with the html element instead
2689  // this makes $(document).scope() possible
2690  if (element.nodeType == NODE_TYPE_DOCUMENT) {
2691    element = element.documentElement;
2692  }
2693  var names = isArray(name) ? name : [name];
2694
2695  while (element) {
2696    for (var i = 0, ii = names.length; i < ii; i++) {
2697      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2698    }
2699
2700    // If dealing with a document fragment node with a host element, and no parent, use the host
2701    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2702    // to lookup parent controllers.
2703    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
2704  }
2705}
2706
2707function jqLiteEmpty(element) {
2708  jqLiteDealoc(element, true);
2709  while (element.firstChild) {
2710    element.removeChild(element.firstChild);
2711  }
2712}
2713
2714function jqLiteRemove(element, keepData) {
2715  if (!keepData) jqLiteDealoc(element);
2716  var parent = element.parentNode;
2717  if (parent) parent.removeChild(element);
2718}
2719
2720
2721function jqLiteDocumentLoaded(action, win) {
2722  win = win || window;
2723  if (win.document.readyState === 'complete') {
2724    // Force the action to be run async for consistent behaviour
2725    // from the action's point of view
2726    // i.e. it will definitely not be in a $apply
2727    win.setTimeout(action);
2728  } else {
2729    // No need to unbind this handler as load is only ever called once
2730    jqLite(win).on('load', action);
2731  }
2732}
2733
2734//////////////////////////////////////////
2735// Functions which are declared directly.
2736//////////////////////////////////////////
2737var JQLitePrototype = JQLite.prototype = {
2738  ready: function(fn) {
2739    var fired = false;
2740
2741    function trigger() {
2742      if (fired) return;
2743      fired = true;
2744      fn();
2745    }
2746
2747    // check if document is already loaded
2748    if (document.readyState === 'complete') {
2749      setTimeout(trigger);
2750    } else {
2751      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2752      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2753      // jshint -W064
2754      JQLite(window).on('load', trigger); // fallback to window.onload for others
2755      // jshint +W064
2756    }
2757  },
2758  toString: function() {
2759    var value = [];
2760    forEach(this, function(e) { value.push('' + e);});
2761    return '[' + value.join(', ') + ']';
2762  },
2763
2764  eq: function(index) {
2765      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2766  },
2767
2768  length: 0,
2769  push: push,
2770  sort: [].sort,
2771  splice: [].splice
2772};
2773
2774//////////////////////////////////////////
2775// Functions iterating getter/setters.
2776// these functions return self on setter and
2777// value on get.
2778//////////////////////////////////////////
2779var BOOLEAN_ATTR = {};
2780forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2781  BOOLEAN_ATTR[lowercase(value)] = value;
2782});
2783var BOOLEAN_ELEMENTS = {};
2784forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2785  BOOLEAN_ELEMENTS[value] = true;
2786});
2787var ALIASED_ATTR = {
2788  'ngMinlength': 'minlength',
2789  'ngMaxlength': 'maxlength',
2790  'ngMin': 'min',
2791  'ngMax': 'max',
2792  'ngPattern': 'pattern'
2793};
2794
2795function getBooleanAttrName(element, name) {
2796  // check dom last since we will most likely fail on name
2797  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2798
2799  // booleanAttr is here twice to minimize DOM access
2800  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
2801}
2802
2803function getAliasedAttrName(element, name) {
2804  var nodeName = element.nodeName;
2805  return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
2806}
2807
2808forEach({
2809  data: jqLiteData,
2810  removeData: jqLiteRemoveData
2811}, function(fn, name) {
2812  JQLite[name] = fn;
2813});
2814
2815forEach({
2816  data: jqLiteData,
2817  inheritedData: jqLiteInheritedData,
2818
2819  scope: function(element) {
2820    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2821    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2822  },
2823
2824  isolateScope: function(element) {
2825    // Can't use jqLiteData here directly so we stay compatible with jQuery!
2826    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
2827  },
2828
2829  controller: jqLiteController,
2830
2831  injector: function(element) {
2832    return jqLiteInheritedData(element, '$injector');
2833  },
2834
2835  removeAttr: function(element, name) {
2836    element.removeAttribute(name);
2837  },
2838
2839  hasClass: jqLiteHasClass,
2840
2841  css: function(element, name, value) {
2842    name = camelCase(name);
2843
2844    if (isDefined(value)) {
2845      element.style[name] = value;
2846    } else {
2847      return element.style[name];
2848    }
2849  },
2850
2851  attr: function(element, name, value) {
2852    var lowercasedName = lowercase(name);
2853    if (BOOLEAN_ATTR[lowercasedName]) {
2854      if (isDefined(value)) {
2855        if (!!value) {
2856          element[name] = true;
2857          element.setAttribute(name, lowercasedName);
2858        } else {
2859          element[name] = false;
2860          element.removeAttribute(lowercasedName);
2861        }
2862      } else {
2863        return (element[name] ||
2864                 (element.attributes.getNamedItem(name) || noop).specified)
2865               ? lowercasedName
2866               : undefined;
2867      }
2868    } else if (isDefined(value)) {
2869      element.setAttribute(name, value);
2870    } else if (element.getAttribute) {
2871      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2872      // some elements (e.g. Document) don't have get attribute, so return undefined
2873      var ret = element.getAttribute(name, 2);
2874      // normalize non-existing attributes to undefined (as jQuery)
2875      return ret === null ? undefined : ret;
2876    }
2877  },
2878
2879  prop: function(element, name, value) {
2880    if (isDefined(value)) {
2881      element[name] = value;
2882    } else {
2883      return element[name];
2884    }
2885  },
2886
2887  text: (function() {
2888    getText.$dv = '';
2889    return getText;
2890
2891    function getText(element, value) {
2892      if (isUndefined(value)) {
2893        var nodeType = element.nodeType;
2894        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
2895      }
2896      element.textContent = value;
2897    }
2898  })(),
2899
2900  val: function(element, value) {
2901    if (isUndefined(value)) {
2902      if (element.multiple && nodeName_(element) === 'select') {
2903        var result = [];
vendor: 3,900 bytes, lines 2904-3033
2904        forEach(element.options, function(option) {
2905          if (option.selected) {
2906            result.push(option.value || option.text);
2907          }
2908        });
2909        return result.length === 0 ? null : result;
2910      }
2911      return element.value;
2912    }
2913    element.value = value;
2914  },
2915
2916  html: function(element, value) {
2917    if (isUndefined(value)) {
2918      return element.innerHTML;
2919    }
2920    jqLiteDealoc(element, true);
2921    element.innerHTML = value;
2922  },
2923
2924  empty: jqLiteEmpty
2925}, function(fn, name) {
2926  /**
2927   * Properties: writes return selection, reads return first value
2928   */
2929  JQLite.prototype[name] = function(arg1, arg2) {
2930    var i, key;
2931    var nodeCount = this.length;
2932
2933    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2934    // in a way that survives minification.
2935    // jqLiteEmpty takes no arguments but is a setter.
2936    if (fn !== jqLiteEmpty &&
2937        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2938      if (isObject(arg1)) {
2939
2940        // we are a write, but the object properties are the key/values
2941        for (i = 0; i < nodeCount; i++) {
2942          if (fn === jqLiteData) {
2943            // data() takes the whole object in jQuery
2944            fn(this[i], arg1);
2945          } else {
2946            for (key in arg1) {
2947              fn(this[i], key, arg1[key]);
2948            }
2949          }
2950        }
2951        // return self for chaining
2952        return this;
2953      } else {
2954        // we are a read, so read the first child.
2955        // TODO: do we still need this?
2956        var value = fn.$dv;
2957        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2958        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
2959        for (var j = 0; j < jj; j++) {
2960          var nodeValue = fn(this[j], arg1, arg2);
2961          value = value ? value + nodeValue : nodeValue;
2962        }
2963        return value;
2964      }
2965    } else {
2966      // we are a write, so apply to all children
2967      for (i = 0; i < nodeCount; i++) {
2968        fn(this[i], arg1, arg2);
2969      }
2970      // return self for chaining
2971      return this;
2972    }
2973  };
2974});
2975
2976function createEventHandler(element, events) {
2977  var eventHandler = function(event, type) {
2978    // jQuery specific api
2979    event.isDefaultPrevented = function() {
2980      return event.defaultPrevented;
2981    };
2982
2983    var eventFns = events[type || event.type];
2984    var eventFnsLength = eventFns ? eventFns.length : 0;
2985
2986    if (!eventFnsLength) return;
2987
2988    if (isUndefined(event.immediatePropagationStopped)) {
2989      var originalStopImmediatePropagation = event.stopImmediatePropagation;
2990      event.stopImmediatePropagation = function() {
2991        event.immediatePropagationStopped = true;
2992
2993        if (event.stopPropagation) {
2994          event.stopPropagation();
2995        }
2996
2997        if (originalStopImmediatePropagation) {
2998          originalStopImmediatePropagation.call(event);
2999        }
3000      };
3001    }
3002
3003    event.isImmediatePropagationStopped = function() {
3004      return event.immediatePropagationStopped === true;
3005    };
3006
3007    // Copy event handlers in case event handlers array is modified during execution.
3008    if ((eventFnsLength > 1)) {
3009      eventFns = shallowCopy(eventFns);
3010    }
3011
3012    for (var i = 0; i < eventFnsLength; i++) {
3013      if (!event.isImmediatePropagationStopped()) {
3014        eventFns[i].call(element, event);
3015      }
3016    }
3017  };
3018
3019  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3020  //       events on `element`
3021  eventHandler.elem = element;
3022  return eventHandler;
3023}
3024
3025//////////////////////////////////////////
3026// Functions iterating traversal.
3027// These functions chain results into a single
3028// selector.
3029//////////////////////////////////////////
3030forEach({
3031  removeData: jqLiteRemoveData,
3032
3033  on: function jqLiteOn(element, type, fn, unsupported) {
3034    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3035
3036    // Do not add event handlers to non-elements because they will not be cleaned up.
3037    if (!jqLiteAcceptsData(element)) {
3038      return;
3039    }
3040
3041    var expandoStore = jqLiteExpandoStore(element, true);
3042    var events = expandoStore.events;
3043    var handle = expandoStore.handle;
3044
3045    if (!handle) {
3046      handle = expandoStore.handle = createEventHandler(element, events);
3047    }
3048
3049    // http://jsperf.com/string-indexof-vs-split
3050    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3051    var i = types.length;
3052
3053    while (i--) {
3054      type = types[i];
3055      var eventFns = events[type];
3056
3057      if (!eventFns) {
3058        events[type] = [];
3059
3060        if (type === 'mouseenter' || type === 'mouseleave') {
3061          // Refer to jQuery's implementation of mouseenter & mouseleave
3062          // Read about mouseenter and mouseleave:
3063          // http://www.quirksmode.org/js/events_mouse.html#link8
3064
3065          jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
3066            var target = this, related = event.relatedTarget;
3067            // For mousenter/leave call the handler if related is outside the target.
3068            // NB: No relatedTarget if the mouse left/entered the browser window
3069            if (!related || (related !== target && !target.contains(related))) {
3070              handle(event, type);
3071            }
3072          });
3073
3074        } else {
3075          if (type !== '$destroy') {
3076            addEventListenerFn(element, type, handle);
3077          }
3078        }
3079        eventFns = events[type];
3080      }
3081      eventFns.push(fn);
3082    }
3083  },
3084
3085  off: jqLiteOff,
3086
3087  one: function(element, type, fn) {
3088    element = jqLite(element);
3089
3090    //add the listener twice so that when it is called
3091    //you can remove the original function and still be
3092    //able to call element.off(ev, fn) normally
3093    element.on(type, function onFn() {
3094      element.off(type, fn);
3095      element.off(type, onFn);
3096    });
3097    element.on(type, fn);
3098  },
3099
3100  replaceWith: function(element, replaceNode) {
3101    var index, parent = element.parentNode;
3102    jqLiteDealoc(element);
3103    forEach(new JQLite(replaceNode), function(node) {
3104      if (index) {
3105        parent.insertBefore(node, index.nextSibling);
3106      } else {
3107        parent.replaceChild(node, element);
3108      }
3109      index = node;
3110    });
3111  },
3112
3113  children: function(element) {
3114    var children = [];
3115    forEach(element.childNodes, function(element) {
3116      if (element.nodeType === NODE_TYPE_ELEMENT)
3117        children.push(element);
3118    });
3119    return children;
3120  },
3121
3122  contents: function(element) {
3123    return element.contentDocument || element.childNodes || [];
3124  },
3125
3126  append: function(element, node) {
3127    var nodeType = element.nodeType;
3128    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3129
3130    node = new JQLite(node);
3131
3132    for (var i = 0, ii = node.length; i < ii; i++) {
3133      var child = node[i];
3134      element.appendChild(child);
3135    }
3136  },
3137
3138  prepend: function(element, node) {
3139    if (element.nodeType === NODE_TYPE_ELEMENT) {
3140      var index = element.firstChild;
3141      forEach(new JQLite(node), function(child) {
3142        element.insertBefore(child, index);
3143      });
3144    }
3145  },
3146
3147  wrap: function(element, wrapNode) {
3148    wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3149    var parent = element.parentNode;
3150    if (parent) {
3151      parent.replaceChild(wrapNode, element);
3152    }
3153    wrapNode.appendChild(element);
3154  },
3155
3156  remove: jqLiteRemove,
3157
3158  detach: function(element) {
3159    jqLiteRemove(element, true);
3160  },
3161
3162  after: function(element, newElement) {
3163    var index = element, parent = element.parentNode;
3164    newElement = new JQLite(newElement);
3165
3166    for (var i = 0, ii = newElement.length; i < ii; i++) {
3167      var node = newElement[i];
3168      parent.insertBefore(node, index.nextSibling);
3169      index = node;
3170    }
3171  },
3172
3173  addClass: jqLiteAddClass,
3174  removeClass: jqLiteRemoveClass,
3175
3176  toggleClass: function(element, selector, condition) {
3177    if (selector) {
vendor: 5,344 bytes, lines 3178-3373
3178      forEach(selector.split(' '), function(className) {
3179        var classCondition = condition;
3180        if (isUndefined(classCondition)) {
3181          classCondition = !jqLiteHasClass(element, className);
3182        }
3183        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3184      });
3185    }
3186  },
3187
3188  parent: function(element) {
3189    var parent = element.parentNode;
3190    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3191  },
3192
3193  next: function(element) {
3194    return element.nextElementSibling;
3195  },
3196
3197  find: function(element, selector) {
3198    if (element.getElementsByTagName) {
3199      return element.getElementsByTagName(selector);
3200    } else {
3201      return [];
3202    }
3203  },
3204
3205  clone: jqLiteClone,
3206
3207  triggerHandler: function(element, event, extraParameters) {
3208
3209    var dummyEvent, eventFnsCopy, handlerArgs;
3210    var eventName = event.type || event;
3211    var expandoStore = jqLiteExpandoStore(element);
3212    var events = expandoStore && expandoStore.events;
3213    var eventFns = events && events[eventName];
3214
3215    if (eventFns) {
3216      // Create a dummy event to pass to the handlers
3217      dummyEvent = {
3218        preventDefault: function() { this.defaultPrevented = true; },
3219        isDefaultPrevented: function() { return this.defaultPrevented === true; },
3220        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3221        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3222        stopPropagation: noop,
3223        type: eventName,
3224        target: element
3225      };
3226
3227      // If a custom event was provided then extend our dummy event with it
3228      if (event.type) {
3229        dummyEvent = extend(dummyEvent, event);
3230      }
3231
3232      // Copy event handlers in case event handlers array is modified during execution.
3233      eventFnsCopy = shallowCopy(eventFns);
3234      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3235
3236      forEach(eventFnsCopy, function(fn) {
3237        if (!dummyEvent.isImmediatePropagationStopped()) {
3238          fn.apply(element, handlerArgs);
3239        }
3240      });
3241    }
3242  }
3243}, function(fn, name) {
3244  /**
3245   * chaining functions
3246   */
3247  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3248    var value;
3249
3250    for (var i = 0, ii = this.length; i < ii; i++) {
3251      if (isUndefined(value)) {
3252        value = fn(this[i], arg1, arg2, arg3);
3253        if (isDefined(value)) {
3254          // any function which returns a value needs to be wrapped
3255          value = jqLite(value);
3256        }
3257      } else {
3258        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3259      }
3260    }
3261    return isDefined(value) ? value : this;
3262  };
3263
3264  // bind legacy bind/unbind to on/off
3265  JQLite.prototype.bind = JQLite.prototype.on;
3266  JQLite.prototype.unbind = JQLite.prototype.off;
3267});
3268
3269
3270// Provider for private $$jqLite service
3271function $$jqLiteProvider() {
3272  this.$get = function $$jqLite() {
3273    return extend(JQLite, {
3274      hasClass: function(node, classes) {
3275        if (node.attr) node = node[0];
3276        return jqLiteHasClass(node, classes);
3277      },
3278      addClass: function(node, classes) {
3279        if (node.attr) node = node[0];
3280        return jqLiteAddClass(node, classes);
3281      },
3282      removeClass: function(node, classes) {
3283        if (node.attr) node = node[0];
3284        return jqLiteRemoveClass(node, classes);
3285      }
3286    });
3287  };
3288}
3289
3290/**
3291 * Computes a hash of an 'obj'.
3292 * Hash of a:
3293 *  string is string
3294 *  number is number as string
3295 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3296 *         that is also assigned to the $$hashKey property of the object.
3297 *
3298 * @param obj
3299 * @returns {string} hash string such that the same input will have the same hash string.
3300 *         The resulting string key is in 'type:hashKey' format.
3301 */
3302function hashKey(obj, nextUidFn) {
3303  var key = obj && obj.$$hashKey;
3304
3305  if (key) {
3306    if (typeof key === 'function') {
3307      key = obj.$$hashKey();
3308    }
3309    return key;
3310  }
3311
3312  var objType = typeof obj;
3313  if (objType == 'function' || (objType == 'object' && obj !== null)) {
3314    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3315  } else {
3316    key = objType + ':' + obj;
3317  }
3318
3319  return key;
3320}
3321
3322/**
3323 * HashMap which can use objects as keys
3324 */
3325function HashMap(array, isolatedUid) {
3326  if (isolatedUid) {
3327    var uid = 0;
3328    this.nextUid = function() {
3329      return ++uid;
3330    };
3331  }
3332  forEach(array, this.put, this);
3333}
3334HashMap.prototype = {
3335  /**
3336   * Store key value pair
3337   * @param key key to store can be any type
3338   * @param value value to store can be any type
3339   */
3340  put: function(key, value) {
3341    this[hashKey(key, this.nextUid)] = value;
3342  },
3343
3344  /**
3345   * @param key
3346   * @returns {Object} the value for the key
3347   */
3348  get: function(key) {
3349    return this[hashKey(key, this.nextUid)];
3350  },
3351
3352  /**
3353   * Remove the key/value pair
3354   * @param key
3355   */
3356  remove: function(key) {
3357    var value = this[key = hashKey(key, this.nextUid)];
3358    delete this[key];
3359    return value;
3360  }
3361};
3362
3363/**
3364 * @ngdoc function
3365 * @module ng
3366 * @name angular.injector
3367 * @kind function
3368 *
3369 * @description
3370 * Creates an injector object that can be used for retrieving services as well as for
3371 * dependency injection (see {@link guide/di dependency injection}).
3372 *
3373 * @param {Array.<string|Function>}
3373 modules A list of module functions or their aliases. See
3374 *     {@link angular.module}. The `ng` module must be explicitly added.
3375 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3376 *     disallows argument name annotation inference.
3377 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3378 *
3379 * @example
3380 * Typical usage
3381 * ```js
3382 *   // create an injector
3383 *   var $injector = angular.injector(['ng']);
3384 *
3385 *   // use the injector to kick off your application
3386 *   // use the type inference to auto inject arguments, or use implicit injection
3387 *   $injector.invoke(function($rootScope, $compile, $document) {
3388 *     $compile($document)($rootScope);
3389 *     $rootScope.$digest();
3390 *   });
3391 * ```
3392 *
3393 * Sometimes you want to get access to the injector of a currently running Angular app
3394 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3395 * application has been bootstrapped. You can do this using the extra `injector()` added
3396 * to JQuery/jqLite elements. See {@link angular.element}.
3397 *
3398 * *This is fairly rare but could be the case if a third party library is injecting the
3399 * markup.*
3400 *
3401 * In the following example a new block of HTML containing a `ng-controller`
3402 * directive is added to the end of the document body by JQuery. We then compile and link
3403 * it into the current AngularJS scope.
3404 *
3405 * ```js
3406 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3407 * $(document.body).append($div);
3408 *
3409 * angular.element(document).injector().invoke(function($compile) {
3410 *   var scope = angular.element($div).scope();
3411 *   $compile($div)(scope);
3412 * });
3413 * ```
3414 */
3415
3416
3417/**
3418 * @ngdoc module
3419 * @name auto
3420 * @description
3421 *
3422 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3423 */
3424
3425var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3426var FN_ARG_SPLIT = /,/;
3427var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3428var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3429var $injectorMinErr = minErr('$injector');
3430
3431function anonFn(fn) {
3432  // For anonymous functions, showing at the very least the function signature can help in
3433  // debugging.
3434  var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3435      args = fnText.match(FN_ARGS);
3436  if (args) {
3437    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3438  }
3439  return 'fn';
3440}
3441
3442function annotate(fn, strictDi, name) {
3443  var $inject,
3444      fnText,
3445      argDecl,
3446      last;
3447
3448  if (typeof fn === 'function') {
3449    if (!($inject = fn.$inject)) {
3450      $inject = [];
3451      if (fn.length) {
3452        if (strictDi) {
3453          if (!isString(name) || !name) {
3454            name = fn.name || anonFn(fn);
3455          }
3456          throw $injectorMinErr('strictdi',
3457            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3458        }
3459        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3460        argDecl = fnText.match(FN_ARGS);
3461        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3462          arg.replace(FN_ARG, function(all, underscore, name) {
3463            $inject.push(name);
3464          });
3465        });
3466      }
3467      fn.$inject = $inject;
3468    }
3469  } else if (isArray(fn)) {
3470    last = fn.length - 1;
3471    assertArgFn(fn[last], 'fn');
3472    $inject = fn.slice(0, last);
3473  } else {
3474    assertArgFn(fn, 'fn', true);
3475  }
3476  return $inject;
3477}
3478
3479///////////////////////////////////////
3480
3481/**
3482 * @ngdoc service
3483 * @name $injector
3484 *
3485 * @description
3486 *
3487 * `$injector` is used to retrieve object instances as defined by
3488 * {@link auto.$provide provider}, instantiate types, invoke methods,
3489 * and load modules.
3490 *
3491 * The following always holds true:
3492 *
3493 * ```js
3494 *   var $injector = angular.injector();
3495 *   expect($injector.get('$injector')).toBe($injector);
3496 *   expect($injector.invoke(function($injector) {
3497 *     return $injector;
3498 *   })).toBe($injector);
3499 * ```
3500 *
3501 * # Injection Function Annotation
3502 *
3503 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3504 * following are all valid ways of annotating function with injection arguments and are equivalent.
3505 *
3506 * ```js
3507 *   // inferred (only works if code not minified/obfuscated)
3508 *   $injector.invoke(function(serviceA){});
3509 *
3510 *   // annotated
3511 *   function explicit(serviceA) {};
3512 *   explicit.$inject = ['serviceA'];
3513 *   $injector.invoke(explicit);
3514 *
3515 *   // inline
3516 *   $injector.invoke(['serviceA', function(serviceA){}]);
3517 * ```
3518 *
3519 * ## Inference
3520 *
3521 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3522 * can then be parsed and the function arguments can be extracted. This method of discovering
3523 * annotations is disallowed when the injector is in strict mode.
3524 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3525 * argument names.
3526 *
3527 * ## `$inject` Annotation
3528 * By adding an `$inject` property onto a function the injection parameters can be specified.
3529 *
3530 * ## Inline
3531 * As an array of injection names, where the last item in the array is the function to call.
3532 */
3533
3534/**
3535 * @ngdoc method
3536 * @name $injector#get
3537 *
3538 * @description
3539 * Return an instance of the service.
3540 *
3541 * @param {string} name The name of the instance to retrieve.
3542 * @param {string} caller An optional string to provide the origin of the function call for error messages.
3543 * @return {*} The instance.
3544 */
3545
3546/**
3547 * @ngdoc method
3548 * @name $injector#invoke
3549 *
3550 * @description
3551 * Invoke the method and supply the method arguments from the `$injector`.
3552 *
3553 * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3554 *   {@link guide/di $inject Annotation} rules.
3555 * @param {Object=} self The `this` for the invoked method.
3556 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3557 *                         object first, before the `$injector` is consulted.
3558 * @returns {*} the value returned by the invoked `fn` function.
3559 */
3560
3561/**
3562 * @ngdoc method
3563 * @name $injector#has
3564 *
3565 * @description
3566 * Allows the user to query if the particular service exists.
3567 *
3568 * @param {string} name Name of the service to query.
3569 * @returns {boolean} `true` if injector has given service.
3570 */
3571
3572/**
3573 * @ngdoc method
3574 * @name $injector#instantiate
3575 * @description
3576 * Create a new instance of JS type. The method takes a constructor function, invokes the new
3577 * operator, and supplies all of the arguments to the constructor function as specified by the
3578 * constructor annotation.
3579 *
3580 * @param {Function} Type Annotated constructor function.
3581 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3582 * object first, before the `$injector` is consulted.
3583 * @returns {Object} new instance of `Type`.
3584 */
3585
3586/**
3587 * @ngdoc method
3588 * @name $injector#annotate
3589 *
3590 * @description
3591 * Returns an array of service names which the function is requesting for injection. This API is
3592 * used by the injector to determine which services need to be injected into the function when the
3593 * function is invoked. There are three ways in which the function can be annotated with the needed
3594 * dependencies.
3595 *
3596 * # Argument names
3597 *
3598 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3599 * by converting the function into a string using `toString()` method and extracting the argument
3600 * names.
3601 * ```js
3602 *   // Given
3603 *   function MyController($scope, $route) {
3604 *     // ...
3605 *   }
3606 *
3607 *   // Then
3608 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3609 * ```
3610 *
3611 * You can disallow this method by using strict injection mode.
3612 *
3613 * This method does not work with code minification / obfuscation. For this reason the following
3614 * annotation strategies are supported.
3615 *
3616 * # The `$inject` property
3617 *
3618 * If a function has an `$inject` property and its value is an array of strings, then the strings
3619 * represent names of services to be injected into the function.
3620 * ```js
3621 *   // Given
3622 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3623 *     // ...
3624 *   }
3625 *   // Define function dependencies
3626 *   MyController['$inject'] = ['$scope', '$route'];
3627 *
3628 *   // Then
3629 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3630 * ```
3631 *
3632 * # The array notation
3633 *
3634 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3635 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3636 * a way that survives minification is a better choice:
3637 *
3638 * ```js
3639 *   // We wish to write this (not minification / obfuscation safe)
3640 *   injector.invoke(function($compile, $rootScope) {
3641 *     // ...
3642 *   });
3643 *
3644 *   // We are forced to write break inlining
3645 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3646 *     // ...
3647 *   };
3648 *   tmpFn.$inject = ['$compile', '$rootScope'];
3649 *   injector.invoke(tmpFn);
3650 *
3651 *   // To better support inline function the inline annotation is supported
3652 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3653 *     // ...
3654 *   }]);
3655 *
3656 *   // Therefore
3657 *   expect(injector.annotate(
3658 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3659 *    ).toEqual(['$compile', '$rootScope']);
3660 * ```
3661 *
3662 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3663 * be retrieved as described above.
3664 *
3665 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3666 *
3667 * @returns {Array.<string>} The names of the services which the function requires.
3668 */
3669
3670
3671
3672
3673/**
3674 * @ngdoc service
3675 * @name $provide
3676 *
3677 * @description
3678 *
3679 * The {@link auto.$provide $provide} service has a number of methods for registering components
3680 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3681 * {@link angular.Module}.
3682 *
3683 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3684 * factories** are functions which, in turn, are created by a **service provider**.
3685 * The **service providers** are constructor functions. When instantiated they must contain a
3686 * property called `$get`, which holds the **service factory** function.
3687 *
3688 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3689 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3690 * function to get the instance of the **service**.
3691 *
3692 * Often services have no configuration options and there is no need to add methods to the service
3693 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3694 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3695 * services without specifying a provider.
3696 *
3697 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3698 *     {@link auto.$injector $injector}
3699 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3700 *     providers and services.
3701 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3702 *     services, not providers.
3703 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3704 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3705 *     given factory function.
3706 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3707 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3708 *      a new object using the given constructor function.
3709 *
3710 * See the individual methods for more information and examples.
3711 */
3712
3713/**
3714 * @ngdoc method
3715 * @name $provide#provider
3716 * @description
3717 *
3718 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3719 * are constructor functions, whose instances are responsible for "providing" a factory for a
3720 * service.
3721 *
3722 * Service provider names start with the name of the service they provide followed by `Provider`.
3723 * For example, the {@link ng.$log $log} service has a provider called
3724 * {@link ng.$logProvider $logProvider}.
3725 *
3726 * Service provider objects can have additional methods which allow configuration of the provider
3727 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3728 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3729 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3730 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3731 * console or not.
3732 *
3733 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3734                        'Provider'` key.
3735 * @param {(Object|function())} provider If the provider is:
3736 *
3737 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3738 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3739 *   - `Constructor`: a new instance of the provider will be created using
3740 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3741 *
3742 * @returns {Object} registered provider instance
3743
3744 * @example
3745 *
3746 * The following example shows how to create a simple event tracking service and register it using
3747 * {@link auto.$provide#provider $provide.provider()}.
3748 *
3749 * ```js
3750 *  // Define the eventTracker provider
3751 *  function EventTrackerProvider() {
3752 *    var trackingUrl = '/track';
3753 *
3754 *    // A provider method for configuring where the tracked events should been saved
3755 *    this.setTrackingUrl = function(url) {
3756 *      trackingUrl = url;
3757 *    };
3758 *
3759 *    // The service factory function
3760 *    this.$get = ['$http', function($http) {
3761 *      var trackedEvents = {};
3762 *      return {
3763 *        // Call this to track an event
3764 *        event: function(event) {
3765 *          var count = trackedEvents[event] || 0;
3766 *          count += 1;
3767 *          trackedEvents[event] = count;
3768 *          return count;
3769 *        },
3770 *        // Call this to save the tracked events to the trackingUrl
3771 *        save: function() {
3772 *          $http.post(trackingUrl, trackedEvents);
3773 *        }
3774 *      };
3775 *    }];
3776 *  }
3777 *
3778 *  describe('eventTracker', function() {
3779 *    var postSpy;
3780 *
3781 *    beforeEach(module(function($provide) {
3782 *      // Register the eventTracker provider
3783 *      $provide.provider('eventTracker', EventTrackerProvider);
3784 *    }));
3785 *
3786 *    beforeEach(module(function(eventTrackerProvider) {
3787 *      // Configure eventTracker provider
3788 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3789 *    }));
3790 *
3791 *    it('tracks events', inject(function(eventTracker) {
3792 *      expect(eventTracker.event('login')).toEqual(1);
3793 *      expect(eventTracker.event('login')).toEqual(2);
3794 *    }));
3795 *
3796 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3797 *      postSpy = spyOn($http, 'post');
3798 *      eventTracker.event('login');
3799 *      eventTracker.save();
3800 *      expect(postSpy).toHaveBeenCalled();
3801 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3802 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3803 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3804 *    }));
3805 *  });
3806 * ```
3807 */
3808
3809/**
3810 * @ngdoc method
3811 * @name $provide#factory
3812 * @description
3813 *
3814 * Register a **service factory**, which will be called to return the service instance.
3815 * This is short for registering a service where its provider consists of only a `$get` property,
3816 * which is the given service factory function.
3817 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3818 * configure your service in a provider.
3819 *
3820 * @param {string} name The name of the instance.
3821 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3822 *                            for `$provide.provider(name, {$get: $getFn})`.
3823 * @returns {Object} registered provider instance
3824 *
3825 * @example
3826 * Here is an example of registering a service
3827 * ```js
3828 *   $provide.factory('ping', ['$http', function($http) {
3829 *     return function ping() {
3830 *       return $http.send('/ping');
3831 *     };
3832 *   }]);
3833 * ```
3834 * You would then inject and use this service like this:
3835 * ```js
3836 *   someModule.controller('Ctrl', ['ping', function(ping) {
3837 *     ping();
3838 *   }]);
3839 * ```
3840 */
3841
3842
3843/**
3844 * @ngdoc method
3845 * @name $provide#service
3846 * @description
3847 *
3848 * Register a **service constructor**, which will be invoked with `new` to create the service
3849 * instance.
3850 * This is short for registering a service where its provider's `$get` property is the service
3851 * constructor function that will be used to instantiate the service instance.
3852 *
3853 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3854 * as a type/class.
3855 *
3856 * @param {string} name The name of the instance.
3857 * @param {Function} constructor A class (constructor function) that will be instantiated.
3858 * @returns {Object} registered provider instance
3859 *
3860 * @example
3861 * Here is an example of registering a service using
3862 * {@link auto.$provide#service $provide.service(class)}.
3863 * ```js
3864 *   var Ping = function($http) {
3865 *     this.$http = $http;
3866 *   };
3867 *
3868 *   Ping.$inject = ['$http'];
3869 *
3870 *   Ping.prototype.send = function() {
3871 *     return this.$http.get('/ping');
3872 *   };
3873 *   $provide.service('ping', Ping);
3874 * ```
3875 * You would then inject and use this service like this:
3876 * ```js
3877 *   someModule.controller('Ctrl', ['ping', function(ping) {
3878 *     ping.send();
3879 *   }]);
3880 * ```
3881 */
3882
3883
3884/**
3885 * @ngdoc method
3886 * @name $provide#value
3887 * @description
3888 *
3889 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3890 * number, an array, an object or a function.  This is short for registering a service where its
3891 * provider's `$get` property is a factory function that takes no arguments and returns the **value
3892 * service**.
3893 *
3894 * Value services are similar to constant services, except that they cannot be injected into a
3895 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3896 * an Angular
3897 * {@link auto.$provide#decorator decorator}.
3898 *
3899 * @param {string} name The name of the instance.
3900 * @param {*} value The value.
3901 * @returns {Object} registered provider instance
3902 *
3903 * @example
3904 * Here are some examples of creating value services.
3905 * ```js
3906 *   $provide.value('ADMIN_USER', 'admin');
3907 *
3908 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3909 *
3910 *   $provide.value('halfOf', function(value) {
3911 *     return value / 2;
3912 *   });
3913 * ```
3914 */
3915
3916
3917/**
3918 * @ngdoc method
3919 * @name $provide#constant
3920 * @description
3921 *
3922 * Register a **constant service**, such as a string, a number, an array, an object or a function,
3923 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3924 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3925 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3926 *
3927 * @param {string} name The name of the constant.
3928 * @param {*} value The constant value.
3929 * @returns {Object} registered instance
3930 *
3931 * @example
3932 * Here a some examples of creating constants:
3933 * ```js
3934 *   $provide.constant('SHARD_HEIGHT', 306);
3935 *
3936 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3937 *
3938 *   $provide.constant('double', function(value) {
3939 *     return value * 2;
3940 *   });
3941 * ```
3942 */
3943
3944
3945/**
3946 * @ngdoc method
3947 * @name $provide#decorator
3948 * @description
3949 *
3950 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3951 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3952 * service. The object returned by the decorator may be the original service, or a new service
3953 * object which replaces or wraps and delegates to the original service.
3954 *
3955 * @param {string} name The name of the service to decorate.
3956 * @param {function()} decorator This function will be invoked when the service needs to be
3957 *    instantiated and should return the decorated service instance. The function is called using
3958 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3959 *    Local injection arguments:
3960 *
3961 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3962 *      decorated or delegated to.
3963 *
3964 * @example
3965 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3966 * calls to {@link ng.$log#error $log.warn()}.
3967 * ```js
3968 *   $provide.decorator('$log', ['$delegate', function($delegate) {
3969 *     $delegate.warn = $delegate.error;
3970 *     return $delegate;
3971 *   }]);
3972 * ```
3973 */
3974
3975
3976function createInjector(modulesToLoad, strictDi) {
3977  strictDi = (strictDi === true);
3978  var INSTANTIATING = {},
3979      providerSuffix = 'Provider',
3980      path = [],
3981      loadedModules = new HashMap([], true),
3982      providerCache = {
3983        $provide: {
3984            provider: supportObject(provider),
3985            factory: supportObject(factory),
3986            service: supportObject(service),
3987            value: supportObject(value),
3988            constant: supportObject(constant),
3989            decorator: decorator
3990          }
3991      },
3992      providerInjector = (providerCache.$injector =
3993          createInternalInjector(providerCache, function(serviceName, caller) {
3994            if (angular.isString(caller)) {
3995              path.push(caller);
3996            }
3997            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3998          })),
3999      instanceCache = {},
4000      instanceInjector = (instanceCache.$injector =
4001          createInternalInjector(instanceCache, function(serviceName, caller) {
4002            var provider = providerInjector.get(serviceName + providerSuffix, caller);
4003            return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4004          }));
4005
4006
4007  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
4008
4009  return instanceInjector;
4010
4011  ////////////////////////////////////
4012  // $provider
4013  ////////////////////////////////////
4014
4015  function supportObject(delegate) {
4016    return function(key, value) {
4017      if (isObject(key)) {
4018        forEach(key, reverseParams(delegate));
4019      } else {
4020        return delegate(key, value);
4021      }
4022    };
4023  }
4024
4025  function provider(name, provider_) {
4026    assertNotHasOwnProperty(name, 'service');
4027    if (isFunction(provider_) || isArray(provider_)) {
4028      provider_ = providerInjector.instantiate(provider_);
4029    }
4030    if (!provider_.$get) {
4031      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4032    }
4033    return providerCache[name + providerSuffix] = provider_;
4034  }
4035
4036  function enforceReturnValue(name, factory) {
4037    return function enforcedReturnValue() {
4038      var result = instanceInjector.invoke(factory, this);
4039      if (isUndefined(result)) {
4040        throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4041      }
4042      return result;
4043    };
4044  }
4045
4046  function factory(name, factoryFn, enforce) {
4047    return provider(name, {
4048      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4049    });
4050  }
4051
4052  function service(name, constructor) {
4053    return factory(name, ['$injector', function($injector) {
4054      return $injector.instantiate(constructor);
4055    }]);
4056  }
4057
4058  function value(name, val) { return factory(name, valueFn(val), false); }
4059
4060  function constant(name, value) {
4061    assertNotHasOwnProperty(name, 'constant');
4062    providerCache[name] = value;
4063    instanceCache[name] = value;
4064  }
4065
4066  function decorator(serviceName, decorFn) {
4067    var origProvider = providerInjector.get(serviceName + providerSuffix),
4068        orig$get = origProvider.$get;
4069
4070    origProvider.$get = function() {
4071      var origInstance = instanceInjector.invoke(orig$get, origProvider);
4072      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4073    };
4074  }
4075
4076  ////////////////////////////////////
4077  // Module Loading
4078  ////////////////////////////////////
4079  function loadModules(modulesToLoad) {
4080    var runBlocks = [], moduleFn;
vendor: 5,290 bytes, lines 4081-4238
4081    forEach(modulesToLoad, function(module) {
4082      if (loadedModules.get(module)) return;
4083      loadedModules.put(module, true);
4084
4085      function runInvokeQueue(queue) {
4086        var i, ii;
4087        for (i = 0, ii = queue.length; i < ii; i++) {
4088          var invokeArgs = queue[i],
4089              provider = providerInjector.get(invokeArgs[0]);
4090
4091          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4092        }
4093      }
4094
4095      try {
4096        if (isString(module)) {
4097          moduleFn = angularModule(module);
4098          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4099          runInvokeQueue(moduleFn._invokeQueue);
4100          runInvokeQueue(moduleFn._configBlocks);
4101        } else if (isFunction(module)) {
4102            runBlocks.push(providerInjector.invoke(module));
4103        } else if (isArray(module)) {
4104            runBlocks.push(providerInjector.invoke(module));
4105        } else {
4106          assertArgFn(module, 'module');
4107        }
4108      } catch (e) {
4109        if (isArray(module)) {
4110          module = module[module.length - 1];
4111        }
4112        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4113          // Safari & FF's stack traces don't contain error.message content
4114          // unlike those of Chrome and IE
4115          // So if stack doesn't contain message, we create a new string that contains both.
4116          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4117          /* jshint -W022 */
4118          e = e.message + '\n' + e.stack;
4119        }
4120        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4121                  module, e.stack || e.message || e);
4122      }
4123    });
4124    return runBlocks;
4125  }
4126
4127  ////////////////////////////////////
4128  // internal Injector
4129  ////////////////////////////////////
4130
4131  function createInternalInjector(cache, factory) {
4132
4133    function getService(serviceName, caller) {
4134      if (cache.hasOwnProperty(serviceName)) {
4135        if (cache[serviceName] === INSTANTIATING) {
4136          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4137                    serviceName + ' <- ' + path.join(' <- '));
4138        }
4139        return cache[serviceName];
4140      } else {
4141        try {
4142          path.unshift(serviceName);
4143          cache[serviceName] = INSTANTIATING;
4144          return cache[serviceName] = factory(serviceName, caller);
4145        } catch (err) {
4146          if (cache[serviceName] === INSTANTIATING) {
4147            delete cache[serviceName];
4148          }
4149          throw err;
4150        } finally {
4151          path.shift();
4152        }
4153      }
4154    }
4155
4156    function invoke(fn, self, locals, serviceName) {
4157      if (typeof locals === 'string') {
4158        serviceName = locals;
4159        locals = null;
4160      }
4161
4162      var args = [],
4163          $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4164          length, i,
4165          key;
4166
4167      for (i = 0, length = $inject.length; i < length; i++) {
4168        key = $inject[i];
4169        if (typeof key !== 'string') {
4170          throw $injectorMinErr('itkn',
4171                  'Incorrect injection token! Expected service name as string, got {0}', key);
4172        }
4173        args.push(
4174          locals && locals.hasOwnProperty(key)
4175          ? locals[key]
4176          : getService(key, serviceName)
4177        );
4178      }
4179      if (isArray(fn)) {
4180        fn = fn[length];
4181      }
4182
4183      // http://jsperf.com/angularjs-invoke-apply-vs-switch
4184      // #5388
4185      return fn.apply(self, args);
4186    }
4187
4188    function instantiate(Type, locals, serviceName) {
4189      // Check if Type is annotated and use just the given function at n-1 as parameter
4190      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4191      // Object creation: http://jsperf.com/create-constructor/2
4192      var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4193      var returnedValue = invoke(Type, instance, locals, serviceName);
4194
4195      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4196    }
4197
4198    return {
4199      invoke: invoke,
4200      instantiate: instantiate,
4201      get: getService,
4202      annotate: createInjector.$$annotate,
4203      has: function(name) {
4204        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4205      }
4206    };
4207  }
4208}
4209
4210createInjector.$$annotate = annotate;
4211
4212/**
4213 * @ngdoc provider
4214 * @name $anchorScrollProvider
4215 *
4216 * @description
4217 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4218 * {@link ng.$location#hash $location.hash()} changes.
4219 */
4220function $AnchorScrollProvider() {
4221
4222  var autoScrollingEnabled = true;
4223
4224  /**
4225   * @ngdoc method
4226   * @name $anchorScrollProvider#disableAutoScrolling
4227   *
4228   * @description
4229   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4230   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4231   * Use this method to disable automatic scrolling.
4232   *
4233   * If automatic scrolling is disabled, one must explicitly call
4234   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4235   * current hash.
4236   */
4237  this.disableAutoScrolling = function() {
4238    autoScrollingEnabled = false;
4239  };
4240
4241  /**
4242   * @ngdoc service
4243   * @name $anchorScroll
4244   * @kind function
4245   * @requires $window
4246   * @requires $location
4247   * @requires $rootScope
4248   *
4249   * @description
4250   * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and
4251   * scrolls to the related element, according to the rules specified in the
4252   * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4253   *
4254   * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4255   * match any anchor whenever it changes. This can be disabled by calling
4256   * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4257   *
4258   * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4259   * vertical scroll-offset (either fixed or dynamic).
4260   *
4261   * @property {(number|function|jqLite)} yOffset
4262   * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4263   * positioned elements at the top of the page, such as navbars, headers etc.
4264   *
4265   * `yOffset` can be specified in various ways:
4266   * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4267   * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4268   *   a number representing the offset (in pixels).<br /><br />
4269   * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4270   *   the top of the page to the element's bottom will be used as offset.<br />
4271   *   **Note**: The element will be taken into account only as long as its `position` is set to
4272   *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4273   *   their height and/or positioning according to the viewport's size.
4274   *
4275   * <br />
4276   * <div class="alert alert-warning">
4277   * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4278   * not some child element.
4279   * </div>
4280   *
4281   * @example
4282     <example module="anchorScrollExample">
4283       <file name="index.html">
4284         <div id="scrollArea" ng-controller="ScrollController">
4285           <a ng-click="gotoBottom()">Go to bottom</a>
4286           <a id="bottom"></a> You're at the bottom!
4287         </div>
4288       </file>
4289       <file name="script.js">
4290         angular.module('anchorScrollExample', [])
4291           .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4292             function ($scope, $location, $anchorScroll) {
4293               $scope.gotoBottom = function() {
4294                 // set the location.hash to the id of
4295                 // the element you wish to scroll to.
4296                 $location.hash('bottom');
4297
4298                 // call $anchorScroll()
4299                 $anchorScroll();
4300               };
4301             }]);
4302       </file>
4303       <file name="style.css">
4304         #scrollArea {
4305           height: 280px;
4306           overflow: auto;
4307         }
4308
4309         #bottom {
4310           display: block;
4311           margin-top: 2000px;
4312         }
4313       </file>
4314     </example>
4315   *
4316   * <hr />
4317   * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4318   * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4319   *
4320   * @example
4321     <example module="anchorScrollOffsetExample">
4322       <file name="index.html">
4323         <div class="fixed-header" ng-controller="headerCtrl">
4324           <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4325             Go to anchor {{x}}
4326           </a>
4327         </div>
4328         <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4329           Anchor {{x}} of 5
4330         </div>
4331       </file>
4332       <file name="script.js">
4333         angular.module('anchorScrollOffsetExample', [])
4334           .run(['$anchorScroll', function($anchorScroll) {
4335             $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4336           }])
4337           .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4338             function ($anchorScroll, $location, $scope) {
4339               $scope.gotoAnchor = function(x) {
4340                 var newHash = 'anchor' + x;
4341                 if ($location.hash() !== newHash) {
4342                   // set the $location.hash to `newHash` and
4343                   // $anchorScroll will automatically scroll to it
4344                   $location.hash('anchor' + x);
4345                 } else {
4346                   // call $anchorScroll() explicitly,
4347                   // since $location.hash hasn't changed
4348                   $anchorScroll();
4349                 }
4350               };
4351             }
4352           ]);
4353       </file>
4354       <file name="style.css">
4355         body {
4356           padding-top: 50px;
4357         }
4358
4359         .anchor {
4360           border: 2px dashed DarkOrchid;
4361           padding: 10px 10px 200px 10px;
4362         }
4363
4364         .fixed-header {
4365           background-color: rgba(0, 0, 0, 0.2);
4366           height: 50px;
4367           position: fixed;
4368           top: 0; left: 0; right: 0;
4369         }
4370
4371         .fixed-header > a {
4372           display: inline-block;
4373           margin: 5px 15px;
4374         }
4375       </file>
4376     </example>
4377   */
4378  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4379    var document = $window.document;
4380
4381    // Helper function to get first anchor from a NodeList
4382    // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4383    //  and working in all supported browsers.)
4384    function getFirstAnchor(list) {
4385      var result = null;
4386      Array.prototype.some.call(list, function(element) {
4387        if (nodeName_(element) === 'a') {
4388          result = element;
4389          return true;
4390        }
4391      });
4392      return result;
4393    }
4394
4395    function getYOffset() {
4396
4397      var offset = scroll.yOffset;
4398
4399      if (isFunction(offset)) {
4400        offset = offset();
4401      } else if (isElement(offset)) {
4402        var elem = offset[0];
4403        var style = $window.getComputedStyle(elem);
4404        if (style.position !== 'fixed') {
4405          offset = 0;
4406        } else {
4407          offset = elem.getBoundingClientRect().bottom;
4408        }
4409      } else if (!isNumber(offset)) {
4410        offset = 0;
4411      }
4412
4413      return offset;
4414    }
4415
4416    function scrollTo(elem) {
4417      if (elem) {
4418        elem.scrollIntoView();
4419
4420        var offset = getYOffset();
4421
4422        if (offset) {
4423          // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4424          // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4425          // top of the viewport.
4426          //
4427          // IF the number of pixels from the top of `elem` to the end of the page's content is less
4428          // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4429          // way down the page.
4430          //
4431          // This is often the case for elements near the bottom of the page.
4432          //
4433          // In such cases we do not need to scroll the whole `offset` up, just the difference between
4434          // the top of the element and the offset, which is enough to align the top of `elem` at the
4435          // desired position.
4436          var elemTop = elem.getBoundingClientRect().top;
4437          $window.scrollBy(0, elemTop - offset);
4438        }
4439      } else {
4440        $window.scrollTo(0, 0);
4441      }
4442    }
4443
4444    function scroll() {
4445      var hash = $location.hash(), elm;
4446
4447      // empty hash, scroll to the top of the page
4448      if (!hash) scrollTo(null);
4449
4450      // element with given id
4451      else if ((elm = document.getElementById(hash))) scrollTo(elm);
4452
4453      // first anchor with given name :-D
4454      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4455
4456      // no element and hash == 'top', scroll to the top of the page
4457      else if (hash === 'top') scrollTo(null);
4458    }
4459
4460    // does not scroll when user clicks on anchor link that is currently on
4461    // (no url change, no $location.hash() change), browser native does scroll
4462    if (autoScrollingEnabled) {
4463      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4464        function autoScrollWatchAction(newVal, oldVal) {
4465          // skip the initial scroll if $location.hash is empty
4466          if (newVal === oldVal && newVal === '') return;
4467
4468          jqLiteDocumentLoaded(function() {
4469            $rootScope.$evalAsync(scroll);
4470          });
4471        });
4472    }
4473
4474    return scroll;
4475  }];
4476}
4477
4478var $animateMinErr = minErr('$animate');
4479
4480/**
4481 * @ngdoc provider
4482 * @name $animateProvider
4483 *
4484 * @description
4485 * Default implementation of $animate that doesn't perform any animations, instead just
4486 * synchronously performs DOM
4487 * updates and calls done() callbacks.
4488 *
4489 * In order to enable animations the ngAnimate module has to be loaded.
4490 *
4491 * To see the functional implementation check out src/ngAnimate/animate.js
4492 */
4493var $AnimateProvider = ['$provide', function($provide) {
4494
4495
4496  this.$$selectors = {};
4497
4498
4499  /**
4500   * @ngdoc method
4501   * @name $animateProvider#register
4502   *
4503   * @description
4504   * Registers a new injectable animation factory function. The factory function produces the
4505   * animation object which contains callback functions for each event that is expected to be
4506   * animated.
4507   *
4508   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4509   *   must be called once the element animation is complete. If a function is returned then the
4510   *   animation service will use this function to cancel the animation whenever a cancel event is
4511   *   triggered.
4512   *
4513   *
4514   * ```js
4515   *   return {
4516     *     eventFn : function(element, done) {
4517     *       //code to run the animation
4518     *       //once complete, then run done()
4519     *       return function cancellationFunction() {
4520     *         //code to cancel the animation
4521     *       }
4522     *     }
4523     *   }
4524   * ```
4525   *
4526   * @param {string} name The name of the animation.
4527   * @param {Function} factory The factory function that will be executed to return the animation
4528   *                           object.
4529   */
4530  this.register = function(name, factory) {
4531    var key = name + '-animation';
4532    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4533        "Expecting class selector starting with '.' got '{0}'.", name);
4534    this.$$selectors[name.substr(1)] = key;
4535    $provide.factory(key, factory);
4536  };
4537
4538  /**
4539   * @ngdoc method
4540   * @name $animateProvider#classNameFilter
4541   *
4542   * @description
4543   * Sets and/or returns the CSS class regular expression that is checked when performing
4544   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4545   * therefore enable $animate to attempt to perform an animation on any element.
4546   * When setting the classNameFilter value, animations will only be performed on elements
4547   * that successfully match the filter expression. This in turn can boost performance
4548   * for low-powered devices as well as applications containing a lot of structural operations.
4549   * @param {RegExp=} expression The className expression which will be checked against all animations
4550   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4551   */
4552  this.classNameFilter = function(expression) {
4553    if (arguments.length === 1) {
4554      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4555    }
4556    return this.$$classNameFilter;
4557  };
4558
4559  this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) {
4560
4561    var currentDefer;
4562
4563    function runAnimationPostDigest(fn) {
4564      var cancelFn, defer = $$q.defer();
4565      defer.promise.$$cancelFn = function ngAnimateMaybeCancel() {
4566        cancelFn && cancelFn();
4567      };
4568
4569      $rootScope.$$postDigest(function ngAnimatePostDigest() {
4570        cancelFn = fn(function ngAnimateNotifyComplete() {
4571          defer.resolve();
4572        });
4573      });
4574
4575      return defer.promise;
4576    }
4577
4578    function resolveElementClasses(element, classes) {
4579      var toAdd = [], toRemove = [];
4580
4581      var hasClasses = createMap();
4582      forEach((element.attr('class') || '').split(/\s+/), function(className) {
4583        hasClasses[className] = true;
4584      });
4585
4586      forEach(classes, function(status, className) {
4587        var hasClass = hasClasses[className];
4588
4589        // If the most recent class manipulation (via $animate) was to remove the class, and the
4590        // element currently has the class, the class is scheduled for removal. Otherwise, if
4591        // the most recent class manipulation (via $animate) was to add the class, and the
4592        // element does not currently have the class, the class is scheduled to be added.
4593        if (status === false && hasClass) {
4594          toRemove.push(className);
4595        } else if (status === true && !hasClass) {
4596          toAdd.push(className);
4597        }
4598      });
4599
4600      return (toAdd.length + toRemove.length) > 0 &&
4601        [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null];
4602    }
4603
4604    function cachedClassManipulation(cache, classes, op) {
4605      for (var i=0, ii = classes.length; i < ii; ++i) {
4606        var className = classes[i];
4607        cache[className] = op;
4608      }
4609    }
4610
4611    function asyncPromise() {
4612      // only serve one instance of a promise in order to save CPU cycles
4613      if (!currentDefer) {
4614        currentDefer = $$q.defer();
4615        $$asyncCallback(function() {
4616          currentDefer.resolve();
4617          currentDefer = null;
4618        });
4619      }
4620      return currentDefer.promise;
4621    }
4622
4623    function applyStyles(element, options) {
4624      if (angular.isObject(options)) {
4625        var styles = extend(options.from || {}, options.to || {});
4626        element.css(styles);
4627      }
4628    }
4629
4630    /**
4631     *
4632     * @ngdoc service
4633     * @name $animate
4634     * @description The $animate service provides rudimentary DOM manipulation functions to
4635     * insert, remove and move elements within the DOM, as well as adding and removing classes.
4636     * This service is the core service used by the ngAnimate $animator service which provides
4637     * high-level animation hooks for CSS and JavaScript.
4638     *
4639     * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4640     * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4641     * manipulation operations.
4642     *
4643     * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4644     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4645     * page}.
4646     */
4647    return {
4648      animate: function(element, from, to) {
4649        applyStyles(element, { from: from, to: to });
4650        return asyncPromise();
4651      },
4652
4653      /**
4654       *
4655       * @ngdoc method
4656       * @name $animate#enter
4657       * @kind function
4658       * @description Inserts the element into the DOM either after the `after` element or
4659       * as the first child within the `parent` element. When the function is called a promise
4660       * is returned that will be resolved at a later time.
4661       * @param {DOMElement} element the element which will be inserted into the DOM
4662       * @param {DOMElement} parent the parent element which will append the element as
4663       *   a child (if the after element is not present)
4664       * @param {DOMElement} after the sibling element which will append the element
4665       *   after itself
4666       * @param {object=} options an optional collection of styles that will be applied to the element.
4667       * @return {Promise} the animation callback promise
4668       */
4669      enter: function(element, parent, after, options) {
4670        applyStyles(element, options);
4671        after ? after.after(element)
4672              : parent.prepend(element);
4673        return asyncPromise();
4674      },
4675
4676      /**
4677       *
4678       * @ngdoc method
4679       * @name $animate#leave
4680       * @kind function
4681       * @description Removes the element from the DOM. When the function is called a promise
4682       * is returned that will be resolved at a later time.
4683       * @param {DOMElement} element the element which will be removed from the DOM
4684       * @param {object=} options an optional collection of options that will be applied to the element.
4685       * @return {Promise} the animation callback promise
4686       */
4687      leave: function(element, options) {
4688        element.remove();
4689        return asyncPromise();
4690      },
4691
4692      /**
4693       *
4694       * @ngdoc method
4695       * @name $animate#move
4696       * @kind function
4697       * @description Moves the position of the provided element within the DOM to be placed
4698       * either after the `after` element or inside of the `parent` element. When the function
4699       * is called a promise is returned that will be resolved at a later time.
4700       *
4701       * @param {DOMElement} element the element which will be moved around within the
4702       *   DOM
4703       * @param {DOMElement} parent the parent element where the element will be
4704       *   inserted into (if the after element is not present)
4705       * @param {DOMElement} after the sibling element where the element will be
4706       *   positioned next to
4707       * @param {object=} options an optional collection of options that will be applied to the element.
4708       * @return {Promise} the animation callback promise
4709       */
4710      move: function(element, parent, after, options) {
4711        // Do not remove element before insert. Removing will cause data associated with the
4712        // element to be dropped. Insert will implicitly do the remove.
4713        return this.enter(element, parent, after, options);
4714      },
4715
4716      /**
4717       *
4718       * @ngdoc method
4719       * @name $animate#addClass
4720       * @kind function
4721       * @description Adds the provided className CSS class value to the provided element.
4722       * When the function is called a promise is returned that will be resolved at a later time.
4723       * @param {DOMElement} element the element which will have the className value
4724       *   added to it
4725       * @param {string} className the CSS class which will be added to the element
4726       * @param {object=} options an optional collection of options that will be applied to the element.
4727       * @return {Promise} the animation callback promise
4728       */
4729      addClass: function(element, className, options) {
4730        return this.setClass(element, className, [], options);
4731      },
4732
4733      $$addClassImmediately: function(element, className, options) {
4734        element = jqLite(element);
4735        className = !isString(className)
4736                        ? (isArray(className) ? className.join(' ') : '')
4737                        : className;
4738        forEach(element, function(element) {
4739          jqLiteAddClass(element, className);
4740        });
4741        applyStyles(element, options);
4742        return asyncPromise();
4743      },
4744
4745      /**
4746       *
4747       * @ngdoc method
4748       * @name $animate#removeClass
4749       * @kind function
4750       * @description Removes the provided className CSS class value from the provided element.
4751       * When the function is called a promise is returned that will be resolved at a later time.
4752       * @param {DOMElement} element the element which will have the className value
4753       *   removed from it
4754       * @param {string} className the CSS class which will be removed from the element
4755       * @param {object=} options an optional collection of options that will be applied to the element.
4756       * @return {Promise} the animation callback promise
4757       */
4758      removeClass: function(element, className, options) {
4759        return this.setClass(element, [], className, options);
4760      },
4761
4762      $$removeClassImmediately: function(element, className, options) {
4763        element = jqLite(element);
4764        className = !isString(className)
4765                        ? (isArray(className) ? className.join(' ') : '')
4766                        : className;
4767        forEach(element, function(element) {
4768          jqLiteRemoveClass(element, className);
4769        });
4770        applyStyles(element, options);
4771        return asyncPromise();
4772      },
4773
4774      /**
4775       *
4776       * @ngdoc method
4777       * @name $animate#setClass
4778       * @kind function
4779       * @description Adds and/or removes the given CSS classes to and from the element.
4780       * When the function is called a promise is returned that will be resolved at a later time.
4781       * @param {DOMElement} element the element which will have its CSS classes changed
4782       *   removed from it
4783       * @param {string} add the CSS classes which will be added to the element
4784       * @param {string} remove the CSS class which will be removed from the element
4785       * @param {object=} options an optional collection of options that will be applied to the element.
4786       * @return {Promise} the animation callback promise
4787       */
4788      setClass: function(element, add, remove, options) {
4789        var self = this;
4790        var STORAGE_KEY = '$$animateClasses';
4791        var createdCache = false;
4792        element = jqLite(element);
4793
4794        var cache = element.data(STORAGE_KEY);
4795        if (!cache) {
4796          cache = {
4797            classes: {},
4798            options: options
4799          };
4800          createdCache = true;
4801        } else if (options && cache.options) {
4802          cache.options = angular.extend(cache.options || {}, options);
4803        }
4804
4805        var classes = cache.classes;
4806
4807        add = isArray(add) ? add : add.split(' ');
4808        remove = isArray(remove) ? remove : remove.split(' ');
4809        cachedClassManipulation(classes, add, true);
4810        cachedClassManipulation(classes, remove, false);
4811
4812        if (createdCache) {
4813          cache.promise = runAnimationPostDigest(function(done) {
4814            var cache = element.data(STORAGE_KEY);
4815            element.removeData(STORAGE_KEY);
4816
4817            // in the event that the element is removed before postDigest
4818            // is run then the cache will be undefined and there will be
4819            // no need anymore to add or remove and of the element classes
4820            if (cache) {
4821              var classes = resolveElementClasses(element, cache.classes);
4822              if (classes) {
4823                self.$$setClassImmediately(element, classes[0], classes[1], cache.options);
4824              }
4825            }
4826
4827            done();
4828          });
4829          element.data(STORAGE_KEY, cache);
4830        }
4831
4832        return cache.promise;
4833      },
4834
4835      $$setClassImmediately: function(element, add, remove, options) {
4836        add && this.$$addClassImmediately(element, add);
4837        remove && this.$$removeClassImmediately(element, remove);
4838        applyStyles(element, options);
4839        return asyncPromise();
4840      },
4841
4842      enabled: noop,
4843      cancel: noop
4844    };
4845  }];
4846}];
4847
4848function $$AsyncCallbackProvider() {
4849  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
4850    return $$rAF.supported
4851      ? function(fn) { return $$rAF(fn); }
4852      : function(fn) {
4853        return $timeout(fn, 0, false);
4854      };
4855  }];
4856}
4857
4858/* global stripHash: true */
4859
4860/**
4861 * ! This is a private undocumented service !
4862 *
4863 * @name $browser
4864 * @requires $log
4865 * @description
4866 * This object has two goals:
4867 *
4868 * - hide all the global state in the browser caused by the window object
4869 * - abstract away all the browser specific features and inconsistencies
4870 *
4871 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4872 * service, which can be used for convenient testing of the application without the interaction with
4873 * the real browser apis.
4874 */
4875/**
4876 * @param {object} window The global window object.
4877 * @param {object} document jQuery wrapped document.
4878 * @param {object} $log window.console or an object with the same interface.
4879 * @param {object} $sniffer $sniffer service
4880 */
4881function Browser(window, document, $log, $sniffer) {
4882  var self = this,
4883      rawDocument = document[0],
4884      location = window.location,
4885      history = window.history,
4886      setTimeout = window.setTimeout,
4887      clearTimeout = window.clearTimeout,
4888      pendingDeferIds = {};
4889
4890  self.isMock = false;
4891
4892  var outstandingRequestCount = 0;
4893  var outstandingRequestCallbacks = [];
4894
4895  // TODO(vojta): remove this temporary api
4896  self.$$completeOutstandingRequest = completeOutstandingRequest;
4897  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
4898
4899  /**
4900   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4901   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4902   */
4903  function completeOutstandingRequest(fn) {
4904    try {
4905      fn.apply(null, sliceArgs(arguments, 1));
4906    } finally {
4907      outstandingRequestCount--;
4908      if (outstandingRequestCount === 0) {
4909        while (outstandingRequestCallbacks.length) {
4910          try {
4911            outstandingRequestCallbacks.pop()();
4912          } catch (e) {
4913            $log.error(e);
4914          }
4915        }
4916      }
4917    }
4918  }
4919
4920  function getHash(url) {
4921    var index = url.indexOf('#');
4922    return index === -1 ? '' : url.substr(index + 1);
4923  }
4924
4925  /**
4926   * @private
4927   * Note: this method is used only by scenario runner
4928   * TODO(vojta): prefix this method with $$ ?
4929   * @param {function()} callback Function that will be called when no outstanding request
4930   */
4931  self.notifyWhenNoOutstandingRequests = function(callback) {
4932    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4933    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4934    // regular poller would result in flaky tests.
4935    forEach(pollFns, function(pollFn) { pollFn(); });
4936
4937    if (outstandingRequestCount === 0) {
4938      callback();
4939    } else {
4940      outstandingRequestCallbacks.push(callback);
4941    }
4942  };
4943
4944  //////////////////////////////////////////////////////////////
4945  // Poll Watcher API
4946  //////////////////////////////////////////////////////////////
4947  var pollFns = [],
4948      pollTimeout;
4949
4950  /**
4951   * @name $browser#addPollFn
4952   *
4953   * @param {function()} fn Poll function to add
4954   *
4955   * @description
4956   * Adds a function to the list of functions that poller periodically executes,
4957   * and starts polling if not started yet.
4958   *
4959   * @returns {function()} the added function
4960   */
4961  self.addPollFn = function(fn) {
4962    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4963    pollFns.push(fn);
4964    return fn;
4965  };
4966
4967  /**
4968   * @param {number} interval How often should browser call poll functions (ms)
4969   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4970   *
4971   * @description
4972   * Configures the poller to run in the specified intervals, using the specified
4973   * setTimeout fn and kicks it off.
4974   */
4975  function startPoller(interval, setTimeout) {
4976    (function check() {
4977      forEach(pollFns, function(pollFn) { pollFn(); });
4978      pollTimeout = setTimeout(check, interval);
4979    })();
4980  }
4981
4982  //////////////////////////////////////////////////////////////
4983  // URL API
4984  //////////////////////////////////////////////////////////////
4985
4986  var cachedState, lastHistoryState,
4987      lastBrowserUrl = location.href,
4988      baseElement = document.find('base'),
4989      reloadLocation = null;
4990
4991  cacheState();
4992  lastHistoryState = cachedState;
4993
4994  /**
4995   * @name $browser#url
4996   *
4997   * @description
4998   * GETTER:
4999   * Without any argument, this method just returns current value of location.href.
5000   *
5001   * SETTER:
5002   * With at least one argument, this method sets url to new value.
5003   * If html5 history api supported, pushState/replaceState is used, otherwise
5004   * location.href/location.replace is used.
5005   * Returns its own instance to allow chaining
5006   *
5007   * NOTE: this api is intended for use only by the $location service. Please use the
5008   * {@link ng.$location $location service} to change url.
5009   *
5010   * @param {string} url New url (when used as setter)
5011   * @param {boolean=} replace Should new url replace current history record?
5012   * @param {object=} state object to use with pushState/replaceState
5013   */
5014  self.url = function(url, replace, state) {
5015    // In modern browsers `history.state` is `null` by default; treating it separately
5016    // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5017    // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5018    if (isUndefined(state)) {
5019      state = null;
5020    }
5021
5022    // Android Browser BFCache causes location, history reference to become stale.
5023    if (location !== window.location) location = window.location;
5024    if (history !== window.history) history = window.history;
5025
5026    // setter
5027    if (url) {
5028      var sameState = lastHistoryState === state;
5029
5030      // Don't change anything if previous and current URLs and states match. This also prevents
5031      // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5032      // See https://github.com/angular/angular.js/commit/ffb2701
5033      if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5034        return self;
5035      }
5036      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5037      lastBrowserUrl = url;
5038      lastHistoryState = state;
5039      // Don't use history API if only the hash changed
5040      // due to a bug in IE10/IE11 which leads
5041      // to not firing a `hashchange` nor `popstate` event
5042      // in some cases (see #9143).
5043      if ($sniffer.history && (!sameBase || !sameState)) {
5044        history[replace ? 'replaceState' : 'pushState'](state, '', url);
5045        cacheState();
5046        // Do the assignment again so that those two variables are referentially identical.
5047        lastHistoryState = cachedState;
5048      } else {
5049        if (!sameBase) {
5050          reloadLocation = url;
5051        }
5052        if (replace) {
5053          location.replace(url);
5054        } else if (!sameBase) {
5055          location.href = url;
5056        } else {
5057          location.hash = getHash(url);
5058        }
5059      }
5060      return self;
5061    // getter
5062    } else {
5063      // - reloadLocation is needed as browsers don't allow to read out
5064      //   the new location.href if a reload happened.
5065      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5066      return reloadLocation || location.href.replace(/%27/g,"'");
5067    }
5068  };
5069
5070  /**
5071   * @name $browser#state
5072   *
5073   * @description
5074   * This method is a getter.
5075   *
5076   * Return history.state or null if history.state is undefined.
5077   *
5078   * @returns {object} state
5079   */
5080  self.state = function() {
5081    return cachedState;
5082  };
5083
5084  var urlChangeListeners = [],
5085      urlChangeInit = false;
5086
5087  function cacheStateAndFireUrlChange() {
5088    cacheState();
5089    fireUrlChange();
5090  }
5091
5092  // This variable should be used *only* inside the cacheState function.
5093  var lastCachedState = null;
5094  function cacheState() {
5095    // This should be the only place in $browser where `history.state` is read.
5096    cachedState = window.history.state;
5097    cachedState = isUndefined(cachedState) ? null : cachedState;
5098
5099    // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5100    if (equals(cachedState, lastCachedState)) {
5101      cachedState = lastCachedState;
5102    }
5103    lastCachedState = cachedState;
5104  }
5105
5106  function fireUrlChange() {
5107    if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5108      return;
5109    }
5110
5111    lastBrowserUrl = self.url();
5112    lastHistoryState = cachedState;
5113    forEach(urlChangeListeners, function(listener) {
5114      listener(self.url(), cachedState);
5115    });
5116  }
5117
5118  /**
5119   * @name $browser#onUrlChange
5120   *
5121   * @description
5122   * Register callback function that will be called, when url changes.
5123   *
5124   * It's only called when the url is changed from outside of angular:
5125   * - user types different url into address bar
5126   * - user clicks on history (forward/back) button
5127   * - user clicks on a link
5128   *
5129   * It's not called when url is changed by $browser.url() method
5130   *
5131   * The listener gets called with new url as parameter.
5132   *
5133   * NOTE: this api is intended for use only by the $location service. Please use the
5134   * {@link ng.$location $location service} to monitor url changes in angular apps.
5135   *
5136   * @param {function(string)} listener Listener function to be called when url changes.
5137   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5138   */
5139  self.onUrlChange = function(callback) {
5140    // TODO(vojta): refactor to use node's syntax for events
5141    if (!urlChangeInit) {
5142      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5143      // don't fire popstate when user change the address bar and don't fire hashchange when url
5144      // changed by push/replaceState
5145
5146      // html5 history api - popstate event
5147      if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5148      // hashchange event
5149      jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5150
5151      urlChangeInit = true;
5152    }
5153
5154    urlChangeListeners.push(callback);
5155    return callback;
5156  };
5157
5158  /**
5159   * Checks whether the url has changed outside of Angular.
5160   * Needs to be exported to be able to check for changes that have been done in sync,
5161   * as hashchange/popstate events fire in async.
5162   */
5163  self.$$checkUrlChange = fireUrlChange;
5164
5165  //////////////////////////////////////////////////////////////
5166  // Misc API
5167  //////////////////////////////////////////////////////////////
5168
5169  /**
5170   * @name $browser#baseHref
5171   *
5172   * @description
5173   * Returns current <base href>
5174   * (always relative - without domain)
5175   *
5176   * @returns {string} The current base href
5177   */
5178  self.baseHref = function() {
5179    var href = baseElement.attr('href');
5180    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5181  };
5182
5183  //////////////////////////////////////////////////////////////
5184  // Cookies API
5185  //////////////////////////////////////////////////////////////
5186  var lastCookies = {};
5187  var lastCookieString = '';
5188  var cookiePath = self.baseHref();
5189
5190  function safeDecodeURIComponent(str) {
5191    try {
5192      return decodeURIComponent(str);
5193    } catch (e) {
5194      return str;
5195    }
5196  }
5197
5198  /**
5199   * @name $browser#cookies
5200   *
5201   * @param {string=} name Cookie name
5202   * @param {string=} value Cookie value
5203   *
5204   * @description
5205   * The cookies method provides a 'private' low level access to browser cookies.
5206   * It is not meant to be used directly, use the $cookie service instead.
5207   *
5208   * The return values vary depending on the arguments that the method was called with as follows:
5209   *
5210   * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
5211   *   it
5212   * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
5213   * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
5214   *   way)
5215   *
5216   * @returns {Object} Hash of all cookies (if called without any parameter)
5217   */
5218  self.cookies = function(name, value) {
5219    var cookieLength, cookieArray, cookie, i, index;
5220
5221    if (name) {
5222      if (value === undefined) {
5223        rawDocument.cookie = encodeURIComponent(name) + "=;
5223path=" + cookiePath +
5224                                ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
5225      } else {
5226        if (isString(value)) {
5227          cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
5228                                ';path=' + cookiePath).length + 1;
5229
5230          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
5231          // - 300 cookies
5232          // - 20 cookies per unique domain
5233          // - 4096 bytes per cookie
5234          if (cookieLength > 4096) {
5235            $log.warn("Cookie '" + name +
5236              "' possibly not set or overflowed because it was too large (" +
5237              cookieLength + " > 4096 bytes)!");
5238          }
5239        }
5240      }
5241    } else {
5242      if (rawDocument.cookie !== lastCookieString) {
5243        lastCookieString = rawDocument.cookie;
5244        cookieArray = lastCookieString.split("; ");
5245        lastCookies = {};
5246
5247        for (i = 0; i < cookieArray.length; i++) {
5248          cookie = cookieArray[i];
5249          index = cookie.indexOf('=');
5250          if (index > 0) { //ignore nameless cookies
5251            name = safeDecodeURIComponent(cookie.substring(0, index));
5252            // the first value that is seen for a cookie is the most
5253            // specific one.  values for the same cookie name that
5254            // follow are for less specific paths.
5255            if (lastCookies[name] === undefined) {
5256              lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
5257            }
5258          }
5259        }
5260      }
5261      return lastCookies;
5262    }
5263  };
5264
5265
5266  /**
5267   * @name $browser#defer
5268   * @param {function()} fn A function, who's execution should be deferred.
5269   * @param {number=} [delay=0] of milliseconds to defer the function execution.
5270   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5271   *
5272   * @description
5273   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5274   *
5275   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5276   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5277   * via `$browser.defer.flush()`.
5278   *
5279   */
5280  self.defer = function(fn, delay) {
5281    var timeoutId;
5282    outstandingRequestCount++;
5283    timeoutId = setTimeout(function() {
5284      delete pendingDeferIds[timeoutId];
5285      completeOutstandingRequest(fn);
5286    }, delay || 0);
5287    pendingDeferIds[timeoutId] = true;
5288    return timeoutId;
5289  };
5290
5291
5292  /**
5293   * @name $browser#defer.cancel
5294   *
5295   * @description
5296   * Cancels a deferred task identified with `deferId`.
5297   *
5298   * @param {*} deferId Token returned by the `$browser.defer` function.
5299   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5300   *                    canceled.
5301   */
5302  self.defer.cancel = function(deferId) {
5303    if (pendingDeferIds[deferId]) {
5304      delete pendingDeferIds[deferId];
5305      clearTimeout(deferId);
5306      completeOutstandingRequest(noop);
5307      return true;
5308    }
5309    return false;
5310  };
5311
5312}
5313
5314function $BrowserProvider() {
5315  this.$get = ['$window', '$log', '$sniffer', '$document',
5316      function($window, $log, $sniffer, $document) {
5317        return new Browser($window, $document, $log, $sniffer);
5318      }];
5319}
5320
5321/**
5322 * @ngdoc service
5323 * @name $cacheFactory
5324 *
5325 * @description
5326 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5327 * them.
5328 *
5329 * ```js
5330 *
5331 *  var cache = $cacheFactory('cacheId');
5332 *  expect($cacheFactory.get('cacheId')).toBe(cache);
5333 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5334 *
5335 *  cache.put("key", "value");
5336 *  cache.put("another key", "another value");
5337 *
5338 *  // We've specified no options on creation
5339 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5340 *
5341 * ```
5342 *
5343 *
5344 * @param {string} cacheId Name or id of the newly created cache.
5345 * @param {object=} options Options object that specifies the cache behavior. Properties:
5346 *
5347 *   - `{number=}` `capacity` — turns the cache into LRU cache.
5348 *
5349 * @returns {object} Newly created cache object with the following set of methods:
5350 *
5351 * - `{object}` `info()` — Returns id, size, and options of cache.
5352 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5353 *   it.
5354 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5355 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5356 * - `{void}` `removeAll()` — Removes all cached values.
5357 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5358 *
5359 * @example
5360   <example module="cacheExampleApp">
5361     <file name="index.html">
5362       <div ng-controller="CacheController">
5363         <input ng-model="newCacheKey" placeholder="Key">
5364         <input ng-model="newCacheValue" placeholder="Value">
5365         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5366
5367         <p ng-if="keys.length">Cached Values</p>
5368         <div ng-repeat="key in keys">
5369           <span ng-bind="key"></span>
5370           <span>: </span>
5371           <b ng-bind="cache.get(key)"></b>
5372         </div>
5373
5374         <p>Cache Info</p>
5375         <div ng-repeat="(key, value) in cache.info()">
5376           <span ng-bind="key"></span>
5377           <span>: </span>
5378           <b ng-bind="value"></b>
5379         </div>
5380       </div>
5381     </file>
5382     <file name="script.js">
5383       angular.module('cacheExampleApp', []).
5384         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
5385           $scope.keys = [];
5386           $scope.cache = $cacheFactory('cacheId');
5387           $scope.put = function(key, value) {
5388             if ($scope.cache.get(key) === undefined) {
5389               $scope.keys.push(key);
5390             }
5391             $scope.cache.put(key, value === undefined ? null : value);
5392           };
5393         }]);
5394     </file>
5395     <file name="style.css">
5396       p {
5397         margin: 10px 0 3px;
5398       }
5399     </file>
5400   </example>
5401 */
5402function $CacheFactoryProvider() {
5403
5404  this.$get = function() {
5405    var caches = {};
5406
5407    function cacheFactory(cacheId, options) {
5408      if (cacheId in caches) {
5409        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
5410      }
5411
5412      var size = 0,
5413          stats = extend({}, options, {id: cacheId}),
5414          data = {},
5415          capacity = (options && options.capacity) || Number.MAX_VALUE,
5416          lruHash = {},
5417          freshEnd = null,
5418          staleEnd = null;
5419
5420      /**
5421       * @ngdoc type
5422       * @name $cacheFactory.Cache
5423       *
5424       * @description
5425       * A cache object used to store and retrieve data, primarily used by
5426       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
5427       * templates and other data.
5428       *
5429       * ```js
5430       *  angular.module('superCache')
5431       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
5432       *      return $cacheFactory('super-cache');
5433       *    }]);
5434       * ```
5435       *
5436       * Example test:
5437       *
5438       * ```js
5439       *  it('should behave like a cache', inject(function(superCache) {
5440       *    superCache.put('key', 'value');
5441       *    superCache.put('another key', 'another value');
5442       *
5443       *    expect(superCache.info()).toEqual({
5444       *      id: 'super-cache',
5445       *      size: 2
5446       *    });
5447       *
5448       *    superCache.remove('another key');
5449       *    expect(superCache.get('another key')).toBeUndefined();
5450       *
5451       *    superCache.removeAll();
5452       *    expect(superCache.info()).toEqual({
5453       *      id: 'super-cache',
5454       *      size: 0
5455       *    });
5456       *  }));
5457       * ```
5458       */
5459      return caches[cacheId] = {
5460
5461        /**
5462         * @ngdoc method
5463         * @name $cacheFactory.Cache#put
5464         * @kind function
5465         *
5466         * @description
5467         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
5468         * retrieved later, and incrementing the size of the cache if the key was not already
5469         * present in the cache. If behaving like an LRU cache, it will also remove stale
5470         * entries from the set.
5471         *
5472         * It will not insert undefined values into the cache.
5473         *
5474         * @param {string} key the key under which the cached data is stored.
5475         * @param {*} value the value to store alongside the key. If it is undefined, the key
5476         *    will not be stored.
5477         * @returns {*} the value stored.
5478         */
5479        put: function(key, value) {
5480          if (capacity < Number.MAX_VALUE) {
5481            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
5482
5483            refresh(lruEntry);
5484          }
5485
5486          if (isUndefined(value)) return;
5487          if (!(key in data)) size++;
5488          data[key] = value;
5489
5490          if (size > capacity) {
5491            this.remove(staleEnd.key);
5492          }
5493
5494          return value;
5495        },
5496
5497        /**
5498         * @ngdoc method
5499         * @name $cacheFactory.Cache#get
5500         * @kind function
5501         *
5502         * @description
5503         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
5504         *
5505         * @param {string} key the key of the data to be retrieved
5506         * @returns {*} the value stored.
5507         */
5508        get: function(key) {
5509          if (capacity < Number.MAX_VALUE) {
5510            var lruEntry = lruHash[key];
5511
5512            if (!lruEntry) return;
5513
5514            refresh(lruEntry);
5515          }
5516
5517          return data[key];
5518        },
5519
5520
5521        /**
5522         * @ngdoc method
5523         * @name $cacheFactory.Cache#remove
5524         * @kind function
5525         *
5526         * @description
5527         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
5528         *
5529         * @param {string} key the key of the entry to be removed
5530         */
5531        remove: function(key) {
5532          if (capacity < Number.MAX_VALUE) {
5533            var lruEntry = lruHash[key];
5534
5535            if (!lruEntry) return;
5536
5537            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
5538            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
5539            link(lruEntry.n,lruEntry.p);
5540
5541            delete lruHash[key];
5542          }
5543
5544          delete data[key];
5545          size--;
5546        },
5547
5548
5549        /**
5550         * @ngdoc method
5551         * @name $cacheFactory.Cache#removeAll
5552         * @kind function
5553         *
5554         * @description
5555         * Clears the cache object of any entries.
5556         */
5557        removeAll: function() {
5558          data = {};
5559          size = 0;
5560          lruHash = {};
5561          freshEnd = staleEnd = null;
5562        },
5563
5564
5565        /**
5566         * @ngdoc method
5567         * @name $cacheFactory.Cache#destroy
5568         * @kind function
5569         *
5570         * @description
5571         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
5572         * removing it from the {@link $cacheFactory $cacheFactory} set.
5573         */
5574        destroy: function() {
5575          data = null;
5576          stats = null;
5577          lruHash = null;
5578          delete caches[cacheId];
5579        },
5580
5581
5582        /**
5583         * @ngdoc method
5584         * @name $cacheFactory.Cache#info
5585         * @kind function
5586         *
5587         * @description
5588         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5589         *
5590         * @returns {object} an object with the following properties:
5591         *   <ul>
5592         *     <li>**id**: the id of the cache instance</li>
5593         *     <li>**size**: the number of entries kept in the cache instance</li>
5594         *     <li>**...**: any additional properties from the options object when creating the
5595         *       cache.</li>
5596         *   </ul>
5597         */
5598        info: function() {
5599          return extend({}, stats, {size: size});
5600        }
5601      };
5602
5603
5604      /**
5605       * makes the `entry` the freshEnd of the LRU linked list
5606       */
5607      function refresh(entry) {
5608        if (entry != freshEnd) {
5609          if (!staleEnd) {
5610            staleEnd = entry;
5611          } else if (staleEnd == entry) {
5612            staleEnd = entry.n;
5613          }
5614
5615          link(entry.n, entry.p);
5616          link(entry, freshEnd);
5617          freshEnd = entry;
5618          freshEnd.n = null;
5619        }
5620      }
5621
5622
5623      /**
5624       * bidirectionally links two entries of the LRU linked list
5625       */
5626      function link(nextEntry, prevEntry) {
5627        if (nextEntry != prevEntry) {
5628          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5629          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5630        }
5631      }
5632    }
5633
5634
5635  /**
5636   * @ngdoc method
5637   * @name $cacheFactory#info
5638   *
5639   * @description
5640   * Get information about all the caches that have been created
5641   *
5642   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5643   */
5644    cacheFactory.info = function() {
5645      var info = {};
5646      forEach(caches, function(cache, cacheId) {
5647        info[cacheId] = cache.info();
5648      });
5649      return info;
5650    };
5651
5652
5653  /**
5654   * @ngdoc method
5655   * @name $cacheFactory#get
5656   *
5657   * @description
5658   * Get access to a cache object by the `cacheId` used when it was created.
5659   *
5660   * @param {string} cacheId Name or id of a cache to access.
5661   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5662   */
5663    cacheFactory.get = function(cacheId) {
5664      return caches[cacheId];
5665    };
5666
5667
5668    return cacheFactory;
5669  };
5670}
5671
5672/**
5673 * @ngdoc service
5674 * @name $templateCache
5675 *
5676 * @description
5677 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5678 * can load templates directly into the cache in a `script` tag, or by consuming the
5679 * `$templateCache` service directly.
5680 *
5681 * Adding via the `script` tag:
5682 *
5683 * ```html
5684 *   <script type="text/ng-template" id="templateId.html">
5685 *     <p>This is the content of the template</p>
5686 *   </script>
5687 * ```
5688 *
5689 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5690 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
5691 * element with ng-app attribute), otherwise the template will be ignored.
5692 *
5693 * Adding via the $templateCache service:
5694 *
5695 * ```js
5696 * var myApp = angular.module('myApp', []);
5697 * myApp.run(function($templateCache) {
5698 *   $templateCache.put('templateId.html', 'This is the content of the template');
5699 * });
5700 * ```
5701 *
5702 * To retrieve the template later, simply use it in your HTML:
5703 * ```html
5704 * <div ng-include=" 'templateId.html' "></div>
5705 * ```
5706 *
5707 * or get it via Javascript:
5708 * ```js
5709 * $templateCache.get('templateId.html')
5710 * ```
5711 *
5712 * See {@link ng.$cacheFactory $cacheFactory}.
5713 *
5714 */
5715function $TemplateCacheProvider() {
5716  this.$get = ['$cacheFactory', function($cacheFactory) {
5717    return $cacheFactory('templates');
5718  }];
5719}
5720
5721/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5722 *
5723 * DOM-related variables:
5724 *
5725 * - "node" - DOM Node
5726 * - "element" - DOM Element or Node
5727 * - "$node" or "$element" - jqLite-wrapped node or element
5728 *
5729 *
5730 * Compiler related stuff:
5731 *
5732 * - "linkFn" - linking fn of a single directive
5733 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5734 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5735 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5736 */
5737
5738
5739/**
5740 * @ngdoc service
5741 * @name $compile
5742 * @kind function
5743 *
5744 * @description
5745 * Compiles an HTML string or DOM into a template and produces a template function, which
5746 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5747 *
5748 * The compilation is a process of walking the DOM tree and matching DOM elements to
5749 * {@link ng.$compileProvider#directive directives}.
5750 *
5751 * <div class="alert alert-warning">
5752 * **Note:** This document is an in-depth reference of all directive options.
5753 * For a gentle introduction to directives with examples of common use cases,
5754 * see the {@link guide/directive directive guide}.
5755 * </div>
5756 *
5757 * ## Comprehensive Directive API
5758 *
5759 * There are many different options for a directive.
5760 *
5761 * The difference resides in the return value of the factory function.
5762 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5763 * or just the `postLink` function (all other properties will have the default values).
5764 *
5765 * <div class="alert alert-success">
5766 * **Best Practice:** It's recommended to use the "directive definition object" form.
5767 * </div>
5768 *
5769 * Here's an example directive declared with a Directive Definition Object:
5770 *
5771 * ```js
5772 *   var myModule = angular.module(...);
5773 *
5774 *   myModule.directive('directiveName', function factory(injectables) {
5775 *     var directiveDefinitionObject = {
5776 *       priority: 0,
5777 *       template: '<div></div>
5777', // or // function(tElement, tAttrs) { ... },
5778 *       // or
5779 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5780 *       transclude: false,
5781 *       restrict: 'A',
5782 *       templateNamespace: 'html',
5783 *       scope: false,
5784 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5785 *       controllerAs: 'stringAlias',
5786 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5787 *       compile: function compile(tElement, tAttrs, transclude) {
5788 *         return {
5789 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5790 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5791 *         }
5792 *         // or
5793 *         // return function postLink( ... ) { ... }
5794 *       },
5795 *       // or
5796 *       // link: {
5797 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5798 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5799 *       // }
5800 *       // or
5801 *       // link: function postLink( ... ) { ... }
5802 *     };
5803 *     return directiveDefinitionObject;
5804 *   });
5805 * ```
5806 *
5807 * <div class="alert alert-warning">
5808 * **Note:** Any unspecified options will use the default value. You can see the default values below.
5809 * </div>
5810 *
5811 * Therefore the above can be simplified as:
5812 *
5813 * ```js
5814 *   var myModule = angular.module(...);
5815 *
5816 *   myModule.directive('directiveName', function factory(injectables) {
5817 *     var directiveDefinitionObject = {
5818 *       link: function postLink(scope, iElement, iAttrs) { ... }
5819 *     };
5820 *     return directiveDefinitionObject;
5821 *     // or
5822 *     // return function postLink(scope, iElement, iAttrs) { ... }
5823 *   });
5824 * ```
5825 *
5826 *
5827 *
5828 * ### Directive Definition Object
5829 *
5830 * The directive definition object provides instructions to the {@link ng.$compile
5831 * compiler}. The attributes are:
5832 *
5833 * #### `multiElement`
5834 * When this property is set to true, the HTML compiler will collect DOM nodes between
5835 * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
5836 * together as the directive elements. It is recommended that this feature be used on directives
5837 * which are not strictly behavioural (such as {@link ngClick}), and which
5838 * do not manipulate or replace child nodes (such as {@link ngInclude}).
5839 *
5840 * #### `priority`
5841 * When there are multiple directives defined on a single DOM element, sometimes it
5842 * is necessary to specify the order in which the directives are applied. The `priority` is used
5843 * to sort the directives before their `compile` functions get called. Priority is defined as a
5844 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5845 * are also run in priority order, but post-link functions are run in reverse order. The order
5846 * of directives with the same priority is undefined. The default priority is `0`.
5847 *
5848 * #### `terminal`
5849 * If set to true then the current `priority` will be the last set of directives
5850 * which will execute (any directives at the current priority will still execute
5851 * as the order of execution on same `priority` is undefined). Note that expressions
5852 * and other directives used in the directive's template will also be excluded from execution.
5853 *
5854 * #### `scope`
5855 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5856 * same element request a new scope, only one new scope is created. The new scope rule does not
5857 * apply for the root of the template since the root of the template always gets a new scope.
5858 *
5859 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5860 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5861 * when creating reusable components, which should not accidentally read or modify data in the
5862 * parent scope.
5863 *
5864 * The 'isolate' scope takes an object hash which defines a set of local scope properties
5865 * derived from the parent scope. These local properties are useful for aliasing values for
5866 * templates. Locals definition is a hash of local scope property to its source:
5867 *
5868 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5869 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5870 *   attribute name is assumed to be the same as the local name.
5871 *   Given `<widget my-attr="hello {{name}}">` and widget definition
5872 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5873 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5874 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5875 *   component scope).
5876 *
5877 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5878 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5879 *   name is specified then the attribute name is assumed to be the same as the local name.
5880 *   Given `<widget my-attr="parentModel">` and widget definition of
5881 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5882 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5883 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5884 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5885 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
5886 *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
5887 *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
5888 *
5889 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5890 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5891 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5892 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5893 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5894 *   pass data from the isolated scope via an expression to the parent scope, this can be
5895 *   done by passing a map of local variable names and values into the expression wrapper fn.
5896 *   For example, if the expression is `increment(amount)` then we can specify the amount value
5897 *   by calling the `localFn` as `localFn({amount: 22})`.
5898 *
5899 *
5900 * #### `bindToController`
5901 * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
5902 * allow a component to have its properties bound to the controller, rather than to scope. When the controller
5903 * is instantiated, the initial values of the isolate scope bindings are already available.
5904 *
5905 * #### `controller`
5906 * Controller constructor function. The controller is instantiated before the
5907 * pre-linking phase and it is shared with other directives (see
5908 * `require` attribute). This allows the directives to communicate with each other and augment
5909 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5910 *
5911 * * `$scope` - Current scope associated with the element
5912 * * `$element` - Current element
5913 * * `$attrs` - Current attributes object for the element
5914 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
5915 *   `function([scope], cloneLinkingFn, futureParentElement)`.
5916 *    * `scope`: optional argument to override the scope.
5917 *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
5918 *    * `futureParentElement`:
5919 *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
5920 *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
5921 *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
5922 *          and when the `cloneLinkinFn` is passed,
5923 *          as those elements need to created and cloned in a special way when they are defined outside their
5924 *          usual containers (e.g. like `<svg>`).
5925 *        * See also the `directive.templateNamespace` property.
5926 *
5927 *
5928 * #### `require`
5929 * Require another directive and inject its controller as the fourth argument to the linking function. The
5930 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5931 * injected argument will be an array in corresponding order. If no such directive can be
5932 * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5933 *
5934 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5935 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5936 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5937 * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5938 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5939 *   `null` to the `link` fn if not found.
5940 * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
5941 *   `null` to the `link` fn if not found.
5942 *
5943 *
5944 * #### `controllerAs`
5945 * Controller alias at the directive scope. An alias for the controller so it
5946 * can be referenced at the directive template. The directive needs to define a scope for this
5947 * configuration to be used. Useful in the case when directive is used as component.
5948 *
5949 *
5950 * #### `restrict`
5951 * String of subset of `EACM` which restricts the directive to a specific directive
5952 * declaration style. If omitted, the defaults (elements and attributes) are used.
5953 *
5954 * * `E` - Element name (default): `<my-directive></my-directive>`
5955 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5956 * * `C` - Class: `<div class="my-directive: exp;"></div>`
5957 * * `M` - Comment: `<!-- directive: my-directive exp -->`
5958 *
5959 *
5960 * #### `templateNamespace`
5961 * String representing the document type used by the markup in the template.
5962 * AngularJS needs this information as those elements need to be created and cloned
5963 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
5964 *
5965 * * `html` - All root nodes in the template are HTML. Root nodes may also be
5966 *   top-level elements such as `<svg>` or `<math>`.
5967 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
5968 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
5969 *
5970 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
5971 *
5972 * #### `template`
5973 * HTML markup that may:
5974 * * Replace the contents of the directive's element (default).
5975 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
5976 * * Wrap the contents of the directive's element (if `transclude` is true).
5977 *
5978 * Value may be:
5979 *
5980 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
5981 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
5982 *   function api below) and returns a string value.
5983 *
5984 *
5985 * #### `templateUrl`
5986 * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
5987 *
5988 * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
5989 * for later when the template has been resolved.  In the meantime it will continue to compile and link
5990 * sibling and parent elements as though this element had not contained any directives.
5991 *
5992 * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
5993 * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
5994 * case when only one deeply nested directive has `templateUrl`.
5995 *
5996 * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
5997 *
5998 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5999 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6000 * a string value representing the url.  In either case, the template URL is passed through {@link
6001 * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6002 *
6003 *
6004 * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6005 * specify what the template should replace. Defaults to `false`.
6006 *
6007 * * `true` - the template will replace the directive's element.
6008 * * `false` - the template will replace the contents of the directive's element.
6009 *
6010 * The replacement process migrates all of the attributes / classes from the old element to the new
6011 * one. See the {@link guide/directive#template-expanding-directive
6012 * Directives Guide} for an example.
6013 *
6014 * There are very few scenarios where element replacement is required for the application function,
6015 * the main one being reusable custom components that are used within SVG contexts
6016 * (because SVG doesn't work with custom elements in the DOM tree).
6017 *
6018 * #### `transclude`
6019 * Extract the contents of the element where the directive appears and make it available to the directive.
6020 * The contents are compiled and provided to the directive as a **transclusion function**. See the
6021 * {@link $compile#transclusion Transclusion} section below.
6022 *
6023 * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6024 * directive's element or the entire element:
6025 *
6026 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6027 * * `'element'` - transclude the whole of the directive's element including any directives on this
6028 *   element that defined at a lower priority than this directive. When used, the `template`
6029 *   property is ignored.
6030 *
6031 *
6032 * #### `compile`
6033 *
6034 * ```js
6035 *   function compile(tElement, tAttrs, transclude) { ... }
6036 * ```
6037 *
6038 * The compile function deals with transforming the template DOM. Since most directives do not do
6039 * template transformation, it is not used often. The compile function takes the following arguments:
6040 *
6041 *   * `tElement` - template element - The element where the directive has been declared. It is
6042 *     safe to do template transformation on the element and child elements only.
6043 *
6044 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6045 *     between all directive compile functions.
6046 *
6047 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6048 *
6049 * <div class="alert alert-warning">
6050 * **Note:** The template instance and the link instance may be different objects if the template has
6051 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6052 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6053 * should be done in a linking function rather than in a compile function.
6054 * </div>
6055
6056 * <div class="alert alert-warning">
6057 * **Note:** The compile function cannot handle directives that recursively use themselves in their
6058 * own templates or compile functions. Compiling these directives results in an infinite loop and a
6059 * stack overflow errors.
6060 *
6061 * This can be avoided by manually using $compile in the postLink function to imperatively compile
6062 * a directive's template instead of relying on automatic template compilation via `template` or
6063 * `templateUrl` declaration or manual compilation inside the compile function.
6064 * </div>
6065 *
6066 * <div class="alert alert-error">
6067 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6068 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6069 *   to the link function instead.
6070 * </div>
6071
6072 * A compile function can have a return value which can be either a function or an object.
6073 *
6074 * * returning a (post-link) function - is equivalent to registering the linking function via the
6075 *   `link` property of the config object when the compile function is empty.
6076 *
6077 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6078 *   control when a linking function should be called during the linking phase. See info about
6079 *   pre-linking and post-linking functions below.
6080 *
6081 *
6082 * #### `link`
6083 * This property is used only if the `compile` property is not defined.
6084 *
6085 * ```js
6086 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6087 * ```
6088 *
6089 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6090 * executed after the template has been cloned. This is where most of the directive logic will be
6091 * put.
6092 *
6093 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6094 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6095 *
6096 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6097 *     manipulate the children of the element only in `postLink` function since the children have
6098 *     already been linked.
6099 *
6100 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6101 *     between all directive linking functions.
6102 *
6103 *   * `controller` - a controller instance - A controller instance if at least one directive on the
6104 *     element defines a controller. The controller is shared among all the directives, which allows
6105 *     the directives to use the controllers as a communication channel.
6106 *
6107 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6108 *     This is the same as the `$transclude`
6109 *     parameter of directive controllers, see there for details.
6110 *     `function([scope], cloneLinkingFn, futureParentElement)`.
6111 *
6112 * #### Pre-linking function
6113 *
6114 * Executed before the child elements are linked. Not safe to do DOM transformation since the
6115 * compiler linking function will fail to locate the correct elements for linking.
6116 *
6117 * #### Post-linking function
6118 *
6119 * Executed after the child elements are linked.
6120 *
6121 * Note that child elements that contain `templateUrl` directives will not have been compiled
6122 * and linked since they are waiting for their template to load asynchronously and their own
6123 * compilation and linking has been suspended until that occurs.
6124 *
6125 * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6126 * for their async templates to be resolved.
6127 *
6128 *
6129 * ### Transclusion
6130 *
6131 * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
6132 * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6133 * scope from where they were taken.
6134 *
6135 * Transclusion is used (often with {@link ngTransclude}) to insert the
6136 * original contents of a directive's element into a specified place in the template of the directive.
6137 * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6138 * content has access to the properties on the scope from which it was taken, even if the directive
6139 * has isolated scope.
6140 * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6141 *
6142 * This makes it possible for the widget to have private state for its template, while the transcluded
6143 * content has access to its originating scope.
6144 *
6145 * <div class="alert alert-warning">
6146 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6147 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6148 * Testing Transclusion Directives}.
6149 * </div>
6150 *
6151 * #### Transclusion Functions
6152 *
6153 * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6154 * function** to the directive's `link` function and `controller`. This transclusion function is a special
6155 * **linking function** that will return the compiled contents linked to a new transclusion scope.
6156 *
6157 * <div class="alert alert-info">
6158 * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6159 * ngTransclude will deal with it for us.
6160 * </div>
6161 *
6162 * If you want to manually control the insertion and removal of the transcluded content in your directive
6163 * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6164 * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6165 *
6166 * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6167 * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6168 * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6169 *
6170 * <div class="alert alert-info">
6171 * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6172 * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6173 * </div>
6174 *
6175 * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6176 * attach function**:
6177 *
6178 * ```js
6179 * var transcludedContent, transclusionScope;
6180 *
6181 * $transclude(function(clone, scope) {
6182 *   element.append(clone);
6183 *   transcludedContent = clone;
6184 *   transclusionScope = scope;
6185 * });
6186 * ```
6187 *
6188 * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6189 * associated transclusion scope:
6190 *
6191 * ```js
6192 * transcludedContent.remove();
6193 * transclusionScope.$destroy();
6194 * ```
6195 *
6196 * <div class="alert alert-info">
6197 * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6198 * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
6199 * then you are also responsible for calling `$destroy` on the transclusion scope.
6200 * </div>
6201 *
6202 * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6203 * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6204 * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6205 *
6206 *
6207 * #### Transclusion Scopes
6208 *
6209 * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6210 * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6211 * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6212 * was taken.
6213 *
6214 * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6215 * like this:
6216 *
6217 * ```html
6218 * <div ng-app>
6219 *   <div isolate>
6220 *     <div transclusion>
6221 *     </div>
6222 *   </div>
6223 * </div>
6224 * ```
6225 *
6226 * The `$parent` scope hierarchy will look like this:
6227 *
6228 * ```
6229 * - $rootScope
6230 *   - isolate
6231 *     - transclusion
6232 * ```
6233 *
6234 * but the scopes will inherit prototypically from different scopes to their `$parent`.
6235 *
6236 * ```
6237 * - $rootScope
6238 *   - transclusion
6239 * - isolate
6240 * ```
6241 *
6242 *
6243 * ### Attributes
6244 *
6245 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6246 * `link()` or `compile()` functions. It has a variety of uses.
6247 *
6248 * accessing *Normalized attribute names:*
6249 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6250 * the attributes object allows for normalized access to
6251 *   the attributes.
6252 *
6253 * * *Directive inter-communication:* All directives share the same instance of the attributes
6254 *   object which allows the directives to use the attributes object as inter directive
6255 *   communication.
6256 *
6257 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6258 *   allowing other directives to read the interpolated value.
6259 *
6260 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6261 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6262 *   the only way to easily get the actual value because during the linking phase the interpolation
6263 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6264 *
6265 * ```js
6266 * function linkingFn(scope, elm, attrs, ctrl) {
6267 *   // get the attribute value
6268 *   console.log(attrs.ngModel);
6269 *
6270 *   // change the attribute
6271 *   attrs.$set('ngModel', 'new value');
6272 *
6273 *   // observe changes to interpolated attribute
6274 *   attrs.$observe('ngModel', function(value) {
6275 *     console.log('ngModel has changed value to ' + value);
6276 *   });
6277 * }
6278 * ```
6279 *
6280 * ## Example
6281 *
6282 * <div class="alert alert-warning">
6283 * **Note**: Typically directives are registered with `module.directive`. The example below is
6284 * to illustrate how `$compile` works.
6285 * </div>
6286 *
6287 <example module="compileExample">
6288   <file name="index.html">
6289    <script>
6290      angular.module('compileExample', [], function($compileProvider) {
6291        // configure new 'compile' directive by passing a directive
6292        // factory function. The factory function injects the '$compile'
6293        $compileProvider.directive('compile', function($compile) {
6294          // directive factory creates a link function
6295          return function(scope, element, attrs) {
6296            scope.$watch(
6297              function(scope) {
6298                 // watch the 'compile' expression for changes
6299                return scope.$eval(attrs.compile);
6300              },
6301              function(value) {
6302                // when the 'compile' expression changes
6303                // assign it into the current DOM
6304                element.html(value);
6305
6306                // compile the new DOM and link it to the current
6307                // scope.
6308                // NOTE: we only compile .childNodes so that
6309                // we don't get into infinite loop compiling ourselves
6310                $compile(element.contents())(scope);
6311              }
6312            );
6313          };
6314        });
6315      })
6316      .controller('GreeterController', ['$scope', function($scope) {
6317        $scope.name = 'Angular';
6318        $scope.html = 'Hello {{name}}';
6319      }]);
6320    </script>
6321    <div ng-controller="GreeterController">
6322      <input ng-model="name"> <br>
6323      <textarea ng-model="html"></textarea> <br>
6324      <div compile="html"></div>
6325    </div>
6326   </file>
6327   <file name="protractor.js" type="protractor">
6328     it('should auto compile', function() {
6329       var textarea = $('textarea');
6330       var output = $('div[compile]');
6331       // The initial state reads 'Hello Angular'.
6332       expect(output.getText()).toBe('Hello Angular');
6333       textarea.clear();
6334       textarea.sendKeys('{{name}}!');
6335       expect(output.getText()).toBe('Angular!');
6336     });
6337   </file>
6338 </example>
6339
6340 *
6341 *
6342 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
6343 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
6344 *
6345 * <div class="alert alert-error">
6346 * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
6347 *   e.g. will not use the right outer scope. Please pass the transclude function as a
6348 *   `parentBoundTranscludeFn` to the link function instead.
6349 * </div>
6350 *
6351 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
6352 *                 root element(s), not their children)
6353 * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
6354 * (a DOM element/tree) to a scope. Where:
6355 *
6356 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
6357 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
6358 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
6359 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
6360 *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
6361 *
6362 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
6363 *      * `scope` - is the current scope with which the linking function is working with.
6364 *
6365 *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
6366 *  keys may be used to control linking behavior:
6367 *
6368 *      * `parentBoundTranscludeFn` - the transclude function made available to
6369 *        directives; if given, it will be passed through to the link functions of
6370 *        directives found in `element` during compilation.
6371 *      * `transcludeControllers` - an object hash with keys that map controller names
6372 *        to controller instances; if given, it will make the controllers
6373 *        available to directives.
6374 *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6375 *        the cloned elements; only needed for transcludes that are allowed to contain non html
6376 *        elements (e.g. SVG elements). See also the directive.controller property.
6377 *
6378 * Calling the linking function returns the element of the template. It is either the original
6379 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
6380 *
6381 * After linking the view is not updated until after a call to $digest which typically is done by
6382 * Angular automatically.
6383 *
6384 * If you need access to the bound view, there are two ways to do it:
6385 *
6386 * - If you are not asking the linking function to clone the template, create the DOM element(s)
6387 *   before you send them to the compiler and keep this reference around.
6388 *   ```js
6389 *     var element = $compile('<p>{{total}}</p>')(scope);
6390 *   ```
6391 *
6392 * - if on the other hand, you need the element to be cloned, the view reference from the original
6393 *   example would not point to the clone, but rather to the original template that was cloned. In
6394 *   this case, you can access the clone via the cloneAttachFn:
6395 *   ```js
6396 *     var templateElement = angular.element('<p>{{total}}</p>'),
6397 *         scope = ....;
6398 *
6399 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
6400 *       //attach the clone to DOM document at the right place
6401 *     });
6402 *
6403 *     //now we have reference to the cloned DOM via `clonedElement`
6404 *   ```
6405 *
6406 *
6407 * For information on how the compiler works, see the
6408 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
6409 */
6410
6411var $compileMinErr = minErr('$compile');
6412
6413/**
6414 * @ngdoc provider
6415 * @name $compileProvider
6416 *
6417 * @description
6418 */
6419$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
6420function $CompileProvider($provide, $$sanitizeUriProvider) {
6421  var hasDirectives = {},
6422      Suffix = 'Directive',
6423      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
6424      CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
6425      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
6426      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
6427
6428  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
6429  // The assumption is that future DOM event attribute names will begin with
6430  // 'on' and be composed of only English letters.
6431  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
6432
6433  function parseIsolateBindings(scope, directiveName) {
6434    var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
6435
6436    var bindings = {};
6437
6438    forEach(scope, function(definition, scopeName) {
6439      var match = definition.match(LOCAL_REGEXP);
6440
6441      if (!match) {
6442        throw $compileMinErr('iscp',
6443            "Invalid isolate scope definition for directive '{0}'." +
6444            " Definition: {... {1}: '{2}' ...}",
6445            directiveName, scopeName, definition);
6446      }
6447
6448      bindings[scopeName] = {
6449        mode: match[1][0],
6450        collection: match[2] === '*',
6451        optional: match[3] === '?',
6452        attrName: match[4] || scopeName
6453      };
6454    });
6455
6456    return bindings;
6457  }
6458
6459  /**
6460   * @ngdoc method
6461   * @name $compileProvider#directive
6462   * @kind function
6463   *
6464   * @description
6465   * Register a new directive with the compiler.
6466   *
6467   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
6468   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
6469   *    names and the values are the factories.
6470   * @param {Function|Array} directiveFactory An injectable directive factory function. See
6471   *    {@link guide/directive} for more info.
6472   * @returns {ng.$compileProvider} Self for chaining.
6473   */
6474   this.directive = function registerDirective(name, directiveFactory) {
6475    assertNotHasOwnProperty(name, 'directive');
6476    if (isString(name)) {
6477      assertArg(directiveFactory, 'directiveFactory');
6478      if (!hasDirectives.hasOwnProperty(name)) {
6479        hasDirectives[name] = [];
6480        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
6481          function($injector, $exceptionHandler) {
6482            var directives = [];
vendor: 10,281 bytes, lines 6483-6753
6483            forEach(hasDirectives[name], function(directiveFactory, index) {
6484              try {
6485                var directive = $injector.invoke(directiveFactory);
6486                if (isFunction(directive)) {
6487                  directive = { compile: valueFn(directive) };
6488                } else if (!directive.compile && directive.link) {
6489                  directive.compile = valueFn(directive.link);
6490                }
6491                directive.priority = directive.priority || 0;
6492                directive.index = index;
6493                directive.name = directive.name || name;
6494                directive.require = directive.require || (directive.controller && directive.name);
6495                directive.restrict = directive.restrict || 'EA';
6496                if (isObject(directive.scope)) {
6497                  directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name);
6498                }
6499                directives.push(directive);
6500              } catch (e) {
6501                $exceptionHandler(e);
6502              }
6503            });
6504            return directives;
6505          }]);
6506      }
6507      hasDirectives[name].push(directiveFactory);
6508    } else {
6509      forEach(name, reverseParams(registerDirective));
6510    }
6511    return this;
6512  };
6513
6514
6515  /**
6516   * @ngdoc method
6517   * @name $compileProvider#aHrefSanitizationWhitelist
6518   * @kind function
6519   *
6520   * @description
6521   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6522   * urls during a[href] sanitization.
6523   *
6524   * The sanitization is a security measure aimed at preventing XSS attacks via html links.
6525   *
6526   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
6527   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
6528   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6529   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6530   *
6531   * @param {RegExp=} regexp New regexp to whitelist urls with.
6532   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6533   *    chaining otherwise.
6534   */
6535  this.aHrefSanitizationWhitelist = function(regexp) {
6536    if (isDefined(regexp)) {
6537      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
6538      return this;
6539    } else {
6540      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
6541    }
6542  };
6543
6544
6545  /**
6546   * @ngdoc method
6547   * @name $compileProvider#imgSrcSanitizationWhitelist
6548   * @kind function
6549   *
6550   * @description
6551   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6552   * urls during img[src] sanitization.
6553   *
6554   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
6555   *
6556   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
6557   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
6558   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6559   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6560   *
6561   * @param {RegExp=} regexp New regexp to whitelist urls with.
6562   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6563   *    chaining otherwise.
6564   */
6565  this.imgSrcSanitizationWhitelist = function(regexp) {
6566    if (isDefined(regexp)) {
6567      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
6568      return this;
6569    } else {
6570      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
6571    }
6572  };
6573
6574  /**
6575   * @ngdoc method
6576   * @name  $compileProvider#debugInfoEnabled
6577   *
6578   * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
6579   * current debugInfoEnabled state
6580   * @returns {*} current value if used as getter or itself (chaining) if used as setter
6581   *
6582   * @kind function
6583   *
6584   * @description
6585   * Call this method to enable/disable various debug runtime information in the compiler such as adding
6586   * binding information and a reference to the current scope on to DOM elements.
6587   * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
6588   * * `ng-binding` CSS class
6589   * * `$binding` data property containing an array of the binding expressions
6590   *
6591   * You may want to disable this in production for a significant performance boost. See
6592   * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
6593   *
6594   * The default value is true.
6595   */
6596  var debugInfoEnabled = true;
6597  this.debugInfoEnabled = function(enabled) {
6598    if (isDefined(enabled)) {
6599      debugInfoEnabled = enabled;
6600      return this;
6601    }
6602    return debugInfoEnabled;
6603  };
6604
6605  this.$get = [
6606            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
6607            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
6608    function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
6609             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
6610
6611    var Attributes = function(element, attributesToCopy) {
6612      if (attributesToCopy) {
6613        var keys = Object.keys(attributesToCopy);
6614        var i, l, key;
6615
6616        for (i = 0, l = keys.length; i < l; i++) {
6617          key = keys[i];
6618          this[key] = attributesToCopy[key];
6619        }
6620      } else {
6621        this.$attr = {};
6622      }
6623
6624      this.$$element = element;
6625    };
6626
6627    Attributes.prototype = {
6628      /**
6629       * @ngdoc method
6630       * @name $compile.directive.Attributes#$normalize
6631       * @kind function
6632       *
6633       * @description
6634       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
6635       * `data-`) to its normalized, camelCase form.
6636       *
6637       * Also there is special case for Moz prefix starting with upper case letter.
6638       *
6639       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
6640       *
6641       * @param {string} name Name to normalize
6642       */
6643      $normalize: directiveNormalize,
6644
6645
6646      /**
6647       * @ngdoc method
6648       * @name $compile.directive.Attributes#$addClass
6649       * @kind function
6650       *
6651       * @description
6652       * Adds the CSS class value specified by the classVal parameter to the element. If animations
6653       * are enabled then an animation will be triggered for the class addition.
6654       *
6655       * @param {string} classVal The className value that will be added to the element
6656       */
6657      $addClass: function(classVal) {
6658        if (classVal && classVal.length > 0) {
6659          $animate.addClass(this.$$element, classVal);
6660        }
6661      },
6662
6663      /**
6664       * @ngdoc method
6665       * @name $compile.directive.Attributes#$removeClass
6666       * @kind function
6667       *
6668       * @description
6669       * Removes the CSS class value specified by the classVal parameter from the element. If
6670       * animations are enabled then an animation will be triggered for the class removal.
6671       *
6672       * @param {string} classVal The className value that will be removed from the element
6673       */
6674      $removeClass: function(classVal) {
6675        if (classVal && classVal.length > 0) {
6676          $animate.removeClass(this.$$element, classVal);
6677        }
6678      },
6679
6680      /**
6681       * @ngdoc method
6682       * @name $compile.directive.Attributes#$updateClass
6683       * @kind function
6684       *
6685       * @description
6686       * Adds and removes the appropriate CSS class values to the element based on the difference
6687       * between the new and old CSS class values (specified as newClasses and oldClasses).
6688       *
6689       * @param {string} newClasses The current CSS className value
6690       * @param {string} oldClasses The former CSS className value
6691       */
6692      $updateClass: function(newClasses, oldClasses) {
6693        var toAdd = tokenDifference(newClasses, oldClasses);
6694        if (toAdd && toAdd.length) {
6695          $animate.addClass(this.$$element, toAdd);
6696        }
6697
6698        var toRemove = tokenDifference(oldClasses, newClasses);
6699        if (toRemove && toRemove.length) {
6700          $animate.removeClass(this.$$element, toRemove);
6701        }
6702      },
6703
6704      /**
6705       * Set a normalized attribute on the element in a way such that all directives
6706       * can share the attribute. This function properly handles boolean attributes.
6707       * @param {string} key Normalized key. (ie ngAttribute)
6708       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
6709       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
6710       *     Defaults to true.
6711       * @param {string=} attrName Optional none normalized name. Defaults to key.
6712       */
6713      $set: function(key, value, writeAttr, attrName) {
6714        // TODO: decide whether or not to throw an error if "class"
6715        //is set through this function since it may cause $updateClass to
6716        //become unstable.
6717
6718        var node = this.$$element[0],
6719            booleanKey = getBooleanAttrName(node, key),
6720            aliasedKey = getAliasedAttrName(node, key),
6721            observer = key,
6722            nodeName;
6723
6724        if (booleanKey) {
6725          this.$$element.prop(key, value);
6726          attrName = booleanKey;
6727        } else if (aliasedKey) {
6728          this[aliasedKey] = value;
6729          observer = aliasedKey;
6730        }
6731
6732        this[key] = value;
6733
6734        // translate normalized key to actual key
6735        if (attrName) {
6736          this.$attr[key] = attrName;
6737        } else {
6738          attrName = this.$attr[key];
6739          if (!attrName) {
6740            this.$attr[key] = attrName = snake_case(key, '-');
6741          }
6742        }
6743
6744        nodeName = nodeName_(this.$$element);
6745
6746        if ((nodeName === 'a' && key === 'href') ||
6747            (nodeName === 'img' && key === 'src')) {
6748          // sanitize a[href] and img[src] values
6749          this[key] = value = $$sanitizeUri(value, key === 'src');
6750        } else if (nodeName === 'img' && key === 'srcset') {
6751          // sanitize img[srcset] values
6752          var result = "";
6753
6754          // first check if there are spaces because it's not the same pattern
6755          var trimmedSrcset = trim(value);
6756          //                (   999x   ,|   999w   ,|   ,|,   )
6757          var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
6758          var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
6759
6760          // split srcset into tuple of uri and descriptor except for the last item
6761          var rawUris = trimmedSrcset.split(pattern);
6762
6763          // for each tuples
6764          var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
6765          for (var i = 0; i < nbrUrisWith2parts; i++) {
6766            var innerIdx = i * 2;
6767            // sanitize the uri
6768            result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
6769            // add the descriptor
6770            result += (" " + trim(rawUris[innerIdx + 1]));
6771          }
6772
6773          // split the last item into uri and descriptor
6774          var lastTuple = trim(rawUris[i * 2]).split(/\s/);
6775
6776          // sanitize the last uri
6777          result += $$sanitizeUri(trim(lastTuple[0]), true);
6778
6779          // and add the last descriptor if any
6780          if (lastTuple.length === 2) {
6781            result += (" " + trim(lastTuple[1]));
6782          }
6783          this[key] = value = result;
6784        }
6785
6786        if (writeAttr !== false) {
6787          if (value === null || value === undefined) {
6788            this.$$element.removeAttr(attrName);
6789          } else {
6790            this.$$element.attr(attrName, value);
6791          }
6792        }
6793
6794        // fire observers
6795        var $$observers = this.$$observers;
6796        $$observers && forEach($$observers[observer], function(fn) {
6797          try {
6798            fn(value);
6799          } catch (e) {
6800            $exceptionHandler(e);
6801          }
6802        });
6803      },
6804
6805
6806      /**
6807       * @ngdoc method
6808       * @name $compile.directive.Attributes#$observe
6809       * @kind function
6810       *
6811       * @description
6812       * Observes an interpolated attribute.
6813       *
6814       * The observer function will be invoked once during the next `$digest` following
6815       * compilation. The observer is then invoked whenever the interpolated value
6816       * changes.
6817       *
6818       * @param {string} key Normalized key. (ie ngAttribute) .
6819       * @param {function(interpolatedValue)} fn Function that will be called whenever
6820                the interpolated value of the attribute changes.
6821       *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
6822       * @returns {function()} Returns a deregistration function for this observer.
6823       */
6824      $observe: function(key, fn) {
6825        var attrs = this,
6826            $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
6827            listeners = ($$observers[key] || ($$observers[key] = []));
6828
6829        listeners.push(fn);
6830        $rootScope.$evalAsync(function() {
6831          if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
6832            // no one registered attribute interpolation function, so lets call it manually
6833            fn(attrs[key]);
6834          }
6835        });
6836
6837        return function() {
6838          arrayRemove(listeners, fn);
6839        };
6840      }
6841    };
6842
6843
6844    function safeAddClass($element, className) {
6845      try {
6846        $element.addClass(className);
6847      } catch (e) {
6848        // ignore, since it means that we are trying to set class on
6849        // SVG element, where class name is read-only.
6850      }
6851    }
6852
6853
6854    var startSymbol = $interpolate.startSymbol(),
6855        endSymbol = $interpolate.endSymbol(),
6856        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
6857            ? identity
6858            : function denormalizeTemplate(template) {
6859              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
6860        },
6861        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
6862
6863    compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
6864      var bindings = $element.data('$binding') || [];
6865
6866      if (isArray(binding)) {
6867        bindings = bindings.concat(binding);
6868      } else {
6869        bindings.push(binding);
6870      }
6871
6872      $element.data('$binding', bindings);
6873    } : noop;
6874
6875    compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
6876      safeAddClass($element, 'ng-binding');
6877    } : noop;
6878
6879    compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
6880      var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') 
6880: '$scope';
6881      $element.data(dataName, scope);
6882    } : noop;
6883
6884    compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
6885      safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
6886    } : noop;
6887
6888    return compile;
6889
6890    //================================
6891
6892    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
6893                        previousCompileContext) {
6894      if (!($compileNodes instanceof jqLite)) {
6895        // jquery always rewraps, whereas we need to preserve the original selector so that we can
6896        // modify it.
6897        $compileNodes = jqLite($compileNodes);
6898      }
6899      // We can not compile top level text elements since text nodes can be merged and we will
6900      // not be able to attach scope data to them, so we will wrap them in <span>
6901      forEach($compileNodes, function(node, index) {
6902        if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
6903          $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
6904        }
6905      });
6906      var compositeLinkFn =
6907              compileNodes($compileNodes, transcludeFn, $compileNodes,
6908                           maxPriority, ignoreDirective, previousCompileContext);
6909      compile.$$addScopeClass($compileNodes);
6910      var namespace = null;
6911      return function publicLinkFn(scope, cloneConnectFn, options) {
6912        assertArg(scope, 'scope');
6913
6914        options = options || {};
6915        var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
6916          transcludeControllers = options.transcludeControllers,
6917          futureParentElement = options.futureParentElement;
6918
6919        // When `parentBoundTranscludeFn` is passed, it is a
6920        // `controllersBoundTransclude` function (it was previously passed
6921        // as `transclude` to directive.link) so we must unwrap it to get
6922        // its `boundTranscludeFn`
6923        if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
6924          parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
6925        }
6926
6927        if (!namespace) {
6928          namespace = detectNamespaceForChildElements(futureParentElement);
6929        }
6930        var $linkNode;
6931        if (namespace !== 'html') {
6932          // When using a directive with replace:true and templateUrl the $compileNodes
6933          // (or a child element inside of them)
6934          // might change, so we need to recreate the namespace adapted compileNodes
6935          // for call to the link function.
6936          // Note: This will already clone the nodes...
6937          $linkNode = jqLite(
6938            wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
6939          );
6940        } else if (cloneConnectFn) {
6941          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
6942          // and sometimes changes the structure of the DOM.
6943          $linkNode = JQLitePrototype.clone.call($compileNodes);
6944        } else {
6945          $linkNode = $compileNodes;
6946        }
6947
6948        if (transcludeControllers) {
6949          for (var controllerName in transcludeControllers) {
6950            $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
6951          }
6952        }
6953
6954        compile.$$addScopeInfo($linkNode, scope);
6955
6956        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
6957        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
6958        return $linkNode;
6959      };
6960    }
6961
6962    function detectNamespaceForChildElements(parentElement) {
6963      // TODO: Make this detect MathML as well...
6964      var node = parentElement && parentElement[0];
6965      if (!node) {
6966        return 'html';
6967      } else {
6968        return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
6969      }
6970    }
6971
6972    /**
6973     * Compile function matches each node in nodeList against the directives. Once all directives
6974     * for a particular node are collected their compile functions are executed. The compile
6975     * functions return values - the linking functions - are combined into a composite linking
6976     * function, which is the a linking function for the node.
6977     *
6978     * @param {NodeList} nodeList an array of nodes or NodeList to compile
6979     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6980     *        scope argument is auto-generated to the new child of the transcluded parent scope.
6981     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
6982     *        the rootElement must be set the jqLite collection of the compile root. This is
vendor: 5,956 bytes, lines 6983-7131
6983     *        needed so that the jqLite collection items can be replaced with widgets.
6984     * @param {number=} maxPriority Max directive priority.
6985     * @returns {Function} A composite linking function of all of the matched directives or null.
6986     */
6987    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
6988                            previousCompileContext) {
6989      var linkFns = [],
6990          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
6991
6992      for (var i = 0; i < nodeList.length; i++) {
6993        attrs = new Attributes();
6994
6995        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
6996        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
6997                                        ignoreDirective);
6998
6999        nodeLinkFn = (directives.length)
7000            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7001                                      null, [], [], previousCompileContext)
7002            : null;
7003
7004        if (nodeLinkFn && nodeLinkFn.scope) {
7005          compile.$$addScopeClass(attrs.$$element);
7006        }
7007
7008        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7009                      !(childNodes = nodeList[i].childNodes) ||
7010                      !childNodes.length)
7011            ? null
7012            : compileNodes(childNodes,
7013                 nodeLinkFn ? (
7014                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7015                     && nodeLinkFn.transclude) : transcludeFn);
7016
7017        if (nodeLinkFn || childLinkFn) {
7018          linkFns.push(i, nodeLinkFn, childLinkFn);
7019          linkFnFound = true;
7020          nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7021        }
7022
7023        //use the previous context only for the first element in the virtual group
7024        previousCompileContext = null;
7025      }
7026
7027      // return a linking function if we have found anything, null otherwise
7028      return linkFnFound ? compositeLinkFn : null;
7029
7030      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7031        var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7032        var stableNodeList;
7033
7034
7035        if (nodeLinkFnFound) {
7036          // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7037          // offsets don't get screwed up
7038          var nodeListLength = nodeList.length;
7039          stableNodeList = new Array(nodeListLength);
7040
7041          // create a sparse array by only copying the elements which have a linkFn
7042          for (i = 0; i < linkFns.length; i+=3) {
7043            idx = linkFns[i];
7044            stableNodeList[idx] = nodeList[idx];
7045          }
7046        } else {
7047          stableNodeList = nodeList;
7048        }
7049
7050        for (i = 0, ii = linkFns.length; i < ii;) {
7051          node = stableNodeList[linkFns[i++]];
7052          nodeLinkFn = linkFns[i++];
7053          childLinkFn = linkFns[i++];
7054
7055          if (nodeLinkFn) {
7056            if (nodeLinkFn.scope) {
7057              childScope = scope.$new();
7058              compile.$$addScopeInfo(jqLite(node), childScope);
7059            } else {
7060              childScope = scope;
7061            }
7062
7063            if (nodeLinkFn.transcludeOnThisElement) {
7064              childBoundTranscludeFn = createBoundTranscludeFn(
7065                  scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
7066                  nodeLinkFn.elementTranscludeOnThisElement);
7067
7068            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7069              childBoundTranscludeFn = parentBoundTranscludeFn;
7070
7071            } else if (!parentBoundTranscludeFn && transcludeFn) {
7072              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7073
7074            } else {
7075              childBoundTranscludeFn = null;
7076            }
7077
7078            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7079
7080          } else if (childLinkFn) {
7081            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7082          }
7083        }
7084      }
7085    }
7086
7087    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
7088
7089      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7090
7091        if (!transcludedScope) {
7092          transcludedScope = scope.$new(false, containingScope);
7093          transcludedScope.$$transcluded = true;
7094        }
7095
7096        return transcludeFn(transcludedScope, cloneFn, {
7097          parentBoundTranscludeFn: previousBoundTranscludeFn,
7098          transcludeControllers: controllers,
7099          futureParentElement: futureParentElement
7100        });
7101      };
7102
7103      return boundTranscludeFn;
7104    }
7105
7106    /**
7107     * Looks for directives on the given node and adds them to the directive collection which is
7108     * sorted.
7109     *
7110     * @param node Node to search.
7111     * @param directives An array to which the directives are added to. This array is sorted before
7112     *        the function returns.
7113     * @param attrs The shared attrs object which is used to populate the normalized attributes.
7114     * @param {number=} maxPriority Max directive priority.
7115     */
7116    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7117      var nodeType = node.nodeType,
7118          attrsMap = attrs.$attr,
7119          match,
7120          className;
7121
7122      switch (nodeType) {
7123        case NODE_TYPE_ELEMENT: /* Element */
7124          // use the node name: <directive>
7125          addDirective(directives,
7126              directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7127
7128          // iterate over the attributes
7129          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7130                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7131            var attrStartName = false;
7132            var attrEndName = false;
7133
7134            attr = nAttrs[j];
7135            name = attr.name;
7136            value = trim(attr.value);
7137
7138            // support ngAttr attribute binding
7139            ngAttrName = directiveNormalize(name);
7140            if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7141              name = name.replace(PREFIX_REGEXP, '')
7142                .substr(8).replace(/_(.)/g, function(match, letter) {
7143                  return letter.toUpperCase();
7144                });
7145            }
7146
7147            var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
7148            if (directiveIsMultiElement(directiveNName)) {
7149              if (ngAttrName === directiveNName + 'Start') {
7150                attrStartName = name;
7151                attrEndName = name.substr(0, name.length - 5) + 'end';
7152                name = name.substr(0, name.length - 6);
7153              }
7154            }
7155
7156            nName = directiveNormalize(name.toLowerCase());
7157            attrsMap[nName] = name;
7158            if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7159                attrs[nName] = value;
7160                if (getBooleanAttrName(node, nName)) {
7161                  attrs[nName] = true; // presence means true
7162                }
7163            }
7164            addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7165            addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7166                          attrEndName);
7167          }
7168
7169          // use class as directive
7170          className = node.className;
7171          if (isObject(className)) {
7172              // Maybe SVGAnimatedString
7173              className = className.animVal;
7174          }
7175          if (isString(className) && className !== '') {
7176            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7177              nName = directiveNormalize(match[2]);
7178              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7179                attrs[nName] = trim(match[3]);
7180              }
7181              className = className.substr(match.index + match[0].length);
7182            }
7183          }
7184          break;
7185        case NODE_TYPE_TEXT: /* Text Node */
7186          addTextInterpolateDirective(directives, node.nodeValue);
7187          break;
7188        case NODE_TYPE_COMMENT: /* Comment */
7189          try {
7190            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7191            if (match) {
7192              nName = directiveNormalize(match[1]);
7193              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7194                attrs[nName] = trim(match[2]);
7195              }
7196            }
7197          } catch (e) {
7198            // turns out that under some circumstances IE9 throws errors when one attempts to read
7199            // comment's node value.
7200            // Just ignore it and continue. (Can't seem to reproduce in test case.)
7201          }
7202          break;
7203      }
7204
7205      directives.sort(byPriority);
7206      return directives;
7207    }
7208
7209    /**
7210     * Given a node with an directive-start it collects all of the siblings until it finds
7211     * directive-end.
7212     * @param node
7213     * @param attrStart
7214     * @param attrEnd
7215     * @returns {*}
7216     */
7217    function groupScan(node, attrStart, attrEnd) {
7218      var nodes = [];
7219      var depth = 0;
7220      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7221        do {
7222          if (!node) {
7223            throw $compileMinErr('uterdir',
7224                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7225                      attrStart, attrEnd);
7226          }
7227          if (node.nodeType == NODE_TYPE_ELEMENT) {
7228            if (node.hasAttribute(attrStart)) depth++;
7229            if (node.hasAttribute(attrEnd)) depth--;
7230          }
7231          nodes.push(node);
7232          node = node.nextSibling;
7233        } while (depth > 0);
7234      } else {
7235        nodes.push(node);
7236      }
7237
7238      return jqLite(nodes);
7239    }
7240
7241    /**
7242     * Wrapper for linking function which converts normal linking function into a grouped
7243     * linking function.
7244     * @param linkFn
7245     * @param attrStart
7246     * @param attrEnd
7247     * @returns {Function}
7248     */
7249    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7250      return function(scope, element, attrs, controllers, transcludeFn) {
7251        element = groupScan(element[0], attrStart, attrEnd);
7252        return linkFn(scope, element, attrs, controllers, transcludeFn);
7253      };
7254    }
7255
7256    /**
7257     * Once the directives have been collected, their compile functions are executed. This method
7258     * is responsible for inlining directive templates as well as terminating the application
7259     * of the directives if the terminal directive has been reached.
7260     *
7261     * @param {Array} directives Array of collected directives to execute their compile function.
7262     *        this needs to be pre-sorted by priority order.
7263     * @param {Node} compileNode The raw DOM node to apply the compile functions to
7264     * @param {Object} templateAttrs The shared attribute function
7265     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7266     *                                                  scope argument is auto-generated to the new
7267     *                                                  child of the transcluded parent scope.
7268     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
7269     *                              argument has the root jqLite array so that we can replace nodes
7270     *                              on it.
7271     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
7272     *                                           compiling the transclusion.
7273     * @param {Array.<Function>} preLinkFns
7274     * @param {Array.<Function>} postLinkFns
7275     * @param {Object} previousCompileContext Context used for previous compilation of the current
7276     *                                        node
7277     * @returns {Function} linkFn
7278     */
7279    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
7280                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
7281                                   previousCompileContext) {
7282      previousCompileContext = previousCompileContext || {};
7283
7284      var terminalPriority = -Number.MAX_VALUE,
7285          newScopeDirective,
7286          controllerDirectives = previousCompileContext.controllerDirectives,
7287          controllers,
7288          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
7289          templateDirective = previousCompileContext.templateDirective,
7290          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
7291          hasTranscludeDirective = false,
7292          hasTemplate = false,
7293          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
7294          $compileNode = templateAttrs.$$element = jqLite(compileNode),
7295          directive,
7296          directiveName,
7297          $template,
7298          replaceDirective = originalReplaceDirective,
7299          childTranscludeFn = transcludeFn,
7300          linkFn,
7301          directiveValue;
7302
7303      // executes all directives on the current element
7304      for (var i = 0, ii = directives.length; i < ii; i++) {
7305        directive = directives[i];
7306        var attrStart = directive.$$start;
7307        var attrEnd = directive.$$end;
7308
7309        // collect multiblock sections
7310        if (attrStart) {
7311          $compileNode = groupScan(compileNode, attrStart, attrEnd);
7312        }
7313        $template = undefined;
7314
7315        if (terminalPriority > directive.priority) {
7316          break; // prevent further processing of directives
7317        }
7318
7319        if (directiveValue = directive.scope) {
7320
7321          // skip the check for directives with async templates, we'll check the derived sync
7322          // directive when the template arrives
7323          if (!directive.templateUrl) {
7324            if (isObject(directiveValue)) {
7325              // This directive is trying to add an isolated scope.
7326              // Check that there is no scope of any kind already
7327              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
7328                                directive, $compileNode);
7329              newIsolateScopeDirective = directive;
7330            } else {
7331              // This directive is trying to add a child scope.
7332              // Check that there is no isolated scope already
7333              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
7334                                $compileNode);
7335            }
7336          }
7337
7338          newScopeDirective = newScopeDirective || directive;
7339        }
7340
7341        directiveName = directive.name;
7342
7343        if (!directive.templateUrl && directive.controller) {
7344          directiveValue = directive.controller;
7345          controllerDirectives = controllerDirectives || {};
7346          assertNoDuplicate("'" + directiveName + "' controller",
7347              controllerDirectives[directiveName], directive, $compileNode);
7348          controllerDirectives[directiveName] = directive;
7349        }
7350
7351        if (directiveValue = directive.transclude) {
7352          hasTranscludeDirective = true;
7353
7354          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
7355          // This option should only be used by directives that know how to safely handle element transclusion,
7356          // where the transcluded nodes are added or replaced after linking.
7357          if (!directive.$$tlb) {
7358            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
7359            nonTlbTranscludeDirective = directive;
7360          }
7361
7362          if (directiveValue == 'element') {
7363            hasElementTranscludeDirective = true;
7364            terminalPriority = directive.priority;
7365            $template = $compileNode;
7366            $compileNode = templateAttrs.$$element =
7367                jqLite(document.createComment(' ' + directiveName + ': ' +
7368                                              templateAttrs[directiveName] + ' '));
7369            compileNode = $compileNode[0];
7370            replaceWith(jqCollection, sliceArgs($template), compileNode);
7371
7372            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
7373                                        replaceDirective && replaceDirective.name, {
7374                                          // Don't pass in:
7375                                          // - controllerDirectives - otherwise we'll create duplicates controllers
7376                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 4,751 bytes, lines 7376-7484
7376ining templates with
7377                                          //   element transclusion doesn't make sense.
7378                                          //
7379                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
7380                                          // on the same element more than once.
7381                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
7382                                        });
7383          } else {
7384            $template = jqLite(jqLiteClone(compileNode)).contents();
7385            $compileNode.empty(); // clear contents
7386            childTranscludeFn = compile($template, transcludeFn);
7387          }
7388        }
7389
7390        if (directive.template) {
7391          hasTemplate = true;
7392          assertNoDuplicate('template', templateDirective, directive, $compileNode);
7393          templateDirective = directive;
7394
7395          directiveValue = (isFunction(directive.template))
7396              ? directive.template($compileNode, templateAttrs)
7397              : directive.template;
7398
7399          directiveValue = denormalizeTemplate(directiveValue);
7400
7401          if (directive.replace) {
7402            replaceDirective = directive;
7403            if (jqLiteIsTextNode(directiveValue)) {
7404              $template = [];
7405            } else {
7406              $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
7407            }
7408            compileNode = $template[0];
7409
7410            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7411              throw $compileMinErr('tplrt',
7412                  "Template for directive '{0}' must have exactly one root element. {1}",
7413                  directiveName, '');
7414            }
7415
7416            replaceWith(jqCollection, $compileNode, compileNode);
7417
7418            var newTemplateAttrs = {$attr: {}};
7419
7420            // combine directives from the original node and from the template:
7421            // - take the array of directives for this element
7422            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
7423            // - collect directives from the template and sort them by priority
7424            // - combine directives as: processed + template + unprocessed
7425            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
7426            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
7427
7428            if (newIsolateScopeDirective) {
7429              markDirectivesAsIsolate(templateDirectives);
7430            }
7431            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
7432            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
7433
7434            ii = directives.length;
7435          } else {
7436            $compileNode.html(directiveValue);
7437          }
7438        }
7439
7440        if (directive.templateUrl) {
7441          hasTemplate = true;
7442          assertNoDuplicate('template', templateDirective, directive, $compileNode);
7443          templateDirective = directive;
7444
7445          if (directive.replace) {
7446            replaceDirective = directive;
7447          }
7448
7449          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
7450              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
7451                controllerDirectives: controllerDirectives,
7452                newIsolateScopeDirective: newIsolateScopeDirective,
7453                templateDirective: templateDirective,
7454                nonTlbTranscludeDirective: nonTlbTranscludeDirective
7455              });
7456          ii = directives.length;
7457        } else if (directive.compile) {
7458          try {
7459            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
7460            if (isFunction(linkFn)) {
7461              addLinkFns(null, linkFn, attrStart, attrEnd);
7462            } else if (linkFn) {
7463              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
7464            }
7465          } catch (e) {
7466            $exceptionHandler(e, startingTag($compileNode));
7467          }
7468        }
7469
7470        if (directive.terminal) {
7471          nodeLinkFn.terminal = true;
7472          terminalPriority = Math.max(terminalPriority, directive.priority);
7473        }
7474
7475      }
7476
7477      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
7478      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
7479      nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
7480      nodeLinkFn.templateOnThisElement = hasTemplate;
7481      nodeLinkFn.transclude = childTranscludeFn;
7482
7483      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
7484
7485      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
7486      return nodeLinkFn;
7487
7488      ////////////////////
7489
7490      function addLinkFns(pre, post, attrStart, attrEnd) {
7491        if (pre) {
7492          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
7493          pre.require = directive.require;
7494          pre.directiveName = directiveName;
7495          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7496            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
7497          }
7498          preLinkFns.push(pre);
7499        }
7500        if (post) {
7501          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
7502          post.require = directive.require;
7503          post.directiveName = directiveName;
7504          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7505            post = cloneAndAnnotateFn(post, {isolateScope: true});
7506          }
7507          postLinkFns.push(post);
7508        }
7509      }
7510
7511
7512      function getControllers(directiveName, require, $element, elementControllers) {
7513        var value, retrievalMethod = 'data', optional = false;
7514        var $searchElement = $element;
7515        var match;
7516        if (isString(require)) {
7517          match = require.match(REQUIRE_PREFIX_REGEXP);
7518          require = require.substring(match[0].length);
7519
7520          if (match[3]) {
7521            if (match[1]) match[3] = null;
7522            else match[1] = match[3];
7523          }
7524          if (match[1] === '^') {
7525            retrievalMethod = 'inheritedData';
7526          } else if (match[1] === '^^') {
7527            retrievalMethod = 'inheritedData';
7528            $searchElement = $element.parent();
7529          }
7530          if (match[2] === '?') {
7531            optional = true;
7532          }
7533
7534          value = null;
7535
7536          if (elementControllers && retrievalMethod === 'data') {
7537            if (value = elementControllers[require]) {
7538              value = value.instance;
7539            }
7540          }
7541          value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
7542
7543          if (!value && !optional) {
7544            throw $compileMinErr('ctreq',
7545                "Controller '{0}', required by directive '{1}', can't be found!",
7546                require, directiveName);
7547          }
7548          return value || null;
7549        } else if (isArray(require)) {
7550          value = [];
7551          forEach(require, function(require) {
7552            value.push(getControllers(directiveName, require, $element, elementControllers));
7553          });
7554        }
7555        return value;
7556      }
7557
7558
7559      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
7560        var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
7561            attrs;
7562
7563        if (compileNode === linkNode) {
7564          attrs = templateAttrs;
7565          $element = templateAttrs.$$element;
7566        } else {
7567          $element = jqLite(linkNode);
7568          attrs = new Attributes($element, templateAttrs);
7569        }
7570
7571        if (newIsolateScopeDirective) {
7572          isolateScope = scope.$new(true);
7573        }
7574
7575        if (boundTranscludeFn) {
7576          // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
7577          // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
7578          transcludeFn = controllersBoundTransclude;
7579          transcludeFn.$$boundTransclude = boundTranscludeFn;
7580        }
7581
7582        if (controllerDirectives) {
7583          // TODO: merge `controllers` and `elementControllers` into single object.
7584          controllers = {};
7585          elementControllers = {};
7586          forEach(controllerDirectives, function(directive) {
7587            var locals = {
7588              $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
7589              $element: $element,
7590              $attrs: attrs,
7591              $transclude: transcludeFn
7592            }, controllerInstance;
7593
7594            controller = directive.controller;
7595            if (controller == '@') {
7596              controller = attrs[directive.name];
7597            }
7598
7599            controllerInstance = $controller(controller, locals, true, directive.controllerAs);
7600
7601            // For directives with element transclusion the element is a comment,
7602            // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
7603            // clean up (http://bugs.jquery.com/ticket/8335).
7604            // Instead, we save the controllers for the element in a local hash and attach to .data
7605            // later, once we have the actual element.
7606            elementControllers[directive.name] = controllerInstance;
7607            if (!hasElementTranscludeDirective) {
7608              $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
7609            }
7610
7611            controllers[directive.name] = controllerInstance;
7612          });
7613        }
7614
7615        if (newIsolateScopeDirective) {
7616          compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
7617              templateDirective === newIsolateScopeDirective.$$originalDirective)));
7618          compile.$$addScopeClass($element, true);
7619
7620          var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name];
7621          var isolateBindingContext = isolateScope;
7622          if (isolateScopeController && isolateScopeController.identifier &&
7623              newIsolateScopeDirective.bindToController === true) {
7624            isolateBindingContext = isolateScopeController.instance;
7625          }
7626
7627          forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) {
7628            var attrName = definition.attrName,
7629                optional = definition.optional,
7630                mode = definition.mode, // @, =, or &
7631                lastValue,
7632                parentGet, parentSet, compare;
7633
7634            switch (mode) {
7635
7636              case '@':
7637                attrs.$observe(attrName, function(value) {
7638                  isolateBindingContext[scopeName] = value;
7639                });
7640                attrs.$$observers[attrName].$$scope = scope;
7641                if (attrs[attrName]) {
7642                  // If the attribute has been provided then we trigger an interpolation to ensure
7643                  // the value is there for use in the link fn
7644                  isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
7645                }
7646                break;
7647
7648              case '=':
7649                if (optional && !attrs[attrName]) {
7650                  return;
7651                }
7652                parentGet = $parse(attrs[attrName]);
7653                if (parentGet.literal) {
7654                  compare = equals;
7655                } else {
7656                  compare = function(a, b) { return a === b || (a !== a && b !== b); };
7657                }
7658                parentSet = parentGet.assign || function() {
7659                  // reset the change, or we will throw this exception on every $digest
7660                  lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7661                  throw $compileMinErr('nonassign',
7662                      "Expression '{0}' used with directive '{1}' is non-assignable!",
7663                      attrs[attrName], newIsolateScopeDirective.name);
7664                };
7665                lastValue = isolateBindingContext[scopeName] = parentGet(scope);
7666                var parentValueWatch = function parentValueWatch(parentValue) {
7667                  if (!compare(parentValue, isolateBindingContext[scopeName])) {
7668                    // we are out of sync and need to copy
7669                    if (!compare(parentValue, lastValue)) {
7670                      // parent changed and it has precedence
7671                      isolateBindingContext[scopeName] = parentValue;
7672                    } else {
7673                      // if the parent can be assigned then do so
7674                      parentSet(scope, parentValue = isolateBindingContext[scopeName]);
7675                    }
7676                  }
7677                  return lastValue = parentValue;
7678                };
7679                parentValueWatch.$stateful = true;
7680                var unwatch;
7681                if (definition.collection) {
7682                  unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
7683                } else {
7684                  unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
7685                }
7686                isolateScope.$on('$destroy', unwatch);
7687                break;
7688
7689              case '&':
7690                parentGet = $parse(attrs[attrName]);
7691                isolateBindingContext[scopeName] = function(locals) {
7692                  return parentGet(scope, locals);
7693                };
7694                break;
7695            }
7696          });
7697        }
7698        if (controllers) {
7699          forEach(controllers, function(controller) {
7700            controller();
7701          });
7702          controllers = null;
7703        }
7704
7705        // PRELINKING
7706        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
7707          linkFn = preLinkFns[i];
7708          invokeLinkFn(linkFn,
7709              linkFn.isolateScope ? isolateScope : scope,
7710              $element,
7711              attrs,
7712              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7713              transcludeFn
7714          );
7715        }
7716
7717        // RECURSION
7718        // We only pass the isolate scope, if the isolate directive has a template,
7719        // otherwise the child elements do not belong to the isolate directive.
7720        var scopeToChild = scope;
7721        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
7722          scopeToChild = isolateScope;
7723        }
7724        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
7725
7726        // POSTLINKING
7727        for (i = postLinkFns.length - 1; i >= 0; i--) {
7728          linkFn = postLinkFns[i];
7729          invokeLinkFn(linkFn,
7730              linkFn.isolateScope ? isolateScope : scope,
7731              $element,
7732              attrs,
7733              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
7734              transcludeFn
7735          );
7736        }
7737
7738        // This is the function that is injected as `$transclude`.
7739        // Note: all arguments are optional!
7740        function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
7741          var transcludeControllers;
7742
7743          // No scope passed in:
7744          if (!isScope(scope)) {
7745            futureParentElement = cloneAttachFn;
7746            cloneAttachFn = scope;
7747            scope = undefined;
7748          }
7749
7750          if (hasElementTranscludeDirective) {
7751            transcludeControllers = elementControllers;
7752          }
7753          if (!futureParentElement) {
7754            futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
7755          }
7756          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
7757        }
7758      }
7759    }
7760
7761    function markDirectivesAsIsolate(directives) {
7762      // mark all directives as needing isolate scope.
7763      for (var j = 0, jj = directives.length; j < jj; j++) {
7764        directives[j] = inherit(directives[j], {$$isolateScope: true});
7765      }
7766    }
7767
7768    /**
7769     * looks up the directive and decorates it with exception handling and proper parameters. We
7770     * call this the boundDirective.
7771     *
7772     * @param {string} name name of the directive to look up.
7773     * @param {string} location The directive must be found in specific format.
7774     *   String containing any of theses characters:
7775     *
7776     *   * `E`: element name
7777     *   * `A': attribute
7778     *   * `C`: class
7779     *   * `M`: comment
7780     * @returns {boolean} true if directive was added.
7781     */
7782    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
7783                          endAttrName) {
7784      if (name === ignoreDirective) return null;
7785      var match = null;
7786      if (hasDirectives.hasOwnProperty(name)) {
7787        for (var directive, directives = $injector.get(name + Suffix),
7788            i = 0, ii = directives.length; i < ii; i++) {
7789          try {
7790            directive = directives[i];
7791            if ((maxPriority === undefined || maxPriority > directive.priority) &&
7792                 directive.restrict.indexOf(location) != -1) {
7793              if (startAttrName) {
7794                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
7795              }
7796              tDirectives.push(directive);
7797              match = directive;
7798            }
7799          } catch (e) { $exceptionHandler(e); }
7800        }
7801      }
7802      return match;
7803    }
7804
7805
7806    /**
7807     * looks up the directive and returns true if it is a multi-element directive,
7808     * and therefore requires DOM nodes between -start and -end markers to be grouped
7809     * together.
7810     *
7811     * @param {string} name name of the directive to look up.
7812     * @returns true if directive was registered as multi-element.
7813     */
7814    function directiveIsMultiElement(name) {
7815      if (hasDirectives.hasOwnProperty(name)) {
7816        for (var directive, directives = $injector.get(name + Suffix),
7817            i = 0, ii = directives.length; i < ii; i++) {
7818          directive = directives[i];
7819          if (directive.multiElement) {
7820            return true;
7821          }
7822        }
7823      }
7824      return false;
7825    }
7826
7827    /**
7828     * When the element is replaced with HTML template then the new attributes
7829     * on the template need to be merged with the existing attributes in the DOM.
7830     * The desired effect is to have both of the attributes present.
7831     *
7832     * @param {object} dst destination attributes (original DOM)
7833     * @param {object} src source attributes (from the directive template)
7834     */
7835    function mergeTemplateAttributes(dst, src) {
7836      var srcAttr = src.$attr,
7837          dstAttr = dst.$attr,
7838          $element = dst.$$element;
7839
7840      // reapply the old attributes to the new element
7841      forEach(dst, function(value, key) {
7842        if (key.charAt(0) != '$') {
7843          if (src[key] && src[key] !== value) {
7844            value += (key === 'style' ? ';' : ' ') + src[key];
7845          }
7846          dst.$set(key, value, true, srcAttr[key]);
7847        }
7848      });
7849
7850      // copy the new attributes on the old attrs object
7851      forEach(src, function(value, key) {
7852        if (key == 'class') {
7853          safeAddClass($element, value);
7854          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
7855        } else if (key == 'style') {
7856          $element.attr('style', $element.attr('style') + ';' + value);
7857          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
7858          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
7859          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
7860          // have an attribute like "has-own-property" or "data-has-own-property", etc.
7861        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
7862          dst[key] = value;
7863          dstAttr[key] = srcAttr[key];
7864        }
7865      });
7866    }
7867
7868
7869    function compileTemplateUrl(directives, $compileNode, tAttrs,
7870        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
7871      var linkQueue = [],
7872          afterTemplateNodeLinkFn,
7873          afterTemplateChildLinkFn,
7874          beforeTemplateCompileNode = $compileNode[0],
7875          origAsyncDirective = directives.shift(),
7876          derivedSyncDirective = inherit(origAsyncDirective, {
7877            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
7878          }),
7879          templateUrl = (isFunction(origAsyncDirective.templateUrl))
7880              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
7881              : origAsyncDirective.templateUrl,
7882          templateNamespace = origAsyncDirective.templateNamespace;
7883
7884      $compileNode.empty();
7885
7886      $templateRequest($sce.getTrustedResourceUrl(templateUrl))
7887        .then(function(content) {
7888          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
7889
7890          content = denormalizeTemplate(content);
7891
7892          if (origAsyncDirective.replace) {
7893            if (jqLiteIsTextNode(content)) {
7894              $template = [];
7895            } else {
7896              $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
7897            }
7898            compileNode = $template[0];
7899
7900            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7901              throw $compileMinErr('tplrt',
7902                  "Template for directive '{0}' must have exactly one root element. {1}",
7903                  origAsyncDirective.name, templateUrl);
7904            }
7905
7906            tempTemplateAttrs = {$attr: {}};
7907            replaceWith($rootElement, $compileNode, compileNode);
7908            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
7909
7910            if (isObject(origAsyncDirective.scope)) {
7911              markDirectivesAsIsolate(templateDirectives);
7912            }
7913            directives = templateDirectives.concat(directives);
7914            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
7915          } else {
7916            compileNode = beforeTemplateCompileNode;
7917            $compileNode.html(content);
7918          }
7919
7920          directives.unshift(derivedSyncDirective);
7921
7922          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
7923              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
7924              previousCompileContext);
vendor: 17,305 bytes, lines 7925-8396
7925          forEach($rootElement, function(node, i) {
7926            if (node == compileNode) {
7927              $rootElement[i] = $compileNode[0];
7928            }
7929          });
7930          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
7931
7932          while (linkQueue.length) {
7933            var scope = linkQueue.shift(),
7934                beforeTemplateLinkNode = linkQueue.shift(),
7935                linkRootElement = linkQueue.shift(),
7936                boundTranscludeFn = linkQueue.shift(),
7937                linkNode = $compileNode[0];
7938
7939            if (scope.$$destroyed) continue;
7940
7941            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
7942              var oldClasses = beforeTemplateLinkNode.className;
7943
7944              if (!(previousCompileContext.hasElementTranscludeDirective &&
7945                  origAsyncDirective.replace)) {
7946                // it was cloned therefore we have to clone as well.
7947                linkNode = jqLiteClone(compileNode);
7948              }
7949              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
7950
7951              // Copy in CSS classes from original node
7952              safeAddClass(jqLite(linkNode), oldClasses);
7953            }
7954            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
7955              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
7956            } else {
7957              childBoundTranscludeFn = boundTranscludeFn;
7958            }
7959            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
7960              childBoundTranscludeFn);
7961          }
7962          linkQueue = null;
7963        });
7964
7965      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
7966        var childBoundTranscludeFn = boundTranscludeFn;
7967        if (scope.$$destroyed) return;
7968        if (linkQueue) {
7969          linkQueue.push(scope,
7970                         node,
7971                         rootElement,
7972                         childBoundTranscludeFn);
7973        } else {
7974          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
7975            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
7976          }
7977          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
7978        }
7979      };
7980    }
7981
7982
7983    /**
7984     * Sorting function for bound directives.
7985     */
7986    function byPriority(a, b) {
7987      var diff = b.priority - a.priority;
7988      if (diff !== 0) return diff;
7989      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
7990      return a.index - b.index;
7991    }
7992
7993
7994    function assertNoDuplicate(what, previousDirective, directive, element) {
7995      if (previousDirective) {
7996        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
7997            previousDirective.name, directive.name, what, startingTag(element));
7998      }
7999    }
8000
8001
8002    function addTextInterpolateDirective(directives, text) {
8003      var interpolateFn = $interpolate(text, true);
8004      if (interpolateFn) {
8005        directives.push({
8006          priority: 0,
8007          compile: function textInterpolateCompileFn(templateNode) {
8008            var templateNodeParent = templateNode.parent(),
8009                hasCompileParent = !!templateNodeParent.length;
8010
8011            // When transcluding a template that has bindings in the root
8012            // we don't have a parent and thus need to add the class during linking fn.
8013            if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8014
8015            return function textInterpolateLinkFn(scope, node) {
8016              var parent = node.parent();
8017              if (!hasCompileParent) compile.$$addBindingClass(parent);
8018              compile.$$addBindingInfo(parent, interpolateFn.expressions);
8019              scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8020                node[0].nodeValue = value;
8021              });
8022            };
8023          }
8024        });
8025      }
8026    }
8027
8028
8029    function wrapTemplate(type, template) {
8030      type = lowercase(type || 'html');
8031      switch (type) {
8032      case 'svg':
8033      case 'math':
8034        var wrapper = document.createElement('div');
8035        wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8036        return wrapper.childNodes[0].childNodes;
8037      default:
8038        return template;
8039      }
8040    }
8041
8042
8043    function getTrustedContext(node, attrNormalizedName) {
8044      if (attrNormalizedName == "srcdoc") {
8045        return $sce.HTML;
8046      }
8047      var tag = nodeName_(node);
8048      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8049      if (attrNormalizedName == "xlinkHref" ||
8050          (tag == "form" && attrNormalizedName == "action") ||
8051          (tag != "img" && (attrNormalizedName == "src" ||
8052                            attrNormalizedName == "ngSrc"))) {
8053        return $sce.RESOURCE_URL;
8054      }
8055    }
8056
8057
8058    function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8059      var trustedContext = getTrustedContext(node, name);
8060      allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8061
8062      var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8063
8064      // no interpolation found -> ignore
8065      if (!interpolateFn) return;
8066
8067
8068      if (name === "multiple" && nodeName_(node) === "select") {
8069        throw $compileMinErr("selmulti",
8070            "Binding to the 'multiple' attribute is not supported. Element: {0}",
8071            startingTag(node));
8072      }
8073
8074      directives.push({
8075        priority: 100,
8076        compile: function() {
8077            return {
8078              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8079                var $$observers = (attr.$$observers || (attr.$$observers = {}));
8080
8081                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8082                  throw $compileMinErr('nodomevents',
8083                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8084                          "ng- versions (such as ng-click instead of onclick) instead.");
8085                }
8086
8087                // If the attribute has changed since last $interpolate()ed
8088                var newValue = attr[name];
8089                if (newValue !== value) {
8090                  // we need to interpolate again since the attribute value has been updated
8091                  // (e.g. by another directive's compile function)
8092                  // ensure unset/empty values make interpolateFn falsy
8093                  interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8094                  value = newValue;
8095                }
8096
8097                // if attribute was updated so that there is no interpolation going on we don't want to
8098                // register any observers
8099                if (!interpolateFn) return;
8100
8101                // initialize attr object so that it's ready in case we need the value for isolate
8102                // scope initialization, otherwise the value would not be available from isolate
8103                // directive's linking fn during linking phase
8104                attr[name] = interpolateFn(scope);
8105
8106                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8107                (attr.$$observers && attr.$$observers[name].$$scope || scope).
8108                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8109                    //special case for class attribute addition + removal
8110                    //so that class changes can tap into the animation
8111                    //hooks provided by the $animate service. Be sure to
8112                    //skip animations when the first digest occurs (when
8113                    //both the new and the old values are the same) since
8114                    //the CSS classes are the non-interpolated values
8115                    if (name === 'class' && newValue != oldValue) {
8116                      attr.$updateClass(newValue, oldValue);
8117                    } else {
8118                      attr.$set(name, newValue);
8119                    }
8120                  });
8121              }
8122            };
8123          }
8124      });
8125    }
8126
8127
8128    /**
8129     * This is a special jqLite.replaceWith, which can replace items which
8130     * have no parents, provided that the containing jqLite collection is provided.
8131     *
8132     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8133     *                               in the root of the tree.
8134     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8135     *                                  the shell, but replace its DOM node reference.
8136     * @param {Node} newNode The new DOM node.
8137     */
8138    function replaceWith($rootElement, elementsToRemove, newNode) {
8139      var firstElementToRemove = elementsToRemove[0],
8140          removeCount = elementsToRemove.length,
8141          parent = firstElementToRemove.parentNode,
8142          i, ii;
8143
8144      if ($rootElement) {
8145        for (i = 0, ii = $rootElement.length; i < ii; i++) {
8146          if ($rootElement[i] == firstElementToRemove) {
8147            $rootElement[i++] = newNode;
8148            for (var j = i, j2 = j + removeCount - 1,
8149                     jj = $rootElement.length;
8150                 j < jj; j++, j2++) {
8151              if (j2 < jj) {
8152                $rootElement[j] = $rootElement[j2];
8153              } else {
8154                delete $rootElement[j];
8155              }
8156            }
8157            $rootElement.length -= removeCount - 1;
8158
8159            // If the replaced element is also the jQuery .context then replace it
8160            // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8161            // http://api.jquery.com/context/
8162            if ($rootElement.context === firstElementToRemove) {
8163              $rootElement.context = newNode;
8164            }
8165            break;
8166          }
8167        }
8168      }
8169
8170      if (parent) {
8171        parent.replaceChild(newNode, firstElementToRemove);
8172      }
8173
8174      // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8175      var fragment = document.createDocumentFragment();
8176      fragment.appendChild(firstElementToRemove);
8177
8178      // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8179      // data here because there's no public interface in jQuery to do that and copying over
8180      // event listeners (which is the main use of private data) wouldn't work anyway.
8181      jqLite(newNode).data(jqLite(firstElementToRemove).data());
8182
8183      // Remove data of the replaced element. We cannot just call .remove()
8184      // on the element it since that would deallocate scope that is needed
8185      // for the new node. Instead, remove the data "manually".
8186      if (!jQuery) {
8187        delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8188      } else {
8189        // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8190        // the replaced element. The cleanData version monkey-patched by Angular would cause
8191        // the scope to be trashed and we do need the very same scope to work with the new
8192        // element. However, we cannot just cache the non-patched version and use it here as
8193        // that would break if another library patches the method after Angular does (one
8194        // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8195        // skipped this one time.
8196        skipDestroyOnNextJQueryCleanData = true;
8197        jQuery.cleanData([firstElementToRemove]);
8198      }
8199
8200      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8201        var element = elementsToRemove[k];
8202        jqLite(element).remove(); // must do this way to clean up expando
8203        fragment.appendChild(element);
8204        delete elementsToRemove[k];
8205      }
8206
8207      elementsToRemove[0] = newNode;
8208      elementsToRemove.length = 1;
8209    }
8210
8211
8212    function cloneAndAnnotateFn(fn, annotation) {
8213      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8214    }
8215
8216
8217    function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8218      try {
8219        linkFn(scope, $element, attrs, controllers, transcludeFn);
8220      } catch (e) {
8221        $exceptionHandler(e, startingTag($element));
8222      }
8223    }
8224  }];
8225}
8226
8227var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8228/**
8229 * Converts all accepted directives format into proper directive name.
8230 * @param name Name to normalize
8231 */
8232function directiveNormalize(name) {
8233  return camelCase(name.replace(PREFIX_REGEXP, ''));
8234}
8235
8236/**
8237 * @ngdoc type
8238 * @name $compile.directive.Attributes
8239 *
8240 * @description
8241 * A shared object between directive compile / linking functions which contains normalized DOM
8242 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
8243 * needed since all of these are treated as equivalent in Angular:
8244 *
8245 * ```
8246 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
8247 * ```
8248 */
8249
8250/**
8251 * @ngdoc property
8252 * @name $compile.directive.Attributes#$attr
8253 *
8254 * @description
8255 * A map of DOM element attribute names to the normalized name. This is
8256 * needed to do reverse lookup from normalized name back to actual name.
8257 */
8258
8259
8260/**
8261 * @ngdoc method
8262 * @name $compile.directive.Attributes#$set
8263 * @kind function
8264 *
8265 * @description
8266 * Set DOM element attribute value.
8267 *
8268 *
8269 * @param {string} name Normalized element attribute name of the property to modify. The name is
8270 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
8271 *          property to the original name.
8272 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
8273 */
8274
8275
8276
8277/**
8278 * Closure compiler type information
8279 */
8280
8281function nodesetLinkingFn(
8282  /* angular.Scope */ scope,
8283  /* NodeList */ nodeList,
8284  /* Element */ rootElement,
8285  /* function(Function) */ boundTranscludeFn
8286) {}
8287
8288function directiveLinkingFn(
8289  /* nodesetLinkingFn */ nodesetLinkingFn,
8290  /* angular.Scope */ scope,
8291  /* Node */ node,
8292  /* Element */ rootElement,
8293  /* function(Function) */ boundTranscludeFn
8294) {}
8295
8296function tokenDifference(str1, str2) {
8297  var values = '',
8298      tokens1 = str1.split(/\s+/),
8299      tokens2 = str2.split(/\s+/);
8300
8301  outer:
8302  for (var i = 0; i < tokens1.length; i++) {
8303    var token = tokens1[i];
8304    for (var j = 0; j < tokens2.length; j++) {
8305      if (token == tokens2[j]) continue outer;
8306    }
8307    values += (values.length > 0 ? ' ' : '') + token;
8308  }
8309  return values;
8310}
8311
8312function removeComments(jqNodes) {
8313  jqNodes = jqLite(jqNodes);
8314  var i = jqNodes.length;
8315
8316  if (i <= 1) {
8317    return jqNodes;
8318  }
8319
8320  while (i--) {
8321    var node = jqNodes[i];
8322    if (node.nodeType === NODE_TYPE_COMMENT) {
8323      splice.call(jqNodes, i, 1);
8324    }
8325  }
8326  return jqNodes;
8327}
8328
8329var $controllerMinErr = minErr('$controller');
8330
8331/**
8332 * @ngdoc provider
8333 * @name $controllerProvider
8334 * @description
8335 * The {@link ng.$controller $controller service} is used by Angular to create new
8336 * controllers.
8337 *
8338 * This provider allows controller registration via the
8339 * {@link ng.$controllerProvider#register register} method.
8340 */
8341function $ControllerProvider() {
8342  var controllers = {},
8343      globals = false,
8344      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
8345
8346
8347  /**
8348   * @ngdoc method
8349   * @name $controllerProvider#register
8350   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
8351   *    the names and the values are the constructors.
8352   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
8353   *    annotations in the array notation).
8354   */
8355  this.register = function(name, constructor) {
8356    assertNotHasOwnProperty(name, 'controller');
8357    if (isObject(name)) {
8358      extend(controllers, name);
8359    } else {
8360      controllers[name] = constructor;
8361    }
8362  };
8363
8364  /**
8365   * @ngdoc method
8366   * @name $controllerProvider#allowGlobals
8367   * @description If called, allows `$controller` to find controller constructors on `window`
8368   */
8369  this.allowGlobals = function() {
8370    globals = true;
8371  };
8372
8373
8374  this.$get = ['$injector', '$window', function($injector, $window) {
8375
8376    /**
8377     * @ngdoc service
8378     * @name $controller
8379     * @requires $injector
8380     *
8381     * @param {Function|string} constructor If called with a function then it's considered to be the
8382     *    controller constructor function. Otherwise it's considered to be a string which is used
8383     *    to retrieve the controller constructor using the following steps:
8384     *
8385     *    * check if a controller with given name is registered via `$controllerProvider`
8386     *    * check if evaluating the string on the current scope returns a constructor
8387     *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
8388     *      `window` object (not recommended)
8389     *
8390     *    The string can use the `controller as property` syntax, where the controller instance is published
8391     *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
8392     *    to work correctly.
8393     *
8394     * @param {Object} locals Injection locals for Controller.
8395     * @return {Object} Instance of given controller.
8396     *
8397     * @description
8398     * `$controller` service is responsible for instantiating controllers.
8399     *
8400     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
8401     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
8402     */
8403    return function(expression, locals, later, ident) {
8404      // PRIVATE API:
8405      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
8406      //                     If true, $controller will allocate the object with the correct
8407      //                     prototype chain, but will not invoke the controller until a returned
8408      //                     callback is invoked.
8409      //   param `ident` --- An optional label which overrides the label parsed from the controller
8410      //                     expression, if any.
8411      var instance, match, constructor, identifier;
8412      later = later === true;
8413      if (ident && isString(ident)) {
8414        identifier = ident;
8415      }
8416
8417      if (isString(expression)) {
8418        match = expression.match(CNTRL_REG);
8419        if (!match) {
8420          throw $controllerMinErr('ctrlfmt',
8421            "Badly formed controller string '{0}'. " +
8422            "Must match `__name__ as __id__` or `__name__`.", expression);
8423        }
8424        constructor = match[1],
8425        identifier = identifier || match[3];
8426        expression = controllers.hasOwnProperty(constructor)
8427            ? controllers[constructor]
8428            : getter(locals.$scope, constructor, true) ||
8429                (globals ? getter($window, constructor, true) : undefined);
8430
8431        assertArgFn(expression, constructor, true);
8432      }
8433
8434      if (later) {
8435        // Instantiate controller later:
8436        // This machinery is used to create an instance of the object before calling the
8437        // controller's constructor itself.
8438        //
8439        // This allows properties to be added to the controller before the constructor is
8440        // invoked. Primarily, this is used for isolate scope bindings in $compile.
8441        //
8442        // This feature is not intended for use by applications, and is thus not documented
8443        // publicly.
8444        // Object creation: http://jsperf.com/create-constructor/2
8445        var controllerPrototype = (isArray(expression) ?
8446          expression[expression.length - 1] : expression).prototype;
8447        instance = Object.create(controllerPrototype || null);
8448
8449        if (identifier) {
8450          addIdentifier(locals, identifier, instance, constructor || expression.name);
8451        }
8452
8453        return extend(function() {
8454          $injector.invoke(expression, instance, locals, constructor);
8455          return instance;
8456        }, {
8457          instance: instance,
8458          identifier: identifier
8459        });
8460      }
8461
8462      instance = $injector.instantiate(expression, locals, constructor);
8463
8464      if (identifier) {
8465        addIdentifier(locals, identifier, instance, constructor || expression.name);
8466      }
8467
8468      return instance;
8469    };
8470
8471    function addIdentifier(locals, identifier, instance, name) {
8472      if (!(locals && isObject(locals.$scope))) {
8473        throw minErr('$controller')('noscp',
8474          "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
8475          name, identifier);
8476      }
8477
8478      locals.$scope[identifier] = instance;
8479    }
8480  }];
8481}
8482
8483/**
8484 * @ngdoc service
8485 * @name $document
8486 * @requires $window
8487 *
8488 * @description
8489 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
8490 *
8491 * @example
8492   <example module="documentExample">
8493     <file name="index.html">
8494       <div ng-controller="ExampleController">
8495         <p>$document title: <b ng-bind="title"></b></p>
8496         <p>window.document title: <b ng-bind="windowTitle"></b></p>
8497       </div>
8498     </file>
8499     <file name="script.js">
8500       angular.module('documentExample', [])
8501         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
8502           $scope.title = $document[0].title;
8503           $scope.windowTitle = angular.element(window.document)[0].title;
8504         }]);
8505     </file>
8506   </example>
8507 */
8508function $DocumentProvider() {
8509  this.$get = ['$window', function(window) {
8510    return jqLite(window.document);
8511  }];
8512}
8513
8514/**
8515 * @ngdoc service
8516 * @name $exceptionHandler
8517 * @requires ng.$log
8518 *
8519 * @description
8520 * Any uncaught exception in angular expressions is delegated to this service.
8521 * The default implementation simply delegates to `$log.error` which logs it into
8522 * the browser console.
8523 *
8524 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
8525 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
8526 *
8527 * ## Example:
8528 *
8529 * ```js
8530 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
8531 *     return function(exception, cause) {
8532 *       exception.message += ' (caused by "' + cause + '")';
8533 *       throw exception;
8534 *     };
8535 *   });
8536 * ```
8537 *
8538 * This example will override the normal action of `$exceptionHandler`, to make angular
8539 * exceptions fail hard when they happen, instead of just logging to the console.
8540 *
8541 * <hr />
8542 * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
8543 * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
8544 * (unless executed during a digest).
8545 *
8546 * If you wish, you can manually delegate exceptions, e.g.
8547 * `try { ... } catch(e) { $exceptionHandler(e); }`
8548 *
8549 * @param {Error} exception Exception associated with the error.
8550 * @param {string=} cause optional information about the context in which
8551 *       the error was thrown.
8552 *
8553 */
8554function $ExceptionHandlerProvider() {
8555  this.$get = ['$log', function($log) {
8556    return function(exception, cause) {
8557      $log.error.apply($log, arguments);
8558    };
8559  }];
8560}
8561
8562var APPLICATION_JSON = 'application/json';
8563var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
8564var JSON_START = /^\[|^\{(?!\{)/;
8565var JSON_ENDS = {
8566  '[': /]$/,
8567  '{': /}$/
8568};
8569var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
8570
8571function defaultHttpResponseTransform(data, headers) {
8572  if (isString(data)) {
8573    // Strip json vulnerability protection prefix and trim whitespace
8574    var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
8575
8576    if (tempData) {
8577      var contentType = headers('Content-Type');
8578      if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
8579        data = fromJson(tempData);
8580      }
8581    }
8582  }
8583
8584  return data;
8585}
8586
8587function isJsonLike(str) {
8588    var jsonStart = str.match(JSON_START);
8589    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
8590}
8591
8592/**
8593 * Parse headers into key value object
8594 *
8595 * @param {string} headers Raw headers as a string
8596 * @returns {Object} Parsed headers as key value object
8597 */
8598function parseHeaders(headers) {
8599  var parsed = createMap(), key, val, i;
8600
8601  if (!headers) return parsed;
8602
8603  forEach(headers.split('\n'), function(line) {
8604    i = line.indexOf(':');
vendor: 5,893 bytes, lines 8605-8787
8605    key = lowercase(trim(line.substr(0, i)));
8606    val = trim(line.substr(i + 1));
8607
8608    if (key) {
8609      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
8610    }
8611  });
8612
8613  return parsed;
8614}
8615
8616
8617/**
8618 * Returns a function that provides access to parsed headers.
8619 *
8620 * Headers are lazy parsed when first requested.
8621 * @see parseHeaders
8622 *
8623 * @param {(string|Object)} headers Headers to provide access to.
8624 * @returns {function(string=)} Returns a getter function which if called with:
8625 *
8626 *   - if called with single an argument returns a single header value or null
8627 *   - if called with no arguments returns an object containing all headers.
8628 */
8629function headersGetter(headers) {
8630  var headersObj = isObject(headers) ? headers : undefined;
8631
8632  return function(name) {
8633    if (!headersObj) headersObj =  parseHeaders(headers);
8634
8635    if (name) {
8636      var value = headersObj[lowercase(name)];
8637      if (value === void 0) {
8638        value = null;
8639      }
8640      return value;
8641    }
8642
8643    return headersObj;
8644  };
8645}
8646
8647
8648/**
8649 * Chain all given functions
8650 *
8651 * This function is used for both request and response transforming
8652 *
8653 * @param {*} data Data to transform.
8654 * @param {function(string=)} headers HTTP headers getter fn.
8655 * @param {number} status HTTP status code of the response.
8656 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
8657 * @returns {*} Transformed data.
8658 */
8659function transformData(data, headers, status, fns) {
8660  if (isFunction(fns))
8661    return fns(data, headers, status);
8662
8663  forEach(fns, function(fn) {
8664    data = fn(data, headers, status);
8665  });
8666
8667  return data;
8668}
8669
8670
8671function isSuccess(status) {
8672  return 200 <= status && status < 300;
8673}
8674
8675
8676/**
8677 * @ngdoc provider
8678 * @name $httpProvider
8679 * @description
8680 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
8681 * */
8682function $HttpProvider() {
8683  /**
8684   * @ngdoc property
8685   * @name $httpProvider#defaults
8686   * @description
8687   *
8688   * Object containing default values for all {@link ng.$http $http} requests.
8689   *
8690   * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
8691   * that will provide the cache for all requests who set their `cache` property to `true`.
8692   * If you set the `default.cache = false` then only requests that specify their own custom
8693   * cache object will be cached. See {@link $http#caching $http Caching} for more information.
8694   *
8695   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
8696   * Defaults value is `'XSRF-TOKEN'`.
8697   *
8698   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
8699   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
8700   *
8701   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
8702   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
8703   * setting default headers.
8704   *     - **`defaults.headers.common`**
8705   *     - **`defaults.headers.post`**
8706   *     - **`defaults.headers.put`**
8707   *     - **`defaults.headers.patch`**
8708   *
8709   **/
8710  var defaults = this.defaults = {
8711    // transform incoming response data
8712    transformResponse: [defaultHttpResponseTransform],
8713
8714    // transform outgoing request data
8715    transformRequest: [function(d) {
8716      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
8717    }],
8718
8719    // default headers
8720    headers: {
8721      common: {
8722        'Accept': 'application/json, text/plain, */*'
8723      },
8724      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8725      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
8726      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
8727    },
8728
8729    xsrfCookieName: 'XSRF-TOKEN',
8730    xsrfHeaderName: 'X-XSRF-TOKEN'
8731  };
8732
8733  var useApplyAsync = false;
8734  /**
8735   * @ngdoc method
8736   * @name $httpProvider#useApplyAsync
8737   * @description
8738   *
8739   * Configure $http service to combine processing of multiple http responses received at around
8740   * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
8741   * significant performance improvement for bigger applications that make many HTTP requests
8742   * concurrently (common during application bootstrap).
8743   *
8744   * Defaults to false. If no value is specifed, returns the current configured value.
8745   *
8746   * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
8747   *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
8748   *    to load and share the same digest cycle.
8749   *
8750   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
8751   *    otherwise, returns the current configured value.
8752   **/
8753  this.useApplyAsync = function(value) {
8754    if (isDefined(value)) {
8755      useApplyAsync = !!value;
8756      return this;
8757    }
8758    return useApplyAsync;
8759  };
8760
8761  /**
8762   * @ngdoc property
8763   * @name $httpProvider#interceptors
8764   * @description
8765   *
8766   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
8767   * pre-processing of request or postprocessing of responses.
8768   *
8769   * These service factories are ordered by request, i.e. they are applied in the same order as the
8770   * array, on request, but reverse order, on response.
8771   *
8772   * {@link ng.$http#interceptors Interceptors detailed info}
8773   **/
8774  var interceptorFactories = this.interceptors = [];
8775
8776  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
8777      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
8778
8779    var defaultCache = $cacheFactory('$http');
8780
8781    /**
8782     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
8783     * The reversal is needed so that we can build up the interception chain around the
8784     * server request.
8785     */
8786    var reversedInterceptors = [];
8787
8788    forEach(interceptorFactories, function(interceptorFactory) {
8789      reversedInterceptors.unshift(isString(interceptorFactory)
8790          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
8791    });
8792
8793    /**
8794     * @ngdoc service
8795     * @kind function
8796     * @name $http
8797     * @requires ng.$httpBackend
8798     * @requires $cacheFactory
8799     * @requires $rootScope
8800     * @requires $q
8801     * @requires $injector
8802     *
8803     * @description
8804     * The `$http` service is a core Angular service that facilitates communication with the remote
8805     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
8806     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
8807     *
8808     * For unit testing applications that use `$http` service, see
8809     * {@link ngMock.$httpBackend $httpBackend mock}.
8810     *
8811     * For a higher level of abstraction, please check out the {@link ngResource.$resource
8812     * $resource} service.
8813     *
8814     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
8815     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
8816     * it is important to familiarize yourself with these APIs and the guarantees they provide.
8817     *
8818     *
8819     * ## General usage
8820     * The `$http` service is a function which takes a single argument — a configuration object —
8821     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
8822     * with two $http specific methods: `success` and `error`.
8823     *
8824     * ```js
8825     *   // Simple GET request example :
8826     *   $http.get('/someUrl').
8827     *     success(function(data, status, headers, config) {
8828     *       // this callback will be called asynchronously
8829     *       // when the response is available
8830     *     }).
8831     *     error(function(data, status, headers, config) {
8832     *       // called asynchronously if an error occurs
8833     *       // or server returns response with an error status.
8834     *     });
8835     * ```
8836     *
8837     * ```js
8838     *   // Simple POST request example (passing data) :
8839     *   $http.post('/someUrl', {msg:'hello word!'}).
8840     *     success(function(data, status, headers, config) {
8841     *       // this callback will be called asynchronously
8842     *       // when the response is available
8843     *     }).
8844     *     error(function(data, status, headers, config) {
8845     *       // called asynchronously if an error occurs
8846     *       // or server returns response with an error status.
8847     *     });
8848     * ```
8849     *
8850     *
8851     * Since the returned value of calling the $http function is a `promise`, you can also use
8852     * the `then` method to register callbacks, and these callbacks will receive a single argument –
8853     * an object representing the response. See the API signature and type info below for more
8854     * details.
8855     *
8856     * A response status code between 200 and 299 is considered a success status and
8857     * will result in the success callback being called. Note that if the response is a redirect,
8858     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
8859     * called for such responses.
8860     *
8861     * ## Writing Unit Tests that use $http
8862     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
8863     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
8864     * request using trained responses.
8865     *
8866     * ```
8867     * $httpBackend.expectGET(...);
8868     * $http.get(...);
8869     * $httpBackend.flush();
8870     * ```
8871     *
8872     * ## Shortcut methods
8873     *
8874     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
8875     * request data must be passed in for POST/PUT requests.
8876     *
8877     * ```js
8878     *   $http.get('/someUrl').success(successCallback);
8879     *   $http.post('/someUrl', data).success(successCallback);
8880     * ```
8881     *
8882     * Complete list of shortcut methods:
8883     *
8884     * - {@link ng.$http#get $http.get}
8885     * - {@link ng.$http#head $http.head}
8886     * - {@link ng.$http#post $http.post}
8887     * - {@link ng.$http#put $http.put}
8888     * - {@link ng.$http#delete $http.delete}
8889     * - {@link ng.$http#jsonp $http.jsonp}
8890     * - {@link ng.$http#patch $http.patch}
8891     *
8892     *
8893     * ## Setting HTTP Headers
8894     *
8895     * The $http service will automatically add certain HTTP headers to all requests. These defaults
8896     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
8897     * object, which currently contains this default configuration:
8898     *
8899     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
8900     *   - `Accept: application/json, text/plain, * / *`
8901     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
8902     *   - `Content-Type: application/json`
8903     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
8904     *   - `Content-Type: application/json`
8905     *
8906     * To add or overwrite these defaults, simply add or remove a property from these configuration
8907     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
8908     * with the lowercased HTTP method name as the key, e.g.
8909     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
8910     *
8911     * The defaults can also be set at runtime via the `$http.defaults` object in the same
8912     * fashion. For example:
8913     *
8914     * ```
8915     * module.run(function($http) {
8916     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
8917     * });
8918     * ```
8919     *
8920     * In addition, you can supply a `headers` property in the config object passed when
8921     * calling `$http(config)`, which overrides the defaults without changing them globally.
8922     *
8923     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
8924     * Use the `headers` property, setting the desired header to `undefined`. For example:
8925     *
8926     * ```js
8927     * var req = {
8928     *  method: 'POST',
8929     *  url: 'http://example.com',
8930     *  headers: {
8931     *    'Content-Type': undefined
8932     *  },
8933     *  data: { test: 'test' },
8934     * }
8935     *
8936     * $http(req).success(function(){...}).error(function(){...});
8937     * ```
8938     *
8939     * ## Transforming Requests and Responses
8940     *
8941     * Both requests and responses can be transformed using transformation functions: `transformRequest`
8942     * and `transformResponse`. These properties can be a single function that returns
8943     * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
8944     * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
8945     *
8946     * ### Default Transformations
8947     *
8948     * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
8949     * `defaults.transformResponse` properties. If a request does not provide its own transformations
8950     * then these will be applied.
8951     *
8952     * You can augment or replace the default transformations by modifying these properties by adding to or
8953     * replacing the array.
8954     *
8955     * Angular provides the following default transformations:
8956     *
8957     * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
8958     *
8959     * - If the `data` property of the request configuration object contains an object, serialize it
8960     *   into JSON format.
8961     *
8962     * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
8963     *
8964     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
8965     *  - If JSON response is detected, deserialize it using a JSON parser.
8966     *
8967     *
8968     * ### Overriding the Default Transformations Per Request
8969     *
8970     * If you wish override the request/response transformations only for a single request then provide
8971     * `transformRequest` and/or `transformResponse` properties on the configuration object passed
8972     * into `$http`.
8973     *
8974     * Note that if you provide these properties on the config object the default transformations will be
8975     * overwritten. If you wish to augment the default transformations then you must include them in your
8976     * local transformation array.
8977     *
8978     * The following code demonstrates adding a new response transformation to be run after the default response
8979     * transformations have been run.
8980     *
8981     * ```js
8982     * function appendTransform(defaults, transform) {
8983     *
8984     *   // We can't guarantee that the default transformation is an array
8985     *   defaults = angular.isArray(defaults) ? defaults : [defaults];
8986     *
8987     *   // Append the new transformation to the defaults
8988     *   return defaults.concat(transform);
8989     * }
8990     *
8991     * $http({
8992     *   url: '...',
8993     *   method: 'GET',
8994     *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
8995     *     return doTransform(value);
8996     *   })
8997     * });
8998     * ```
8999     *
9000     *
9001     * ## Caching
9002     *
9003     * To enable caching, set the request configuration `cache` property to `true` (to use default
9004     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
9005     * When the cache is enabled, `$http` stores the response from the server in the specified
9006     * cache. The next time the same request is made, the response is served from the cache without
9007     * sending a request to the server.
9008     *
9009     * Note that even if the response is served from cache, delivery of the data is asynchronous in
9010     * the same way that real requests are.
9011     *
9012     * If there are multiple GET requests for the same URL that should be cached using the same
9013     * cache, but the cache is not populated yet, only one request to the server will be made and
9014     * the remaining requests will be fulfilled using the response from the first request.
9015     *
9016     * You can change the default cache to a new object (built with
9017     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
9018     * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
9019     * their `cache` property to `true` will now use this cache object.
9020     *
9021     * If you set the default cache to `false` then only requests that specify their own custom
9022     * cache object will be cached.
9023     *
9024     * ## Interceptors
9025     *
9026     * Before you start creating interceptors, be sure to understand the
9027     * {@link ng.$q $q and deferred/promise APIs}.
9028     *
9029     * For purposes of global error handling, authentication, or any kind of synchronous or
9030     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
9031     * able to intercept requests before they are handed to the server and
9032     * responses before they are handed over to the application code that
9033     * initiated these requests. The interceptors leverage the {@link ng.$q
9034     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
9035     *
9036     * The interceptors are service factories that are registered with the `$httpProvider` by
9037     * adding them to the `$httpProvider.interceptors` array. The factory is called and
9038     * injected with dependencies (if specified) and returns the interceptor.
9039     *
9040     * There are two kinds of interceptors (and two kinds of rejection interceptors):
9041     *
9042     *   * `request`: interceptors get called with a http `config` object. The function is free to
9043     *     modify the `config` object or create a new one. The function needs to return the `config`
9044     *     object directly, or a promise containing the `config` or a new `config` object.
9045     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
9046     *     resolved with a rejection.
9047     *   * `response`: interceptors get called with http `response` object. The function is free to
9048     *     modify the `response` object or create a new one. The function needs to return the `response`
9049     *     object directly, or as a promise containing the `response` or a new `response` object.
9050     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
9051     *     resolved with a rejection.
9052     *
9053     *
9054     * ```js
9055     *   // register the interceptor as a service
9056     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
9057     *     return {
9058     *       // optional method
9059     *       'request': function(config) {
9060     *         // do something on success
9061     *         return config;
9062     *       },
9063     *
9064     *       // optional method
9065     *      'requestError': function(rejection) {
9066     *         // do something on error
9067     *         if (canRecover(rejection)) {
9068     *           return responseOrNewPromise
9069     *         }
9070     *         return $q.reject(rejection);
9071     *       },
9072     *
9073     *
9074     *
9075     *       // optional method
9076     *       'response': function(response) {
9077     *         // do something on success
9078     *         return response;
9079     *       },
9080     *
9081     *       // optional method
9082     *      'responseError': function(rejection) {
9083     *         // do something on error
9084     *         if (canRecover(rejection)) {
9085     *           return responseOrNewPromise
9086     *         }
9087     *         return $q.reject(rejection);
9088     *       }
9089     *     };
9090     *   });
9091     *
9092     *   $httpProvider.interceptors.push('myHttpInterceptor');
9093     *
9094     *
9095     *   // alternatively, register the interceptor via an anonymous factory
9096     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
9097     *     return {
9098     *      'request': function(config) {
9099     *          // same as above
9100     *       },
9101     *
9102     *       'response': function(response) {
9103     *          // same as above
9104     *       }
9105     *     };
9106     *   });
9107     * ```
9108     *
9109     * ## Security Considerations
9110     *
9111     * When designing web applications, consider security threats from:
9112     *
9113     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9114     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
9115     *
9116     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
9117     * pre-configured with strategies that address these issues, but for this to work backend server
9118     * cooperation is required.
9119     *
9120     * ### JSON Vulnerability Protection
9121     *
9122     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9123     * allows third party website to turn your JSON resource URL into
9124     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
9125     * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
9126     * Angular will automatically strip the prefix before processing it as JSON.
9127     *
9128     * For example if your server needs to return:
9129     * ```js
9130     * ['one','two']
9131     * ```
9132     *
9133     * which is vulnerable to attack, your server can return:
9134     * ```js
9135     * )]}',
9136     * ['one','two']
9137     * ```
9138     *
9139     * Angular will strip the prefix, before processing the JSON.
9140     *
9141     *
9142     * ### Cross Site Request Forgery (XSRF) Protection
9143     *
9144     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
9145     * an unauthorized site can gain your user's private data. Angular provides a mechanism
9146     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
9147     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
9148     * JavaScript that runs on your domain could read the cookie, your server can be assured that
9149     * the XHR came from JavaScript running on your domain. The header will not be set for
9150     * cross-domain requests.
9151     *
9152     * To take advantage of this, your server needs to set a token in a JavaScript readable session
9153     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
9154     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
9155     * that only JavaScript running on your domain could have sent the request. The token must be
9156     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
9157     * making up its own tokens). We recommend that the token is a digest of your site's
9158     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
9159     * for added security.
9160     *
9161     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
9162     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
9163     * or the per-request config object.
9164     *
9165     *
9166     * @param {object} config Object describing the request to be made and how it should be
9167     *    processed. The object has following properties:
9168     *
9169     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
9170     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
9171     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
9172     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
9173     *      JSONified.
9174     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
9175     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
9176     *      HTTP headers to send to the server. If the return value of a function is null, the
9177     *      header will not be sent.
9178     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
9179     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
9180     *    - **transformRequest** –
9181     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>
9181}` –
9182     *      transform function or an array of such functions. The transform function takes the http
9183     *      request body and headers and returns its transformed (typically serialized) version.
9184     *      See {@link ng.$http#overriding-the-default-transformations-per-request
9185     *      Overriding the Default Transformations}
9186     *    - **transformResponse** –
9187     *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
9188     *      transform function or an array of such functions. The transform function takes the http
9189     *      response body, headers and status and returns its transformed (typically deserialized) version.
9190     *      See {@link ng.$http#overriding-the-default-transformations-per-request
9191     *      Overriding the Default Transformations}
9192     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
9193     *      GET request, otherwise if a cache instance built with
9194     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
9195     *      caching.
9196     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
9197     *      that should abort the request when resolved.
9198     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
9199     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
9200     *      for more information.
9201     *    - **responseType** - `{string}` - see
9202     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
9203     *
9204     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
9205     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
9206     *   method takes two arguments a success and an error callback which will be called with a
9207     *   response object. The `success` and `error` methods take a single argument - a function that
9208     *   will be called when the request succeeds or fails respectively. The arguments passed into
9209     *   these functions are destructured representation of the response object passed into the
9210     *   `then` method. The response object has these properties:
9211     *
9212     *   - **data** – `{string|Object}` – The response body transformed with the transform
9213     *     functions.
9214     *   - **status** – `{number}` – HTTP status code of the response.
9215     *   - **headers** – `{function([headerName])}` – Header getter function.
9216     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9217     *   - **statusText** – `{string}` – HTTP status text of the response.
9218     *
9219     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
9220     *   requests. This is primarily meant to be used for debugging purposes.
9221     *
9222     *
9223     * @example
9224<example module="httpExample">
9225<file name="index.html">
9226  <div ng-controller="FetchController">
9227    <select ng-model="method">
9228      <option>GET</option>
9229      <option>JSONP</option>
9230    </select>
9231    <input type="text" ng-model="url" size="80"/>
9232    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
9233    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
9234    <button id="samplejsonpbtn"
9235      ng-click="updateModel('JSONP',
9236                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
9237      Sample JSONP
9238    </button>
9239    <button id="invalidjsonpbtn"
9240      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
9241        Invalid JSONP
9242      </button>
9243    <pre>http status code: {{status}}</pre>
9244    <pre>http response data: {{data}}</pre>
9245  </div>
9246</file>
9247<file name="script.js">
9248  angular.module('httpExample', [])
9249    .controller('FetchController', ['$scope', '$http', '$templateCache',
9250      function($scope, $http, $templateCache) {
9251        $scope.method = 'GET';
9252        $scope.url = 'http-hello.html';
9253
9254        $scope.fetch = function() {
9255          $scope.code = null;
9256          $scope.response = null;
9257
9258          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
9259            success(function(data, status) {
9260              $scope.status = status;
9261              $scope.data = data;
9262            }).
9263            error(function(data, status) {
9264              $scope.data = data || "Request failed";
9265              $scope.status = status;
9266          });
9267        };
9268
9269        $scope.updateModel = function(method, url) {
9270          $scope.method = method;
9271          $scope.url = url;
9272        };
9273      }]);
9274</file>
9275<file name="http-hello.html">
9276  Hello, $http!
9277</file>
9278<file name="protractor.js" type="protractor">
9279  var status = element(by.binding('status'));
9280  var data = element(by.binding('data'));
9281  var fetchBtn = element(by.id('fetchbtn'));
9282  var sampleGetBtn = element(by.id('samplegetbtn'));
9283  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
9284  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
9285
9286  it('should make an xhr GET request', function() {
9287    sampleGetBtn.click();
9288    fetchBtn.click();
9289    expect(status.getText()).toMatch('200');
9290    expect(data.getText()).toMatch(/Hello, \$http!/);
9291  });
9292
9293// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
9294// it('should make a JSONP request to angularjs.org', function() {
9295//   sampleJsonpBtn.click();
9296//   fetchBtn.click();
9297//   expect(status.getText()).toMatch('200');
9298//   expect(data.getText()).toMatch(/Super Hero!/);
9299// });
9300
9301  it('should make JSONP request to invalid URL and invoke the error handler',
9302      function() {
9303    invalidJsonpBtn.click();
9304    fetchBtn.click();
9305    expect(status.getText()).toMatch('0');
9306    expect(data.getText()).toMatch('Request failed');
9307  });
9308</file>
9309</example>
9310     */
9311    function $http(requestConfig) {
9312
9313      if (!angular.isObject(requestConfig)) {
9314        throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
9315      }
9316
9317      var config = extend({
9318        method: 'get',
9319        transformRequest: defaults.transformRequest,
9320        transformResponse: defaults.transformResponse
9321      }, requestConfig);
9322
9323      config.headers = mergeHeaders(requestConfig);
9324      config.method = uppercase(config.method);
9325
9326      var serverRequest = function(config) {
9327        var headers = config.headers;
9328        var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
9329
9330        // strip content-type if data is undefined
9331        if (isUndefined(reqData)) {
9332          forEach(headers, function(value, header) {
9333            if (lowercase(header) === 'content-type') {
9334                delete headers[header];
9335            }
9336          });
9337        }
9338
9339        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
9340          config.withCredentials = defaults.withCredentials;
9341        }
9342
9343        // send request
9344        return sendReq(config, reqData).then(transformResponse, transformResponse);
9345      };
9346
9347      var chain = [serverRequest, undefined];
9348      var promise = $q.when(config);
9349
9350      // apply interceptors
9351      forEach(reversedInterceptors, function(interceptor) {
9352        if (interceptor.request || interceptor.requestError) {
9353          chain.unshift(interceptor.request, interceptor.requestError);
9354        }
9355        if (interceptor.response || interceptor.responseError) {
9356          chain.push(interceptor.response, interceptor.responseError);
9357        }
9358      });
9359
9360      while (chain.length) {
9361        var thenFn = chain.shift();
9362        var rejectFn = chain.shift();
9363
9364        promise = promise.then(thenFn, rejectFn);
9365      }
9366
9367      promise.success = function(fn) {
9368        promise.then(function(response) {
9369          fn(response.data, response.status, response.headers, config);
9370        });
9371        return promise;
9372      };
9373
9374      promise.error = function(fn) {
9375        promise.then(null, function(response) {
9376          fn(response.data, response.status, response.headers, config);
9377        });
9378        return promise;
9379      };
9380
9381      return promise;
9382
9383      function transformResponse(response) {
9384        // make a copy since the response must be cacheable
9385        var resp = extend({}, response);
9386        if (!response.data) {
9387          resp.data = response.data;
9388        } else {
9389          resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
9390        }
9391        return (isSuccess(response.status))
9392          ? resp
9393          : $q.reject(resp);
9394      }
9395
9396      function executeHeaderFns(headers) {
9397        var headerContent, processedHeaders = {};
9398
9399        forEach(headers, function(headerFn, header) {
9400          if (isFunction(headerFn)) {
9401            headerContent = headerFn();
9402            if (headerContent != null) {
9403              processedHeaders[header] = headerContent;
9404            }
9405          } else {
9406            processedHeaders[header] = headerFn;
9407          }
9408        });
9409
9410        return processedHeaders;
9411      }
9412
9413      function mergeHeaders(config) {
9414        var defHeaders = defaults.headers,
9415            reqHeaders = extend({}, config.headers),
9416            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
9417
9418        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
9419
9420        // using for-in instead of forEach to avoid unecessary iteration after header has been found
9421        defaultHeadersIteration:
9422        for (defHeaderName in defHeaders) {
9423          lowercaseDefHeaderName = lowercase(defHeaderName);
9424
9425          for (reqHeaderName in reqHeaders) {
9426            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
9427              continue defaultHeadersIteration;
9428            }
9429          }
9430
9431          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
9432        }
9433
9434        // execute if header value is a function for merged headers
9435        return executeHeaderFns(reqHeaders);
9436      }
9437    }
9438
9439    $http.pendingRequests = [];
9440
9441    /**
9442     * @ngdoc method
9443     * @name $http#get
9444     *
9445     * @description
9446     * Shortcut method to perform `GET` request.
9447     *
9448     * @param {string} url Relative or absolute URL specifying the destination of the request
9449     * @param {Object=} config Optional configuration object
9450     * @returns {HttpPromise} Future object
9451     */
9452
9453    /**
9454     * @ngdoc method
9455     * @name $http#delete
9456     *
9457     * @description
9458     * Shortcut method to perform `DELETE` request.
9459     *
9460     * @param {string} url Relative or absolute URL specifying the destination of the request
9461     * @param {Object=} config Optional configuration object
9462     * @returns {HttpPromise} Future object
9463     */
9464
9465    /**
9466     * @ngdoc method
9467     * @name $http#head
9468     *
9469     * @description
9470     * Shortcut method to perform `HEAD` request.
9471     *
9472     * @param {string} url Relative or absolute URL specifying the destination of the request
9473     * @param {Object=} config Optional configuration object
9474     * @returns {HttpPromise} Future object
9475     */
9476
9477    /**
9478     * @ngdoc method
9479     * @name $http#jsonp
9480     *
9481     * @description
9482     * Shortcut method to perform `JSONP` request.
9483     *
9484     * @param {string} url Relative or absolute URL specifying the destination of the request.
9485     *                     The name of the callback should be the string `JSON_CALLBACK`.
9486     * @param {Object=} config Optional configuration object
9487     * @returns {HttpPromise} Future object
9488     */
9489    createShortMethods('get', 'delete', 'head', 'jsonp');
9490
9491    /**
9492     * @ngdoc method
9493     * @name $http#post
9494     *
9495     * @description
9496     * Shortcut method to perform `POST` request.
9497     *
9498     * @param {string} url Relative or absolute URL specifying the destination of the request
9499     * @param {*} data Request content
9500     * @param {Object=} config Optional configuration object
9501     * @returns {HttpPromise} Future object
9502     */
9503
9504    /**
9505     * @ngdoc method
9506     * @name $http#put
9507     *
9508     * @description
9509     * Shortcut method to perform `PUT` request.
9510     *
9511     * @param {string} url Relative or absolute URL specifying the destination of the request
9512     * @param {*} data Request content
9513     * @param {Object=} config Optional configuration object
9514     * @returns {HttpPromise} Future object
9515     */
9516
9517     /**
9518      * @ngdoc method
9519      * @name $http#patch
9520      *
9521      * @description
9522      * Shortcut method to perform `PATCH` request.
9523      *
9524      * @param {string} url Relative or absolute URL specifying the destination of the request
9525      * @param {*} data Request content
9526      * @param {Object=} config Optional configuration object
9527      * @returns {HttpPromise} Future object
9528      */
9529    createShortMethodsWithData('post', 'put', 'patch');
9530
9531        /**
9532         * @ngdoc property
9533         * @name $http#defaults
9534         *
9535         * @description
9536         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
9537         * default headers, withCredentials as well as request and response transformations.
9538         *
9539         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
9540         */
9541    $http.defaults = defaults;
9542
9543
9544    return $http;
9545
9546
9547    function createShortMethods(names) {
9548      forEach(arguments, function(name) {
9549        $http[name] = function(url, config) {
9550          return $http(extend(config || {}, {
9551            method: name,
9552            url: url
9553          }));
9554        };
9555      });
9556    }
9557
9558
9559    function createShortMethodsWithData(name) {
9560      forEach(arguments, function(name) {
9561        $http[name] = function(url, data, config) {
9562          return $http(extend(config || {}, {
9563            method: name,
9564            url: url,
9565            data: data
9566          }));
9567        };
9568      });
9569    }
9570
9571
9572    /**
9573     * Makes the request.
9574     *
9575     * !!! ACCESSES CLOSURE VARS:
9576     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
9577     */
9578    function sendReq(config, reqData) {
9579      var deferred = $q.defer(),
9580          promise = deferred.promise,
9581          cache,
9582          cachedResp,
9583          reqHeaders = config.headers,
9584          url = buildUrl(config.url, config.params);
9585
9586      $http.pendingRequests.push(config);
9587      promise.then(removePendingReq, removePendingReq);
9588
9589
9590      if ((config.cache || defaults.cache) && config.cache !== false &&
9591          (config.method === 'GET' || config.method === 'JSONP')) {
9592        cache = isObject(config.cache) ? config.cache
9593              : isObject(defaults.cache) ? defaults.cache
9594              : defaultCache;
9595      }
9596
9597      if (cache) {
9598        cachedResp = cache.get(url);
9599        if (isDefined(cachedResp)) {
9600          if (isPromiseLike(cachedResp)) {
9601            // cached request has already been sent, but there is no response yet
9602            cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
9603          } else {
9604            // serving from cache
9605            if (isArray(cachedResp)) {
9606              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
9607            } else {
9608              resolvePromise(cachedResp, 200, {}, 'OK');
9609            }
9610          }
9611        } else {
9612          // put the promise for the non-transformed response into cache as a placeholder
9613          cache.put(url, promise);
9614        }
9615      }
9616
9617
9618      // if we won't have the response in cache, set the xsrf headers and
9619      // send the request to the backend
9620      if (isUndefined(cachedResp)) {
9621        var xsrfValue = urlIsSameOrigin(config.url)
9622            ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
9623            : undefined;
9624        if (xsrfValue) {
9625          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
9626        }
9627
9628        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
9629            config.withCredentials, config.responseType);
9630      }
9631
9632      return promise;
9633
9634
9635      /**
9636       * Callback registered to $httpBackend():
9637       *  - caches the response if desired
9638       *  - resolves the raw $http promise
9639       *  - calls $apply
9640       */
9641      function done(status, response, headersString, statusText) {
9642        if (cache) {
9643          if (isSuccess(status)) {
9644            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
9645          } else {
9646            // remove promise from the cache
9647            cache.remove(url);
9648          }
9649        }
9650
9651        function resolveHttpPromise() {
9652          resolvePromise(response, status, headersString, statusText);
9653        }
9654
9655        if (useApplyAsync) {
9656          $rootScope.$applyAsync(resolveHttpPromise);
9657        } else {
9658          resolveHttpPromise();
9659          if (!$rootScope.$$phase) $rootScope.$apply();
9660        }
9661      }
9662
9663
9664      /**
9665       * Resolves the raw $http promise.
9666       */
9667      function resolvePromise(response, status, headers, statusText) {
9668        // normalize internal statuses to 0
9669        status = Math.max(status, 0);
9670
9671        (isSuccess(status) ? deferred.resolve : deferred.reject)({
9672          data: response,
9673          status: status,
9674          headers: headersGetter(headers),
9675          config: config,
9676          statusText: statusText
9677        });
9678      }
9679
9680      function resolvePromiseWithResult(result) {
9681        resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
9682      }
9683
9684      function removePendingReq() {
9685        var idx = $http.pendingRequests.indexOf(config);
9686        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
9687      }
9688    }
9689
9690
9691    function buildUrl(url, params) {
9692      if (!params) return url;
9693      var parts = [];
9694      forEachSorted(params, function(value, key) {
9695        if (value === null || isUndefined(value)) return;
9696        if (!isArray(value)) value = [value];
9697
9698        forEach(value, function(v) {
9699          if (isObject(v)) {
9700            if (isDate(v)) {
9701              v = v.toISOString();
9702            } else {
9703              v = toJson(v);
9704            }
9705          }
9706          parts.push(encodeUriQuery(key) + '=' +
9707                     encodeUriQuery(v));
9708        });
9709      });
9710      if (parts.length > 0) {
9711        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
9712      }
9713      return url;
9714    }
9715  }];
9716}
9717
9718function createXhr() {
9719    return new window.XMLHttpRequest();
9720}
9721
9722/**
9723 * @ngdoc service
9724 * @name $httpBackend
9725 * @requires $window
9726 * @requires $document
9727 *
9728 * @description
9729 * HTTP backend used by the {@link ng.$http service} that delegates to
9730 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
9731 *
9732 * You should never need to use this service directly, instead use the higher-level abstractions:
9733 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
9734 *
9735 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
9736 * $httpBackend} which can be trained with responses.
9737 */
9738function $HttpBackendProvider() {
9739  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
9740    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
9741  }];
9742}
9743
9744function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
9745  // TODO(vojta): fix the signature
9746  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
9747    $browser.$$incOutstandingRequestCount();
9748    url = url || $browser.url();
9749
9750    if (lowercase(method) == 'jsonp') {
9751      var callbackId = '_' + (callbacks.counter++).toString(36);
9752      callbacks[callbackId] = function(data) {
9753        callbacks[callbackId].data = data;
9754        callbacks[callbackId].called = true;
9755      };
9756
9757      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
9758          callbackId, function(status, text) {
9759        completeRequest(callback, status, callbacks[callbackId].data, "", text);
9760        callbacks[callbackId] = noop;
9761      });
9762    } else {
9763
9764      var xhr = createXhr();
9765
9766      xhr.open(method, url, true);
9767      forEach(headers, function(value, key) {
9768        if (isDefined(value)) {
9769            xhr.setRequestHeader(key, value);
9770        }
9771      });
9772
9773      xhr.onload = function requestLoaded() {
9774        var statusText = xhr.statusText || '';
9775
9776        // responseText is the old-school way of retrieving response (supported by IE8 & 9)
9777        // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
9778        var response = ('response' in xhr) ? xhr.response : xhr.responseText;
9779
9780        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
9781        var status = xhr.status === 1223 ? 204 : xhr.status;
9782
9783        // fix status code when it is 0 (0 status is undocumented).
9784        // Occurs when accessing file resources or on Android 4.1 stock browser
9785        // while retrieving files from application cache.
9786        if (status === 0) {
9787          status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
9788        }
9789
9790        completeRequest(callback,
9791            status,
9792            response,
9793            xhr.getAllResponseHeaders(),
9794            statusText);
9795      };
9796
9797      var requestError = function() {
9798        // The response is always empty
9799        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
9800        completeRequest(callback, -1, null, null, '');
9801      };
9802
9803      xhr.onerror = requestError;
9804      xhr.onabort = requestError;
9805
9806      if (withCredentials) {
9807        xhr.withCredentials = true;
9808      }
9809
9810      if (responseType) {
9811        try {
9812          xhr.responseType = responseType;
9813        } catch (e) {
9814          // WebKit added support for the json responseType value on 09/03/2013
9815          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
9816          // known to throw when setting the value "json" as the response type. Other older
9817          // browsers implementing the responseType
9818          //
9819          // The json response type can be ignored if not supported, because JSON payloads are
9820          // parsed on the client-side regardless.
9821          if (responseType !== 'json') {
9822            throw e;
9823          }
9824        }
9825      }
9826
9827      xhr.send(post || null);
9828    }
9829
9830    if (timeout > 0) {
9831      var timeoutId = $browserDefer(timeoutRequest, timeout);
9832    } else if (isPromiseLike(timeout)) {
9833      timeout.then(timeoutRequest);
9834    }
9835
9836
9837    function timeoutRequest() {
9838      jsonpDone && jsonpDone();
9839      xhr && xhr.abort();
9840    }
9841
9842    function completeRequest(callback, status, response, headersString, statusText) {
9843      // cancel timeout and subsequent timeout promise resolution
9844      if (timeoutId !== undefined) {
9845        $browserDefer.cancel(timeoutId);
9846      }
9847      jsonpDone = xhr = null;
9848
9849      callback(status, response, headersString, statusText);
9850      $browser.$$completeOutstandingRequest(noop);
9851    }
9852  };
9853
9854  function jsonpReq(url, callbackId, done) {
9855    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
9856    // - fetches local scripts via XHR and evals them
9857    // - adds and immediately removes script elements from the document
9858    var script = rawDocument.createElement('script'), callback = null;
9859    script.type = "text/javascript";
9860    script.src = url;
9861    script.async = true;
9862
9863    callback = function(event) {
9864      removeEventListenerFn(script, "load", callback);
9865      removeEventListenerFn(script, "error", callback);
9866      rawDocument.body.removeChild(script);
9867      script = null;
9868      var status = -1;
9869      var text = "unknown";
9870
9871      if (event) {
9872        if (event.type === "load" && !callbacks[callbackId].called) {
9873          event = { type: "error" };
9874        }
9875        text = event.type;
9876        status = event.type === "error" ? 404 : 200;
9877      }
9878
9879      if (done) {
9880        done(status, text);
9881      }
9882    };
9883
9884    addEventListenerFn(script, "load", callback);
9885    addEventListenerFn(script, "error", callback);
9886    rawDocument.body.appendChild(script);
9887    return callback;
9888  }
9889}
9890
9891var $interpolateMinErr = minErr('$interpolate');
9892
9893/**
9894 * @ngdoc provider
9895 * @name $interpolateProvider
9896 *
9897 * @description
9898 *
9899 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
9900 *
9901 * @example
9902<example module="customInterpolationApp">
9903<file name="index.html">
9904<script>
9905  var customInterpolationApp = angular.module('customInterpolationApp', []);
9906
9907  customInterpolationApp.config(function($interpolateProvider) {
9908    $interpolateProvider.startSymbol('//');
9909    $interpolateProvider.endSymbol('//');
9910  });
9911
9912
9913  customInterpolationApp.controller('DemoController', function() {
9914      this.label = "This binding is brought you by // interpolation symbols.";
9915  });
9916</script>
9917<div ng-app="App" ng-controller="DemoController as demo">
9918    //demo.label//
9919</div>
9920</file>
9921<file name="protractor.js" type="protractor">
9922  it('should interpolate binding with custom symbols', function() {
9923    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
9924  });
9925</file>
9926</example>
9927 */
9928function $InterpolateProvider() {
9929  var startSymbol = '{{';
9930  var endSymbol = '}}';
9931
9932  /**
9933   * @ngdoc method
9934   * @name $interpolateProvider#startSymbol
9935   * @description
9936   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
9937   *
9938   * @param {string=} value new value to set the starting symbol to.
9939   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
9940   */
9941  this.startSymbol = function(value) {
9942    if (value) {
9943      startSymbol = value;
9944      return this;
9945    } else {
9946      return startSymbol;
9947    }
9948  };
9949
9950  /**
9951   * @ngdoc method
9952   * @name $interpolateProvider#endSymbol
9953   * @description
9954   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
9955   *
9956   * @param {string=} value new value to set the ending symbol to.
9957   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
9958   */
9959  this.endSymbol = function(value) {
9960    if (value) {
9961      endSymbol = value;
9962      return this;
9963    } else {
9964      return endSymbol;
9965    }
9966  };
9967
9968
9969  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
9970    var startSymbolLength = startSymbol.length,
9971        endSymbolLength = endSymbol.length,
9972        escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
9973        escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
9974
9975    function escape(ch) {
9976      return '\\\\\\' + ch;
9977    }
9978
9979    /**
9980     * @ngdoc service
9981     * @name $interpolate
9982     * @kind function
9983     *
9984     * @requires $parse
9985     * @requires $sce
9986     *
9987     * @description
9988     *
9989     * Compiles a string with markup into an interpolation function. This service is used by the
9990     * HTML {@link ng.$compile $compile} service for data binding. See
9991     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
9992     * interpolation markup.
9993     *
9994     *
9995     * ```js
9996     *   var $interpolate = ...; // injected
9997     *   var exp = $interpolate('Hello {{name | uppercase}}!');
9998     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
9999     * ```
10000     *
10001     * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
10002     * `true`, the interpolation function will return `undefined` unless all embedded expressions
10003     * evaluate to a value other than `undefined`.
10004     *
10005     * ```js
10006     *   var $interpolate = ...; // injected
10007     *   var context = {greeting: 'Hello', name: undefined };
10008     *
10009     *   // default "forgiving" mode
10010     *   var exp = $interpolate('{{greeting}} {{name}}!');
10011     *   expect(exp(context)).toEqual('Hello !');
10012     *
10013     *   // "allOrNothing" mode
10014     *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
10015     *   expect(exp(context)).toBeUndefined();
10016     *   context.name = 'Angular';
10017     *   expect(exp(context)).toEqual('Hello Angular!');
10018     * ```
10019     *
10020     * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
10021     *
10022     * ####Escaped Interpolation
10023     * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
10024     * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
10025     * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
10026     * or binding.
10027     *
10028     * This enables web-servers to prevent script injection attacks and defacing attacks, to some
10029     * degree, while also enabling code examples to work without relying on the
10030     * {@link ng.directive:ngNonBindable ngNonBindable} directive.
10031     *
10032     * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
10033     * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
10034     * interpolation start/end markers with their escaped counterparts.**
10035     *
10036     * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
10037     * output when the $interpolate service processes the text. So, for HTML elements interpolated
10038     * by {@link ng.$compile $compile}
10038, or otherwise interpolated with the `mustHaveExpression` parameter
10039     * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
10040     * this is typically useful only when user-data is used in rendering a template from the server, or
10041     * when otherwise untrusted data is used by a directive.
10042     *
10043     * <example>
10044     *  <file name="index.html">
10045     *    <div ng-init="username='A user'">
10046     *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
10047     *        </p>
10048     *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
10049     *        application, but fails to accomplish their task, because the server has correctly
10050     *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
10051     *        characters.</p>
10052     *      <p>Instead, the result of the attempted script injection is visible, and can be removed
10053     *        from the database by an administrator.</p>
10054     *    </div>
10055     *  </file>
10056     * </example>
10057     *
10058     * @param {string} text The text with markup to interpolate.
10059     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
10060     *    embedded expression in order to return an interpolation function. Strings with no
10061     *    embedded expression will return null for the interpolation function.
10062     * @param {string=} trustedContext when provided, the returned function passes the interpolated
10063     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
10064     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
10065     *    provides Strict Contextual Escaping for details.
10066     * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
10067     *    unless all embedded expressions evaluate to a value other than `undefined`.
10068     * @returns {function(context)} an interpolation function which is used to compute the
10069     *    interpolated string. The function has these parameters:
10070     *
10071     * - `context`: evaluation context for all expressions embedded in the interpolated text
10072     */
10073    function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
10074      allOrNothing = !!allOrNothing;
10075      var startIndex,
10076          endIndex,
10077          index = 0,
10078          expressions = [],
10079          parseFns = [],
10080          textLength = text.length,
10081          exp,
10082          concat = [],
10083          expressionPositions = [];
10084
10085      while (index < textLength) {
10086        if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
10087             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
10088          if (index !== startIndex) {
10089            concat.push(unescapeText(text.substring(index, startIndex)));
10090          }
10091          exp = text.substring(startIndex + startSymbolLength, endIndex);
10092          expressions.push(exp);
10093          parseFns.push($parse(exp, parseStringifyInterceptor));
10094          index = endIndex + endSymbolLength;
10095          expressionPositions.push(concat.length);
10096          concat.push('');
10097        } else {
10098          // we did not find an interpolation, so we have to add the remainder to the separators array
10099          if (index !== textLength) {
10100            concat.push(unescapeText(text.substring(index)));
10101          }
10102          break;
10103        }
10104      }
10105
10106      // Concatenating expressions makes it hard to reason about whether some combination of
10107      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
10108      // single expression be used for iframe[src], object[src], etc., we ensure that the value
10109      // that's used is assigned or constructed by some JS code somewhere that is more testable or
10110      // make it obvious that you bound the value to some user controlled value.  This helps reduce
10111      // the load when auditing for XSS issues.
10112      if (trustedContext && concat.length > 1) {
10113          throw $interpolateMinErr('noconcat',
10114              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10115              "interpolations that concatenate multiple expressions when a trusted value is " +
10116              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10117      }
10118
10119      if (!mustHaveExpression || expressions.length) {
10120        var compute = function(values) {
10121          for (var i = 0, ii = expressions.length; i < ii; i++) {
10122            if (allOrNothing && isUndefined(values[i])) return;
10123            concat[expressionPositions[i]] = values[i];
10124          }
10125          return concat.join('');
10126        };
10127
10128        var getValue = function(value) {
10129          return trustedContext ?
10130            $sce.getTrusted(trustedContext, value) :
10131            $sce.valueOf(value);
10132        };
10133
10134        var stringify = function(value) {
10135          if (value == null) { // null || undefined
10136            return '';
10137          }
10138          switch (typeof value) {
10139            case 'string':
10140              break;
10141            case 'number':
10142              value = '' + value;
10143              break;
10144            default:
10145              value = toJson(value);
10146          }
10147
10148          return value;
10149        };
10150
10151        return extend(function interpolationFn(context) {
10152            var i = 0;
10153            var ii = expressions.length;
10154            var values = new Array(ii);
10155
10156            try {
10157              for (; i < ii; i++) {
10158                values[i] = parseFns[i](context);
10159              }
10160
10161              return compute(values);
10162            } catch (err) {
10163              var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10164                  err.toString());
10165              $exceptionHandler(newErr);
10166            }
10167
10168          }, {
10169          // all of these properties are undocumented for now
10170          exp: text, //just for compatibility with regular watchers created via $watch
10171          expressions: expressions,
10172          $$watchDelegate: function(scope, listener, objectEquality) {
10173            var lastValue;
10174            return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
10175              var currValue = compute(values);
10176              if (isFunction(listener)) {
10177                listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
10178              }
10179              lastValue = currValue;
10180            }, objectEquality);
10181          }
10182        });
10183      }
10184
10185      function unescapeText(text) {
10186        return text.replace(escapedStartRegexp, startSymbol).
10187          replace(escapedEndRegexp, endSymbol);
10188      }
10189
10190      function parseStringifyInterceptor(value) {
10191        try {
10192          value = getValue(value);
10193          return allOrNothing && !isDefined(value) ? value : stringify(value);
10194        } catch (err) {
10195          var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10196            err.toString());
10197          $exceptionHandler(newErr);
10198        }
10199      }
10200    }
10201
10202
10203    /**
10204     * @ngdoc method
10205     * @name $interpolate#startSymbol
10206     * @description
10207     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
10208     *
10209     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
10210     * the symbol.
10211     *
10212     * @returns {string} start symbol.
10213     */
10214    $interpolate.startSymbol = function() {
10215      return startSymbol;
10216    };
10217
10218
10219    /**
10220     * @ngdoc method
10221     * @name $interpolate#endSymbol
10222     * @description
10223     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10224     *
10225     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
10226     * the symbol.
10227     *
10228     * @returns {string} end symbol.
10229     */
10230    $interpolate.endSymbol = function() {
10231      return endSymbol;
10232    };
10233
10234    return $interpolate;
10235  }];
10236}
10237
10238function $IntervalProvider() {
10239  this.$get = ['$rootScope', '$window', '$q', '$$q',
10240       function($rootScope,   $window,   $q,   $$q) {
10241    var intervals = {};
10242
10243
10244     /**
10245      * @ngdoc service
10246      * @name $interval
10247      *
10248      * @description
10249      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
10250      * milliseconds.
10251      *
10252      * The return value of registering an interval function is a promise. This promise will be
10253      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
10254      * run indefinitely if `count` is not defined. The value of the notification will be the
10255      * number of iterations that have run.
10256      * To cancel an interval, call `$interval.cancel(promise)`.
10257      *
10258      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
10259      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
10260      * time.
10261      *
10262      * <div class="alert alert-warning">
10263      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
10264      * with them.  In particular they are not automatically destroyed when a controller's scope or a
10265      * directive's element are destroyed.
10266      * You should take this into consideration and make sure to always cancel the interval at the
10267      * appropriate moment.  See the example below for more details on how and when to do this.
10268      * </div>
10269      *
10270      * @param {function()} fn A function that should be called repeatedly.
10271      * @param {number} delay Number of milliseconds between each function call.
10272      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
10273      *   indefinitely.
10274      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
10275      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
10276      * @returns {promise} A promise which will be notified on each iteration.
10277      *
10278      * @example
10279      * <example module="intervalExample">
10280      * <file name="index.html">
10281      *   <script>
10282      *     angular.module('intervalExample', [])
10283      *       .controller('ExampleController', ['$scope', '$interval',
10284      *         function($scope, $interval) {
10285      *           $scope.format = 'M/d/yy h:mm:ss a';
10286      *           $scope.blood_1 = 100;
10287      *           $scope.blood_2 = 120;
10288      *
10289      *           var stop;
10290      *           $scope.fight = function() {
10291      *             // Don't start a new fight if we are already fighting
10292      *             if ( angular.isDefined(stop) ) return;
10293      *
10294      *             stop = $interval(function() {
10295      *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10296      *                 $scope.blood_1 = $scope.blood_1 - 3;
10297      *                 $scope.blood_2 = $scope.blood_2 - 4;
10298      *               } else {
10299      *                 $scope.stopFight();
10300      *               }
10301      *             }, 100);
10302      *           };
10303      *
10304      *           $scope.stopFight = function() {
10305      *             if (angular.isDefined(stop)) {
10306      *               $interval.cancel(stop);
10307      *               stop = undefined;
10308      *             }
10309      *           };
10310      *
10311      *           $scope.resetFight = function() {
10312      *             $scope.blood_1 = 100;
10313      *             $scope.blood_2 = 120;
10314      *           };
10315      *
10316      *           $scope.$on('$destroy', function() {
10317      *             // Make sure that the interval is destroyed too
10318      *             $scope.stopFight();
10319      *           });
10320      *         }])
10321      *       // Register the 'myCurrentTime' directive factory method.
10322      *       // We inject $interval and dateFilter service since the factory method is DI.
10323      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
10324      *         function($interval, dateFilter) {
10325      *           // return the directive link function. (compile function not needed)
10326      *           return function(scope, element, attrs) {
10327      *             var format,  // date format
10328      *                 stopTime; // so that we can cancel the time updates
10329      *
10330      *             // used to update the UI
10331      *             function updateTime() {
10332      *               element.text(dateFilter(new Date(), format));
10333      *             }
10334      *
10335      *             // watch the expression, and update the UI on change.
10336      *             scope.$watch(attrs.myCurrentTime, function(value) {
10337      *               format = value;
10338      *               updateTime();
10339      *             });
10340      *
10341      *             stopTime = $interval(updateTime, 1000);
10342      *
10343      *             // listen on DOM destroy (removal) event, and cancel the next UI update
10344      *             // to prevent updating time after the DOM element was removed.
10345      *             element.on('$destroy', function() {
10346      *               $interval.cancel(stopTime);
10347      *             });
10348      *           }
10349      *         }]);
10350      *   </script>
10351      *
10352      *   <div>
10353      *     <div ng-controller="ExampleController">
10354      *       Date format: <input ng-model="format"> <hr/>
10355      *       Current time is: <span my-current-time="format"></span>
10356      *       <hr/>
10357      *       Blood 1 : <font color='red'>{{blood_1}}</font>
10358      *       Blood 2 : <font color='red'>{{blood_2}}</font>
10359      *       <button type="button" data-ng-click="fight()">Fight</button>
10360      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
10361      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
10362      *     </div>
10363      *   </div>
10364      *
10365      * </file>
10366      * </example>
10367      */
10368    function interval(fn, delay, count, invokeApply) {
10369      var setInterval = $window.setInterval,
10370          clearInterval = $window.clearInterval,
10371          iteration = 0,
10372          skipApply = (isDefined(invokeApply) && !invokeApply),
10373          deferred = (skipApply ? $$q : $q).defer(),
10374          promise = deferred.promise;
10375
10376      count = isDefined(count) ? count : 0;
10377
10378      promise.then(null, null, fn);
10379
10380      promise.$$intervalId = setInterval(function tick() {
10381        deferred.notify(iteration++);
10382
10383        if (count > 0 && iteration >= count) {
10384          deferred.resolve(iteration);
10385          clearInterval(promise.$$intervalId);
10386          delete intervals[promise.$$intervalId];
10387        }
10388
10389        if (!skipApply) $rootScope.$apply();
10390
10391      }, delay);
10392
10393      intervals[promise.$$intervalId] = deferred;
10394
10395      return promise;
10396    }
10397
10398
10399     /**
10400      * @ngdoc method
10401      * @name $interval#cancel
10402      *
10403      * @description
10404      * Cancels a task associated with the `promise`.
10405      *
10406      * @param {promise} promise returned by the `$interval` function.
10407      * @returns {boolean} Returns `true` if the task was successfully canceled.
10408      */
10409    interval.cancel = function(promise) {
10410      if (promise && promise.$$intervalId in intervals) {
10411        intervals[promise.$$intervalId].reject('canceled');
10412        $window.clearInterval(promise.$$intervalId);
10413        delete intervals[promise.$$intervalId];
10414        return true;
10415      }
10416      return false;
10417    };
10418
10419    return interval;
10420  }];
10421}
10422
10423/**
10424 * @ngdoc service
10425 * @name $locale
10426 *
10427 * @description
10428 * $locale service provides localization rules for various Angular components. As of right now the
10429 * only public api is:
10430 *
10431 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
10432 */
10433function $LocaleProvider() {
10434  this.$get = function() {
10435    return {
10436      id: 'en-us',
10437
10438      NUMBER_FORMATS: {
10439        DECIMAL_SEP: '.',
10440        GROUP_SEP: ',',
10441        PATTERNS: [
10442          { // Decimal Pattern
10443            minInt: 1,
10444            minFrac: 0,
10445            maxFrac: 3,
10446            posPre: '',
10447            posSuf: '',
10448            negPre: '-',
10449            negSuf: '',
10450            gSize: 3,
10451            lgSize: 3
10452          },{ //Currency Pattern
10453            minInt: 1,
10454            minFrac: 2,
10455            maxFrac: 2,
10456            posPre: '\u00A4',
10457            posSuf: '',
10458            negPre: '(\u00A4',
10459            negSuf: ')',
10460            gSize: 3,
10461            lgSize: 3
10462          }
10463        ],
10464        CURRENCY_SYM: '$'
10465      },
10466
10467      DATETIME_FORMATS: {
10468        MONTH:
10469            'January,February,March,April,May,June,July,August,September,October,November,December'
10470            .split(','),
10471        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
10472        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
10473        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
10474        AMPMS: ['AM','PM'],
10475        medium: 'MMM d, y h:mm:ss a',
10476        'short': 'M/d/yy h:mm a',
10477        fullDate: 'EEEE, MMMM d, y',
10478        longDate: 'MMMM d, y',
10479        mediumDate: 'MMM d, y',
10480        shortDate: 'M/d/yy',
10481        mediumTime: 'h:mm:ss a',
10482        shortTime: 'h:mm a'
10483      },
10484
10485      pluralCat: function(num) {
10486        if (num === 1) {
10487          return 'one';
10488        }
10489        return 'other';
10490      }
10491    };
10492  };
10493}
10494
10495var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
10496    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
10497var $locationMinErr = minErr('$location');
10498
10499
10500/**
10501 * Encode path using encodeUriSegment, ignoring forward slashes
10502 *
10503 * @param {string} path Path to encode
10504 * @returns {string}
10505 */
10506function encodePath(path) {
10507  var segments = path.split('/'),
10508      i = segments.length;
10509
10510  while (i--) {
10511    segments[i] = encodeUriSegment(segments[i]);
10512  }
10513
10514  return segments.join('/');
10515}
10516
10517function parseAbsoluteUrl(absoluteUrl, locationObj) {
10518  var parsedUrl = urlResolve(absoluteUrl);
10519
10520  locationObj.$$protocol = parsedUrl.protocol;
10521  locationObj.$$host = parsedUrl.hostname;
10522  locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
10523}
10524
10525
10526function parseAppUrl(relativeUrl, locationObj) {
10527  var prefixed = (relativeUrl.charAt(0) !== '/');
10528  if (prefixed) {
10529    relativeUrl = '/' + relativeUrl;
10530  }
10531  var match = urlResolve(relativeUrl);
10532  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
10533      match.pathname.substring(1) : match.pathname);
10534  locationObj.$$search = parseKeyValue(match.search);
10535  locationObj.$$hash = decodeURIComponent(match.hash);
10536
10537  // make sure path starts with '/';
10538  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
10539    locationObj.$$path = '/' + locationObj.$$path;
10540  }
10541}
10542
10543
10544/**
10545 *
10546 * @param {string} begin
10547 * @param {string} whole
10548 * @returns {string} returns text from whole after begin or undefined if it does not begin with
10549 *                   expected string.
10550 */
10551function beginsWith(begin, whole) {
10552  if (whole.indexOf(begin) === 0) {
10553    return whole.substr(begin.length);
10554  }
10555}
10556
10557
10558function stripHash(url) {
10559  var index = url.indexOf('#');
10560  return index == -1 ? url : url.substr(0, index);
10561}
10562
10563function trimEmptyHash(url) {
10564  return url.replace(/(#.+)|#$/, '$1');
10565}
10566
10567
10568function stripFile(url) {
10569  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
10570}
10571
10572/* return the server only (scheme://host:port) */
10573function serverBase(url) {
10574  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
10575}
10576
10577
10578/**
10579 * LocationHtml5Url represents an url
10580 * This object is exposed as $location service when HTML5 mode is enabled and supported
10581 *
10582 * @constructor
10583 * @param {string} appBase application base URL
10584 * @param {string} basePrefix url path prefix
10585 */
10586function LocationHtml5Url(appBase, basePrefix) {
10587  this.$$html5 = true;
10588  basePrefix = basePrefix || '';
10589  var appBaseNoFile = stripFile(appBase);
10590  parseAbsoluteUrl(appBase, this);
10591
10592
10593  /**
10594   * Parse given html5 (regular) url string into properties
10595   * @param {string} url HTML5 url
10596   * @private
10597   */
10598  this.$$parse = function(url) {
10599    var pathUrl = beginsWith(appBaseNoFile, url);
10600    if (!isString(pathUrl)) {
10601      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
10602          appBaseNoFile);
10603    }
10604
10605    parseAppUrl(pathUrl, this);
10606
10607    if (!this.$$path) {
10608      this.$$path = '/';
10609    }
10610
10611    this.$$compose();
10612  };
10613
10614  /**
10615   * Compose url and update `absUrl` property
10616   * @private
10617   */
10618  this.$$compose = function() {
10619    var search = toKeyValue(this.$$search),
10620        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10621
10622    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10623    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
10624  };
10625
10626  this.$$parseLinkUrl = function(url, relHref) {
10627    if (relHref && relHref[0] === '#') {
10628      // special case for links to hash fragments:
10629      // keep the old url and only replace the hash fragment
10630      this.hash(relHref.slice(1));
10631      return true;
10632    }
10633    var appUrl, prevAppUrl;
10634    var rewrittenUrl;
10635
10636    if ((appUrl = beginsWith(appBase, url)) !== undefined) {
10637      prevAppUrl = appUrl;
10638      if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
10639        rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
10640      } else {
10641        rewrittenUrl = appBase + prevAppUrl;
10642      }
10643    } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
10644      rewrittenUrl = appBaseNoFile + appUrl;
10645    } else if (appBaseNoFile == url + '/') {
10646      rewrittenUrl = appBaseNoFile;
10647    }
10648    if (rewrittenUrl) {
10649      this.$$parse(rewrittenUrl);
10650    }
10651    return !!rewrittenUrl;
10652  };
10653}
10654
10655
10656/**
10657 * LocationHashbangUrl represents url
10658 * This object is exposed as $location service when developer doesn't opt into html5 mode.
10659 * It also serves as the base class for html5 mode fallback on legacy browsers.
10660 *
10661 * @constructor
10662 * @param {string} appBase application base URL
10663 * @param {string} hashPrefix hashbang prefix
10664 */
10665function LocationHashbangUrl(appBase, hashPrefix) {
10666  var appBaseNoFile = stripFile(appBase);
10667
10668  parseAbsoluteUrl(appBase, this);
10669
10670
10671  /**
10672   * Parse given hashbang url into properties
10673   * @param {string} url Hashbang url
10674   * @private
10675   */
10676  this.$$parse = function(url) {
10677    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
10678    var withoutHashUrl;
10679
10680    if (withoutBaseUrl.charAt(0) === '#') {
10681
10682      // The rest of the url starts with a hash so we have
10683      // got either a hashbang path or a plain hash fragment
10684      withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
10685      if (isUndefined(withoutHashUrl)) {
10686        // There was no hashbang prefix so we just have a hash fragment
10687        withoutHashUrl = withoutBaseUrl;
10688      }
10689
10690    } else {
10691      // There was no hashbang path nor hash fragment:
10692      // If we are in HTML5 mode we use what is left as the path;
10693      // Otherwise we ignore what is left
10694      withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
10695    }
10696
10697    parseAppUrl(withoutHashUrl, this);
10698
10699    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
10700
10701    this.$$compose();
10702
10703    /*
10704     * In Windows, on an anchor node on documents loaded from
10705     * the filesystem, the browser will return a pathname
10706     * prefixed with the drive name ('/C:/path') when a
10707     * pathname without a drive is set:
10708     *  * a.setAttribute('href', '/foo')
10709     *   * a.pathname === '/C:/foo' //true
10710     *
10711     * Inside of Angular, we're always using pathnames that
10712     * do not include drive names for routing.
10713     */
10714    function removeWindowsDriveName(path, url, base) {
10715      /*
10716      Matches paths for file protocol on windows,
10717      such as /C:/foo/bar, and captures only /foo/bar.
10718      */
10719      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
10720
10721      var firstPathSegmentMatch;
10722
10723      //Get the relative path from the input URL.
10724      if (url.indexOf(base) === 0) {
10725        url = url.replace(base, '');
10726      }
10727
10728      // The input URL intentionally contains a first path segment that ends with a colon.
10729      if (windowsFilePathExp.exec(url)) {
10730        return path;
10731      }
10732
10733      firstPathSegmentMatch = windowsFilePathExp.exec(path);
10734      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
10735    }
10736  };
10737
10738  /**
10739   * Compose hashbang url and update `absUrl` property
10740   * @private
10741   */
10742  this.$$compose = function() {
10743    var search = toKeyValue(this.$$search),
10744        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10745
10746    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10747    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
10748  };
10749
10750  this.$$parseLinkUrl = function(url, relHref) {
10751    if (stripHash(appBase) == stripHash(url)) {
10752      this.$$parse(url);
10753      return true;
10754    }
10755    return false;
10756  };
10757}
10758
10759
10760/**
10761 * LocationHashbangUrl represents url
10762 * This object is exposed as $location service when html5 history api is enabled but the browser
10763 * does not support it.
10764 *
10765 * @constructor
10766 * @param {string} appBase application base URL
10767 * @param {string} hashPrefix hashbang prefix
10768 */
10769function LocationHashbangInHtml5Url(appBase, hashPrefix) {
10770  this.$$html5 = true;
10771  LocationHashbangUrl.apply(this, arguments);
10772
10773  var appBaseNoFile = stripFile(appBase);
10774
10775  this.$$parseLinkUrl = function(url, relHref) {
10776    if (relHref && relHref[0] === '#') {
10777      // special case for links to hash fragments:
10778      // keep the old url and only replace the hash fragment
10779      this.hash(relHref.slice(1));
10780      return true;
10781    }
10782
10783    var rewrittenUrl;
10784    var appUrl;
10785
10786    if (appBase == stripHash(url)) {
10787      rewrittenUrl = url;
10788    } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
10789      rewrittenUrl = appBase + hashPrefix + appUrl;
10790    } else if (appBaseNoFile === url + '/') {
10791      rewrittenUrl = appBaseNoFile;
10792    }
10793    if (rewrittenUrl) {
10794      this.$$parse(rewrittenUrl);
10795    }
10796    return !!rewrittenUrl;
10797  };
10798
10799  this.$$compose = function() {
10800    var search = toKeyValue(this.$$search),
10801        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
10802
10803    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
10804    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
10805    this.$$absUrl = appBase + hashPrefix + this.$$url;
10806  };
10807
10808}
10809
10810
10811var locationPrototype = {
10812
10813  /**
10814   * Are we in html5 mode?
10815   * @private
10816   */
10817  $$html5: false,
10818
10819  /**
10820   * Has any change been replacing?
10821   * @private
10822   */
10823  $$replace: false,
10824
10825  /**
10826   * @ngdoc method
10827   * @name $location#absUrl
10828   *
10829   * @description
10830   * This method is getter only.
10831   *
10832   * Return full url representation with all segments encoded according to rules specified in
10833   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
10834   *
10835   *
10836   * ```js
10837   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10838   * var absUrl = $location.absUrl();
10839   * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
10840   * ```
10841   *
10842   * @return {string} full url
10843   */
10844  absUrl: locationGetter('$$absUrl'),
10845
10846  /**
10847   * @ngdoc method
10848   * @name $location#url
10849   *
10850   * @description
10851   * This method is getter / setter.
10852   *
10853   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
10854   *
10855   * Change path, search and hash, when called with parameter and return `$location`.
10856   *
10857   *
10858   * ```js
10859   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10860   * var url = $location.url();
10861   * // => "/some/path?foo=bar&baz=xoxo"
10862   * ```
10863   *
10864   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
10865   * @return {string} url
10866   */
10867  url: function(url) {
10868    if (isUndefined(url))
10869      return this.$$url;
10870
10871    var match = PATH_MATCH.exec(url);
10872    if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
10873    if (match[2] || match[1] || url === '') this.search(match[3] || '');
10874    this.hash(match[5] || '');
10875
10876    return this;
10877  },
10878
10879  /**
10880   * @ngdoc method
10881   * @name $location#protocol
10882   *
10883   * @description
10884   * This method is getter only.
10885   *
10886   * Return protocol of current url.
10887   *
10888   *
10889   * ```js
10890   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10891   * var protocol = $location.protocol();
10892   * // => "http"
10893   * ```
10894   *
10895   * @return {string} protocol of current url
10896   */
10897  protocol: locationGetter('$$protocol'),
10898
10899  /**
10900   * @ngdoc method
10901   * @name $location#host
10902   *
10903   * @description
10904   * This method is getter only.
10905   *
10906   * Return host of current url.
10907   *
10908   *
10909   * ```js
10910   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10911   * var host = $location.host();
10912   * // => "example.com"
10913   * ```
10914   *
10915   * @return {string} host of current url.
10916   */
10917  host: locationGetter('$$host'),
10918
10919  /**
10920   * @ngdoc method
10921   * @name $location#port
10922   *
10923   * @description
10924   * This method is getter only.
10925   *
10926   * Return port of current url.
10927   *
10928   *
10929   * ```js
10930   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10931   * var port = $location.port();
10932   * // => 80
10933   * ```
10934   *
10935   * @return {Number} port
10936   */
10937  port: locationGetter('$$port'),
10938
10939  /**
10940   * @ngdoc method
10941   * @name $location#path
10942   *
10943   * @description
10944   * This method is getter / setter.
10945   *
10946   * Return path of current url when called without any parameter.
10947   *
10948   * Change path when called with parameter and return `$location`.
10949   *
10950   * Note: Path should always begin with forward slash (/), this method will add the forward slash
10951   * if it is missing.
10952   *
10953   *
10954   * ```js
10955   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10956   * var path = $location.path();
10957   * // => "/some/path"
10958   * ```
10959   *
10960   * @param {(string|number)=} path New path
10961   * @return {string} path
10962   */
10963  path: locationGetterSetter('$$path', function(path) {
10964    path = path !== null ? path.toString() : '';
10965    return path.charAt(0) == '/' ? path : '/' + path;
10966  }),
10967
10968  /**
10969   * @ngdoc method
10970   * @name $location#search
10971   *
10972   * @description
10973   * This method is getter / setter.
10974   *
10975   * Return search part (as object) of current url when called without any parameter.
10976   *
10977   * Change search part when called with parameter and return `$location`.
10978   *
10979   *
10980   * ```js
10981   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10982   * var searchObject = $location.search();
10983   * // => {foo: 'bar', baz: 'xoxo'}
10984   *
10985   * // set foo to 'yipee'
10986   * $location.search('foo', 'yipee');
10987   * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
10988   * ```
10989   *
10990   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
10991   * hash object.
10992   *
10993   * When called with a single argument the method acts as a setter, setting the `search` component
10994   * of `$location` to the specified value.
10995   *
10996   * If the argument is a hash object containing an array of values, these values will be encoded
10997   * as duplicate search parameters in the url.
10998   *
10999   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11000   * will override only a single search property.
11001   *
11002   * If `paramValue` is an array, it will override the property of the `search` component of
11003   * `$location` specified via the first argument.
11004   *
11005   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11006   *
11007   * If `paramValue` is `true`, the property specified via the first argument will be added with no
11008   * value nor trailing equal sign.
11009   *
11010   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11011   * one or more arguments returns `$location` object itself.
11012   */
11013  search: function(search, paramValue) {
11014    switch (arguments.length) {
11015      case 0:
11016        return this.$$search;
11017      case 1:
11018        if (isString(search) || isNumber(search)) {
11019          search = search.toString();
11020          this.$$search = parseKeyValue(search);
11021        } else if (isObject(search)) {
11022          search = copy(search, {});
11023          // remove object undefined or null properties
vendor: 18,208 bytes, lines 11024-11593
11024          forEach(search, function(value, key) {
11025            if (value == null) delete search[key];
11026          });
11027
11028          this.$$search = search;
11029        } else {
11030          throw $locationMinErr('isrcharg',
11031              'The first argument of the `$location#search()` call must be a string or an object.');
11032        }
11033        break;
11034      default:
11035        if (isUndefined(paramValue) || paramValue === null) {
11036          delete this.$$search[search];
11037        } else {
11038          this.$$search[search] = paramValue;
11039        }
11040    }
11041
11042    this.$$compose();
11043    return this;
11044  },
11045
11046  /**
11047   * @ngdoc method
11048   * @name $location#hash
11049   *
11050   * @description
11051   * This method is getter / setter.
11052   *
11053   * Return hash fragment when called without any parameter.
11054   *
11055   * Change hash fragment when called with parameter and return `$location`.
11056   *
11057   *
11058   * ```js
11059   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
11060   * var hash = $location.hash();
11061   * // => "hashValue"
11062   * ```
11063   *
11064   * @param {(string|number)=} hash New hash fragment
11065   * @return {string} hash
11066   */
11067  hash: locationGetterSetter('$$hash', function(hash) {
11068    return hash !== null ? hash.toString() : '';
11069  }),
11070
11071  /**
11072   * @ngdoc method
11073   * @name $location#replace
11074   *
11075   * @description
11076   * If called, all changes to $location during current `$digest` will be replacing current history
11077   * record, instead of adding new one.
11078   */
11079  replace: function() {
11080    this.$$replace = true;
11081    return this;
11082  }
11083};
11084
11085forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
11086  Location.prototype = Object.create(locationPrototype);
11087
11088  /**
11089   * @ngdoc method
11090   * @name $location#state
11091   *
11092   * @description
11093   * This method is getter / setter.
11094   *
11095   * Return the history state object when called without any parameter.
11096   *
11097   * Change the history state object when called with one parameter and return `$location`.
11098   * The state object is later passed to `pushState` or `replaceState`.
11099   *
11100   * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
11101   * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
11102   * older browsers (like IE9 or Android < 4.0), don't use this method.
11103   *
11104   * @param {object=} state State object for pushState or replaceState
11105   * @return {object} state
11106   */
11107  Location.prototype.state = function(state) {
11108    if (!arguments.length)
11109      return this.$$state;
11110
11111    if (Location !== LocationHtml5Url || !this.$$html5) {
11112      throw $locationMinErr('nostate', 'History API state support is available only ' +
11113        'in HTML5 mode and only in browsers supporting HTML5 History API');
11114    }
11115    // The user might modify `stateObject` after invoking `$location.state(stateObject)`
11116    // but we're changing the $$state reference to $browser.state() during the $digest
11117    // so the modification window is narrow.
11118    this.$$state = isUndefined(state) ? null : state;
11119
11120    return this;
11121  };
11122});
11123
11124
11125function locationGetter(property) {
11126  return function() {
11127    return this[property];
11128  };
11129}
11130
11131
11132function locationGetterSetter(property, preprocess) {
11133  return function(value) {
11134    if (isUndefined(value))
11135      return this[property];
11136
11137    this[property] = preprocess(value);
11138    this.$$compose();
11139
11140    return this;
11141  };
11142}
11143
11144
11145/**
11146 * @ngdoc service
11147 * @name $location
11148 *
11149 * @requires $rootElement
11150 *
11151 * @description
11152 * The $location service parses the URL in the browser address bar (based on the
11153 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
11154 * available to your application. Changes to the URL in the address bar are reflected into
11155 * $location service and changes to $location are reflected into the browser address bar.
11156 *
11157 * **The $location service:**
11158 *
11159 * - Exposes the current URL in the browser address bar, so you can
11160 *   - Watch and observe the URL.
11161 *   - Change the URL.
11162 * - Synchronizes the URL with the browser when the user
11163 *   - Changes the address bar.
11164 *   - Clicks the back or forward button (or clicks a History link).
11165 *   - Clicks on a link.
11166 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
11167 *
11168 * For more information see {@link guide/$location Developer Guide: Using $location}
11169 */
11170
11171/**
11172 * @ngdoc provider
11173 * @name $locationProvider
11174 * @description
11175 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
11176 */
11177function $LocationProvider() {
11178  var hashPrefix = '',
11179      html5Mode = {
11180        enabled: false,
11181        requireBase: true,
11182        rewriteLinks: true
11183      };
11184
11185  /**
11186   * @ngdoc method
11187   * @name $locationProvider#hashPrefix
11188   * @description
11189   * @param {string=} prefix Prefix for hash part (containing path and search)
11190   * @returns {*} current value if used as getter or itself (chaining) if used as setter
11191   */
11192  this.hashPrefix = function(prefix) {
11193    if (isDefined(prefix)) {
11194      hashPrefix = prefix;
11195      return this;
11196    } else {
11197      return hashPrefix;
11198    }
11199  };
11200
11201  /**
11202   * @ngdoc method
11203   * @name $locationProvider#html5Mode
11204   * @description
11205   * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
11206   *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
11207   *   properties:
11208   *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
11209   *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
11210   *     support `pushState`.
11211   *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
11212   *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
11213   *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
11214   *     See the {@link guide/$location $location guide for more information}
11215   *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
11216   *     enables/disables url rewriting for relative links.
11217   *
11218   * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
11219   */
11220  this.html5Mode = function(mode) {
11221    if (isBoolean(mode)) {
11222      html5Mode.enabled = mode;
11223      return this;
11224    } else if (isObject(mode)) {
11225
11226      if (isBoolean(mode.enabled)) {
11227        html5Mode.enabled = mode.enabled;
11228      }
11229
11230      if (isBoolean(mode.requireBase)) {
11231        html5Mode.requireBase = mode.requireBase;
11232      }
11233
11234      if (isBoolean(mode.rewriteLinks)) {
11235        html5Mode.rewriteLinks = mode.rewriteLinks;
11236      }
11237
11238      return this;
11239    } else {
11240      return html5Mode;
11241    }
11242  };
11243
11244  /**
11245   * @ngdoc event
11246   * @name $location#$locationChangeStart
11247   * @eventType broadcast on root scope
11248   * @description
11249   * Broadcasted before a URL will change.
11250   *
11251   * This change can be prevented by calling
11252   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
11253   * details about event object. Upon successful change
11254   * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
11255   *
11256   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11257   * the browser supports the HTML5 History API.
11258   *
11259   * @param {Object} angularEvent Synthetic event object.
11260   * @param {string} newUrl New URL
11261   * @param {string=} oldUrl URL that was before it was changed.
11262   * @param {string=} newState New history state object
11263   * @param {string=} oldState History state object that was before it was changed.
11264   */
11265
11266  /**
11267   * @ngdoc event
11268   * @name $location#$locationChangeSuccess
11269   * @eventType broadcast on root scope
11270   * @description
11271   * Broadcasted after a URL was changed.
11272   *
11273   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11274   * the browser supports the HTML5 History API.
11275   *
11276   * @param {Object} angularEvent Synthetic event object.
11277   * @param {string} newUrl New URL
11278   * @param {string=} oldUrl URL that was before it was changed.
11279   * @param {string=} newState New history state object
11280   * @param {string=} oldState History state object that was before it was changed.
11281   */
11282
11283  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
11284      function($rootScope, $browser, $sniffer, $rootElement, $window) {
11285    var $location,
11286        LocationMode,
11287        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
11288        initialUrl = $browser.url(),
11289        appBase;
11290
11291    if (html5Mode.enabled) {
11292      if (!baseHref && html5Mode.requireBase) {
11293        throw $locationMinErr('nobase',
11294          "$location in HTML5 mode requires a <base> tag to be present!");
11295      }
11296      appBase = serverBase(initialUrl) + (baseHref || '/');
11297      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
11298    } else {
11299      appBase = stripHash(initialUrl);
11300      LocationMode = LocationHashbangUrl;
11301    }
11302    $location = new LocationMode(appBase, '#' + hashPrefix);
11303    $location.$$parseLinkUrl(initialUrl, initialUrl);
11304
11305    $location.$$state = $browser.state();
11306
11307    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
11308
11309    function setBrowserUrlWithFallback(url, replace, state) {
11310      var oldUrl = $location.url();
11311      var oldState = $location.$$state;
11312      try {
11313        $browser.url(url, replace, state);
11314
11315        // Make sure $location.state() returns referentially identical (not just deeply equal)
11316        // state object; this makes possible quick checking if the state changed in the digest
11317        // loop. Checking deep equality would be too expensive.
11318        $location.$$state = $browser.state();
11319      } catch (e) {
11320        // Restore old values if pushState fails
11321        $location.url(oldUrl);
11322        $location.$$state = oldState;
11323
11324        throw e;
11325      }
11326    }
11327
11328    $rootElement.on('click', function(event) {
11329      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
11330      // currently we open nice url link and redirect then
11331
11332      if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
11333
11334      var elm = jqLite(event.target);
11335
11336      // traverse the DOM up to find first A tag
11337      while (nodeName_(elm[0]) !== 'a') {
11338        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
11339        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
11340      }
11341
11342      var absHref = elm.prop('href');
11343      // get the actual href attribute - see
11344      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
11345      var relHref = elm.attr('href') || elm.attr('xlink:href');
11346
11347      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
11348        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
11349        // an animation.
11350        absHref = urlResolve(absHref.animVal).href;
11351      }
11352
11353      // Ignore when url is started with javascript: or mailto:
11354      if (IGNORE_URI_REGEXP.test(absHref)) return;
11355
11356      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
11357        if ($location.$$parseLinkUrl(absHref, relHref)) {
11358          // We do a preventDefault for all urls that are part of the angular application,
11359          // in html5mode and also without, so that we are able to abort navigation without
11360          // getting double entries in the location history.
11361          event.preventDefault();
11362          // update location manually
11363          if ($location.absUrl() != $browser.url()) {
11364            $rootScope.$apply();
11365            // hack to work around FF6 bug 684208 when scenario runner clicks on links
11366            $window.angular['ff-684208-preventDefault'] = true;
11367          }
11368        }
11369      }
11370    });
11371
11372
11373    // rewrite hashbang url <> html5 url
11374    if ($location.absUrl() != initialUrl) {
11375      $browser.url($location.absUrl(), true);
11376    }
11377
11378    var initializing = true;
11379
11380    // update $location when $browser url changes
11381    $browser.onUrlChange(function(newUrl, newState) {
11382      $rootScope.$evalAsync(function() {
11383        var oldUrl = $location.absUrl();
11384        var oldState = $location.$$state;
11385        var defaultPrevented;
11386
11387        $location.$$parse(newUrl);
11388        $location.$$state = newState;
11389
11390        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11391            newState, oldState).defaultPrevented;
11392
11393        // if the location was changed by a `$locationChangeStart` handler then stop
11394        // processing this location change
11395        if ($location.absUrl() !== newUrl) return;
11396
11397        if (defaultPrevented) {
11398          $location.$$parse(oldUrl);
11399          $location.$$state = oldState;
11400          setBrowserUrlWithFallback(oldUrl, false, oldState);
11401        } else {
11402          initializing = false;
11403          afterLocationChange(oldUrl, oldState);
11404        }
11405      });
11406      if (!$rootScope.$$phase) $rootScope.$digest();
11407    });
11408
11409    // update browser
11410    $rootScope.$watch(function $locationWatch() {
11411      var oldUrl = trimEmptyHash($browser.url());
11412      var newUrl = trimEmptyHash($location.absUrl());
11413      var oldState = $browser.state();
11414      var currentReplace = $location.$$replace;
11415      var urlOrStateChanged = oldUrl !== newUrl ||
11416        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
11417
11418      if (initializing || urlOrStateChanged) {
11419        initializing = false;
11420
11421        $rootScope.$evalAsync(function() {
11422          var newUrl = $location.absUrl();
11423          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11424              $location.$$state, oldState).defaultPrevented;
11425
11426          // if the location was changed by a `$locationChangeStart` handler then stop
11427          // processing this location change
11428          if ($location.absUrl() !== newUrl) return;
11429
11430          if (defaultPrevented) {
11431            $location.$$parse(oldUrl);
11432            $location.$$state = oldState;
11433          } else {
11434            if (urlOrStateChanged) {
11435              setBrowserUrlWithFallback(newUrl, currentReplace,
11436                                        oldState === $location.$$state ? null : $location.$$state);
11437            }
11438            afterLocationChange(oldUrl, oldState);
11439          }
11440        });
11441      }
11442
11443      $location.$$replace = false;
11444
11445      // we don't need to return anything because $evalAsync will make the digest loop dirty when
11446      // there is a change
11447    });
11448
11449    return $location;
11450
11451    function afterLocationChange(oldUrl, oldState) {
11452      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
11453        $location.$$state, oldState);
11454    }
11455}];
11456}
11457
11458/**
11459 * @ngdoc service
11460 * @name $log
11461 * @requires $window
11462 *
11463 * @description
11464 * Simple service for logging. Default implementation safely writes the message
11465 * into the browser's console (if present).
11466 *
11467 * The main purpose of this service is to simplify debugging and troubleshooting.
11468 *
11469 * The default is to log `debug` messages. You can use
11470 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
11471 *
11472 * @example
11473   <example module="logExample">
11474     <file name="script.js">
11475       angular.module('logExample', [])
11476         .controller('LogController', ['$scope', '$log', function($scope, $log) {
11477           $scope.$log = $log;
11478           $scope.message = 'Hello World!';
11479         }]);
11480     </file>
11481     <file name="index.html">
11482       <div ng-controller="LogController">
11483         <p>Reload this page with open console, enter text and hit the log button...</p>
11484         Message:
11485         <input type="text" ng-model="message"/>
11486         <button ng-click="$log.log(message)">log</button>
11487         <button ng-click="$log.warn(message)">warn</button>
11488         <button ng-click="$log.info(message)">info</button>
11489         <button ng-click="$log.error(message)">error</button>
11490       </div>
11491     </file>
11492   </example>
11493 */
11494
11495/**
11496 * @ngdoc provider
11497 * @name $logProvider
11498 * @description
11499 * Use the `$logProvider` to configure how the application logs messages
11500 */
11501function $LogProvider() {
11502  var debug = true,
11503      self = this;
11504
11505  /**
11506   * @ngdoc method
11507   * @name $logProvider#debugEnabled
11508   * @description
11509   * @param {boolean=} flag enable or disable debug level messages
11510   * @returns {*} current value if used as getter or itself (chaining) if used as setter
11511   */
11512  this.debugEnabled = function(flag) {
11513    if (isDefined(flag)) {
11514      debug = flag;
11515    return this;
11516    } else {
11517      return debug;
11518    }
11519  };
11520
11521  this.$get = ['$window', function($window) {
11522    return {
11523      /**
11524       * @ngdoc method
11525       * @name $log#log
11526       *
11527       * @description
11528       * Write a log message
11529       */
11530      log: consoleLog('log'),
11531
11532      /**
11533       * @ngdoc method
11534       * @name $log#info
11535       *
11536       * @description
11537       * Write an information message
11538       */
11539      info: consoleLog('info'),
11540
11541      /**
11542       * @ngdoc method
11543       * @name $log#warn
11544       *
11545       * @description
11546       * Write a warning message
11547       */
11548      warn: consoleLog('warn'),
11549
11550      /**
11551       * @ngdoc method
11552       * @name $log#error
11553       *
11554       * @description
11555       * Write an error message
11556       */
11557      error: consoleLog('error'),
11558
11559      /**
11560       * @ngdoc method
11561       * @name $log#debug
11562       *
11563       * @description
11564       * Write a debug message
11565       */
11566      debug: (function() {
11567        var fn = consoleLog('debug');
11568
11569        return function() {
11570          if (debug) {
11571            fn.apply(self, arguments);
11572          }
11573        };
11574      }())
11575    };
11576
11577    function formatError(arg) {
11578      if (arg instanceof Error) {
11579        if (arg.stack) {
11580          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
11581              ? 'Error: ' + arg.message + '\n' + arg.stack
11582              : arg.stack;
11583        } else if (arg.sourceURL) {
11584          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
11585        }
11586      }
11587      return arg;
11588    }
11589
11590    function consoleLog(type) {
11591      var console = $window.console || {},
11592          logFn = console[type] || console.log || noop,
11593          hasApply = false;
11594
11595      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
11596      // The reason behind this is that console.log has type "object" in IE8...
11597      try {
11598        hasApply = !!logFn.apply;
11599      } catch (e) {}
11600
11601      if (hasApply) {
11602        return function() {
11603          var args = [];
11604          forEach(arguments, function(arg) {
11605            args.push(formatError(arg));
11606          });
11607          return logFn.apply(console, args);
11608        };
11609      }
11610
11611      // we are IE which either doesn't have window.console => this is noop and we do nothing,
11612      // or we are IE where console.log doesn't have apply so we log at least first 2 args
11613      return function(arg1, arg2) {
11614        logFn(arg1, arg2 == null ? '' : arg2);
11615      };
11616    }
11617  }];
11618}
11619
11620var $parseMinErr = minErr('$parse');
11621
11622// Sandboxing Angular Expressions
11623// ------------------------------
11624// Angular expressions are generally considered safe because these expressions only have direct
11625// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
11626// obtaining a reference to native JS functions such as the Function constructor.
11627//
11628// As an example, consider the following Angular expression:
11629//
11630//   {}.toString.constructor('alert("evil JS code")')
11631//
11632// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
11633// against the expression language, but not to prevent exploits that were enabled by exposing
11634// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
11635// practice and therefore we are not even trying to protect against interaction with an object
11636// explicitly exposed in this way.
11637//
11638// In general, it is not possible to access a Window object from an angular expression unless a
11639// window or some DOM object that has a reference to window is published onto a Scope.
11640// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
11641// native objects.
11642//
11643// See https://docs.angularjs.org/guide/security
11644
11645
11646function ensureSafeMemberName(name, fullExpression) {
11647  if (name === "__defineGetter__" || name === "__defineSetter__"
11648      || name === "__lookupGetter__" || name === "__lookupSetter__"
11649      || name === "__proto__") {
11650    throw $parseMinErr('isecfld',
11651        'Attempting to access a disallowed field in Angular expressions! '
11652        + 'Expression: {0}', fullExpression);
11653  }
11654  return name;
11655}
11656
11657function ensureSafeObject(obj, fullExpression) {
11658  // nifty check if obj is Function that is fast and works across iframes and other contexts
11659  if (obj) {
11660    if (obj.constructor === obj) {
11661      throw $parseMinErr('isecfn',
11662          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11663          fullExpression);
11664    } else if (// isWindow(obj)
11665        obj.window === obj) {
11666      throw $parseMinErr('isecwindow',
11667          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
11668          fullExpression);
11669    } else if (// isElement(obj)
11670        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
11671      throw $parseMinErr('isecdom',
11672          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
11673          fullExpression);
11674    } else if (// block Object so that we can't get hold of dangerous Object.* methods
11675        obj === Object) {
11676      throw $parseMinErr('isecobj',
11677          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
11678          fullExpression);
11679    }
11680  }
11681  return obj;
11682}
11683
11684var CALL = Function.prototype.call;
11685var APPLY = Function.prototype.apply;
11686var BIND = Function.prototype.bind;
11687
11688function ensureSafeFunction(obj, fullExpression) {
11689  if (obj) {
11690    if (obj.constructor === obj) {
11691      throw $parseMinErr('isecfn',
11692        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
11693        fullExpression);
11694    } else if (obj === CALL || obj === APPLY || obj === BIND) {
11695      throw $parseMinErr('isecff',
11696        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
11697        fullExpression);
11698    }
11699  }
11700}
11701
11702//Keyword constants
11703var CONSTANTS = createMap();
11704forEach({
11705  'null': function() { return null; },
11706  'true': function() { return true; },
11707  'false': function() { return false; },
11708  'undefined': function() {}
11709}, function(constantGetter, name) {
11710  constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true;
11711  CONSTANTS[name] = constantGetter;
11712});
11713
11714//Not quite a constant, but can be lex/parsed the same
11715CONSTANTS['this'] = function(self) { return self; };
11716CONSTANTS['this'].sharedGetter = true;
11717
11718
11719//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
11720var OPERATORS = extend(createMap(), {
11721    '+':function(self, locals, a, b) {
11722      a=a(self, locals); b=b(self, locals);
11723      if (isDefined(a)) {
11724        if (isDefined(b)) {
11725          return a + b;
11726        }
11727        return a;
11728      }
11729      return isDefined(b) ? b : undefined;},
11730    '-':function(self, locals, a, b) {
11731          a=a(self, locals); b=b(self, locals);
11732          return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
11733        },
11734    '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
11735    '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
11736    '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
11737    '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
11738    '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
11739    '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
11740    '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
11741    '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
11742    '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
11743    '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
11744    '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
11745    '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
11746    '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
11747    '!':function(self, locals, a) {return !a(self, locals);},
11748
11749    //Tokenized as operators but parsed as assignment/filters
11750    '=':true,
11751    '|':true
11752});
11753var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
11754
11755
vendor: 3,907 bytes, lines 11756-11897
11756/////////////////////////////////////////
11757
11758
11759/**
11760 * @constructor
11761 */
11762var Lexer = function(options) {
11763  this.options = options;
11764};
11765
11766Lexer.prototype = {
11767  constructor: Lexer,
11768
11769  lex: function(text) {
11770    this.text = text;
11771    this.index = 0;
11772    this.tokens = [];
11773
11774    while (this.index < this.text.length) {
11775      var ch = this.text.charAt(this.index);
11776      if (ch === '"' || ch === "'") {
11777        this.readString(ch);
11778      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
11779        this.readNumber();
11780      } else if (this.isIdent(ch)) {
11781        this.readIdent();
11782      } else if (this.is(ch, '(){}[].,;:?')) {
11783        this.tokens.push({index: this.index, text: ch});
11784        this.index++;
11785      } else if (this.isWhitespace(ch)) {
11786        this.index++;
11787      } else {
11788        var ch2 = ch + this.peek();
11789        var ch3 = ch2 + this.peek(2);
11790        var op1 = OPERATORS[ch];
11791        var op2 = OPERATORS[ch2];
11792        var op3 = OPERATORS[ch3];
11793        if (op1 || op2 || op3) {
11794          var token = op3 ? ch3 : (op2 ? ch2 : ch);
11795          this.tokens.push({index: this.index, text: token, operator: true});
11796          this.index += token.length;
11797        } else {
11798          this.throwError('Unexpected next character ', this.index, this.index + 1);
11799        }
11800      }
11801    }
11802    return this.tokens;
11803  },
11804
11805  is: function(ch, chars) {
11806    return chars.indexOf(ch) !== -1;
11807  },
11808
11809  peek: function(i) {
11810    var num = i || 1;
11811    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
11812  },
11813
11814  isNumber: function(ch) {
11815    return ('0' <= ch && ch <= '9') && typeof ch === "string";
11816  },
11817
11818  isWhitespace: function(ch) {
11819    // IE treats non-breaking space as \u00A0
11820    return (ch === ' ' || ch === '\r' || ch === '\t' ||
11821            ch === '\n' || ch === '\v' || ch === '\u00A0');
11822  },
11823
11824  isIdent: function(ch) {
11825    return ('a' <= ch && ch <= 'z' ||
11826            'A' <= ch && ch <= 'Z' ||
11827            '_' === ch || ch === '$');
11828  },
11829
11830  isExpOperator: function(ch) {
11831    return (ch === '-' || ch === '+' || this.isNumber(ch));
11832  },
11833
11834  throwError: function(error, start, end) {
11835    end = end || this.index;
11836    var colStr = (isDefined(start)
11837            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
11838            : ' ' + end);
11839    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
11840        error, colStr, this.text);
11841  },
11842
11843  readNumber: function() {
11844    var number = '';
11845    var start = this.index;
11846    while (this.index < this.text.length) {
11847      var ch = lowercase(this.text.charAt(this.index));
11848      if (ch == '.' || this.isNumber(ch)) {
11849        number += ch;
11850      } else {
11851        var peekCh = this.peek();
11852        if (ch == 'e' && this.isExpOperator(peekCh)) {
11853          number += ch;
11854        } else if (this.isExpOperator(ch) &&
11855            peekCh && this.isNumber(peekCh) &&
11856            number.charAt(number.length - 1) == 'e') {
11857          number += ch;
11858        } else if (this.isExpOperator(ch) &&
11859            (!peekCh || !this.isNumber(peekCh)) &&
11860            number.charAt(number.length - 1) == 'e') {
11861          this.throwError('Invalid exponent');
11862        } else {
11863          break;
11864        }
11865      }
11866      this.index++;
11867    }
11868    this.tokens.push({
11869      index: start,
11870      text: number,
11871      constant: true,
11872      value: Number(number)
11873    });
11874  },
11875
11876  readIdent: function() {
11877    var start = this.index;
11878    while (this.index < this.text.length) {
11879      var ch = this.text.charAt(this.index);
11880      if (!(this.isIdent(ch) || this.isNumber(ch))) {
11881        break;
11882      }
11883      this.index++;
11884    }
11885    this.tokens.push({
11886      index: start,
11887      text: this.text.slice(start, this.index),
11888      identifier: true
11889    });
11890  },
11891
11892  readString: function(quote) {
11893    var start = this.index;
11894    this.index++;
11895    var string = '';
11896    var rawString = quote;
11897    var escape = false;
11898    while (this.index < this.text.length) {
11899      var ch = this.text.charAt(this.index);
11900      rawString += ch;
11901      if (escape) {
11902        if (ch === 'u') {
11903          var hex = this.text.substring(this.index + 1, this.index + 5);
11904          if (!hex.match(/[\da-f]{4}/i))
11905            this.throwError('Invalid unicode escape [\\u' + hex + ']');
11906          this.index += 4;
11907          string += String.fromCharCode(parseInt(hex, 16));
11908        } else {
11909          var rep = ESCAPE[ch];
11910          string = string + (rep || ch);
11911        }
11912        escape = false;
11913      } else if (ch === '\\') {
11914        escape = true;
11915      } else if (ch === quote) {
11916        this.index++;
11917        this.tokens.push({
11918          index: start,
11919          text: rawString,
11920          constant: true,
11921          value: string
11922        });
11923        return;
11924      } else {
11925        string += ch;
11926      }
11927      this.index++;
11928    }
11929    this.throwError('Unterminated quote', start);
11930  }
11931};
11932
11933
11934function isConstant(exp) {
11935  return exp.constant;
11936}
11937
11938/**
11939 * @constructor
11940 */
11941var Parser = function(lexer, $filter, options) {
11942  this.lexer = lexer;
11943  this.$filter = $filter;
11944  this.options = options;
11945};
11946
11947Parser.ZERO = extend(function() {
11948  return 0;
11949}, {
11950  sharedGetter: true,
11951  constant: true
11952});
11953
11954Parser.prototype = {
11955  constructor: Parser,
11956
11957  parse: function(text) {
11958    this.text = text;
11959    this.tokens = this.lexer.lex(text);
11960
11961    var value = this.statements();
11962
11963    if (this.tokens.length !== 0) {
11964      this.throwError('is an unexpected token', this.tokens[0]);
11965    }
11966
11967    value.literal = !!value.literal;
11968    value.constant = !!value.constant;
11969
11970    return value;
11971  },
11972
11973  primary: function() {
11974    var primary;
11975    if (this.expect('(')) {
11976      primary = this.filterChain();
11977      this.consume(')');
11978    } else if (this.expect('[')) {
11979      primary = this.arrayDeclaration();
11980    } else if (this.expect('{')) {
11981      primary = this.object();
11982    } else if (this.peek().identifier && this.peek().text in CONSTANTS) {
11983      primary = CONSTANTS[this.consume().text];
11984    } else if (this.peek().identifier) {
11985      primary = this.identifier();
11986    } else if (this.peek().constant) {
11987      primary = this.constant();
11988    } else {
11989      this.throwError('not a primary expression', this.peek());
11990    }
11991
11992    var next, context;
11993    while ((next = this.expect('(', '[', '.'))) {
11994      if (next.text === '(') {
11995        primary = this.functionCall(primary, context);
11996        context = null;
11997      } else if (next.text === '[') {
11998        context = primary;
11999        primary = this.objectIndex(primary);
12000      } else if (next.text === '.') {
12001        context = primary;
12002        primary = this.fieldAccess(primary);
12003      } else {
12004        this.throwError('IMPOSSIBLE');
12005      }
12006    }
12007    return primary;
12008  },
12009
12010  throwError: function(msg, token) {
12011    throw $parseMinErr('syntax',
12012        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
12013          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
12014  },
12015
12016  peekToken: function() {
12017    if (this.tokens.length === 0)
12018      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12019    return this.tokens[0];
12020  },
12021
12022  peek: function(e1, e2, e3, e4) {
12023    return this.peekAhead(0, e1, e2, e3, e4);
12024  },
12025  peekAhead: function(i, e1, e2, e3, e4) {
12026    if (this.tokens.length > i) {
12027      var token = this.tokens[i];
12028      var t = token.text;
12029      if (t === e1 || t === e2 || t === e3 || t === e4 ||
12030          (!e1 && !e2 && !e3 && !e4)) {
12031        return token;
12032      }
12033    }
12034    return false;
12035  },
12036
12037  expect: function(e1, e2, e3, e4) {
12038    var token = this.peek(e1, e2, e3, e4);
12039    if (token) {
12040      this.tokens.shift();
12041      return token;
12042    }
12043    return false;
12044  },
12045
12046  consume: function(e1) {
12047    if (this.tokens.length === 0) {
12048      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12049    }
12050
12051    var token = this.expect(e1);
12052    if (!token) {
12053      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
12054    }
12055    return token;
12056  },
12057
12058  unaryFn: function(op, right) {
12059    var fn = OPERATORS[op];
12060    return extend(function $parseUnaryFn(self, locals) {
12061      return fn(self, locals, right);
12062    }, {
12063      constant:right.constant,
12064      inputs: [right]
12065    });
12066  },
12067
12068  binaryFn: function(left, op, right, isBranching) {
12069    var fn = OPERATORS[op];
12070    return extend(function $parseBinaryFn(self, locals) {
12071      return fn(self, locals, left, right);
12072    }, {
12073      constant: left.constant && right.constant,
12074      inputs: !isBranching && [left, right]
12075    });
12076  },
12077
12078  identifier: function() {
12079    var id = this.consume().text;
12080
12081    //Continue reading each `.identifier` unless it is a method invocation
12082    while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
12083      id += this.consume().text + this.consume().text;
12084    }
12085
12086    return getterFn(id, this.options, this.text);
12087  },
12088
12089  constant: function() {
12090    var value = this.consume().value;
12091
12092    return extend(function $parseConstant() {
12093      return value;
12094    }, {
12095      constant: true,
12096      literal: true
12097    });
12098  },
12099
12100  statements: function() {
12101    var statements = [];
12102    while (true) {
12103      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12104        statements.push(this.filterChain());
12105      if (!this.expect(';')) {
12106        // optimize for the common case where there is only one statement.
12107        // TODO(size): maybe we should not support multiple statements?
12108        return (statements.length === 1)
12109            ? statements[0]
12110            : function $parseStatements(self, locals) {
12111                var value;
12112                for (var i = 0, ii = statements.length; i < ii; i++) {
12113                  value = statements[i](self, locals);
12114                }
12115                return value;
12116              };
12117      }
12118    }
12119  },
12120
12121  filterChain: function() {
12122    var left = this.expression();
12123    var token;
12124    while ((token = this.expect('|'))) {
12125      left = this.filter(left);
12126    }
12127    return left;
12128  },
12129
12130  filter: function(inputFn) {
12131    var fn = this.$filter(this.consume().text);
12132    var argsFn;
12133    var args;
12134
12135    if (this.peek(':')) {
12136      argsFn = [];
12137      args = []; // we can safely reuse the array
12138      while (this.expect(':')) {
12139        argsFn.push(this.expression());
12140      }
12141    }
12142
12143    var inputs = [inputFn].concat(argsFn || []);
12144
12145    return extend(function $parseFilter(self, locals) {
12146      var input = inputFn(self, locals);
12147      if (args) {
12148        args[0] = input;
12149
12150        var i = argsFn.length;
12151        while (i--) {
12152          args[i + 1] = argsFn[i](self, locals);
12153        }
12154
12155        return fn.apply(undefined, args);
12156      }
12157
12158      return fn(input);
12159    }, {
12160      constant: !fn.$stateful && inputs.every(isConstant),
12161      inputs: !fn.$stateful && inputs
12162    });
12163  },
12164
12165  expression: function() {
12166    return this.assignment();
12167  },
12168
12169  assignment: function() {
12170    var left = this.ternary();
12171    var right;
12172    var token;
12173    if ((token = this.expect('='))) {
12174      if (!left.assign) {
12175        this.throwError('implies assignment but [' +
12176            this.text.substring(0, token.index) + '] can not be assigned to', token);
12177      }
12178      right = this.ternary();
12179      return extend(function $parseAssignment(scope, locals) {
12180        return left.assign(scope, right(scope, locals), locals);
12181      }, {
12182        inputs: [left, right]
12183      });
12184    }
12185    return left;
12186  },
12187
12188  ternary: function() {
12189    var left = this.logicalOR();
12190    var middle;
12191    var token;
12192    if ((token = this.expect('?'))) {
12193      middle = this.assignment();
12194      if (this.consume(':')) {
12195        var right = this.assignment();
12196
12197        return extend(function $parseTernary(self, locals) {
12198          return left(self, locals) ? middle(self, locals) : right(self, locals);
12199        }, {
12200          constant: left.constant && middle.constant && right.constant
12201        });
12202      }
12203    }
12204
12205    return left;
12206  },
12207
12208  logicalOR: function() {
12209    var left = this.logicalAND();
12210    var token;
12211    while ((token = this.expect('||'))) {
12212      left = this.binaryFn(left, token.text, this.logicalAND(), true);
12213    }
12214    return left;
12215  },
12216
12217  logicalAND: function() {
12218    var left = this.equality();
12219    var token;
12220    while ((token = this.expect('&&'))) {
12221      left = this.binaryFn(left, token.text, this.equality(), true);
12222    }
12223    return left;
12224  },
12225
12226  equality: function() {
12227    var left = this.relational();
12228    var token;
12229    while ((token = this.expect('==','!=','===','!=='))) {
12230      left = this.binaryFn(left, token.text, this.relational());
12231    }
12232    return left;
12233  },
12234
12235  relational: function() {
12236    var left = this.additive();
12237    var token;
12238    while ((token = this.expect('<', '>', '<=', '>='))) {
12239      left = this.binaryFn(left, token.text, this.additive());
12240    }
12241    return left;
12242  },
12243
12244  additive: function() {
12245    var left = this.multiplicative();
12246    var token;
12247    while ((token = this.expect('+','-'))) {
12248      left = this.binaryFn(left, token.text, this.multiplicative());
12249    }
12250    return left;
12251  },
12252
12253  multiplicative: function() {
12254    var left = this.unary();
12255    var token;
12256    while ((token = this.expect('*','/','%'))) {
12257      left = this.binaryFn(left, token.text, this.unary());
12258    }
12259    return left;
12260  },
12261
12262  unary: function() {
12263    var token;
12264    if (this.expect('+')) {
12265      return this.primary();
12266    } else if ((token = this.expect('-'))) {
12267      return this.binaryFn(Parser.ZERO, token.text, this.unary());
12268    } else if ((token = this.expect('!'))) {
12269      return this.unaryFn(token.text, this.unary());
12270    } else {
12271      return this.primary();
12272    }
12273  },
12274
12275  fieldAccess: function(object) {
12276    var getter = this.identifier();
12277
12278    return extend(function $parseFieldAccess(scope, locals, self) {
12279      var o = self || object(scope, locals);
12280      return (o == null) ? undefined : getter(o);
12281    }, {
12282      assign: function(scope, value, locals) {
12283        var o = object(scope, locals);
12284        if (!o) object.assign(scope, o = {}, locals);
12285        return getter.assign(o, value);
12286      }
12287    });
12288  },
12289
12290  objectIndex: function(obj) {
12291    var expression = this.text;
12292
12293    var indexFn = this.expression();
12294    this.consume(']');
12295
12296    return extend(function $parseObjectIndex(self, locals) {
12297      var o = obj(self, locals),
12298          i = indexFn(self, locals),
12299          v;
12300
12301      ensureSafeMemberName(i, expression);
12302      if (!o) return undefined;
12303      v = ensureSafeObject(o[i], expression);
12304      return v;
12305    }, {
12306      assign: function(self, value, locals) {
12307        var key = ensureSafeMemberName(indexFn(self, locals), expression);
12308        // prevent overwriting of Function.constructor which would break ensureSafeObject check
12309        var o = ensureSafeObject(obj(self, locals), expression);
12310        if (!o) obj.assign(self, o = {}, locals);
12311        return o[key] = value;
12312      }
12313    });
12314  },
12315
12316  functionCall: function(fnGetter, contextGetter) {
12317    var argsFn = [];
12318    if (this.peekToken().text !== ')') {
12319      do {
12320        argsFn.push(this.expression());
12321      } while (this.expect(','));
12322    }
12323    this.consume(')');
12324
12325    var expressionText = this.text;
12326    // we can safely reuse the array across invocations
12327    var args = argsFn.length ? [] : null;
12328
12329    return function $parseFunctionCall(scope, locals) {
12330      var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
12331      var fn = fnGetter(scope, locals, context) || noop;
12332
12333      if (args) {
12334        var i = argsFn.length;
12335        while (i--) {
12336          args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
12337        }
12338      }
12339
12340      ensureSafeObject(context, expressionText);
12341      ensureSafeFunction(fn, expressionText);
12342
12343      // IE doesn't have apply for some native functions
12344      var v = fn.apply
12345            ? fn.apply(context, args)
12346            : fn(args[0], args[1], args[2], args[3], args[4]);
12347
12348      if (args) {
12349        // Free-up the memory (arguments of the last function call).
12350        args.length = 0;
12351      }
12352
12353      return ensureSafeObject(v, expressionText);
12354      };
12355  },
12356
12357  // This is used with json array declaration
12358  arrayDeclaration: function() {
12359    var elementFns = [];
12360    if (this.peekToken().text !== ']') {
12361      do {
12362        if (this.peek(']')) {
12363          // Support trailing commas per ES5.1.
12364          break;
12365        }
12366        elementFns.push(this.expression());
12367      } while (this.expect(','));
12368    }
12369    this.consume(']');
12370
12371    return extend(function $parseArrayLiteral(self, locals) {
12372      var array = [];
12373      for (var i = 0, ii = elementFns.length; i < ii; i++) {
12374        array.push(elementFns[i](self, locals));
12375      }
12376      return array;
12377    }, {
12378      literal: true,
12379      constant: elementFns.every(isConstant),
12380      inputs: elementFns
12381    });
12382  },
12383
12384  object: function() {
12385    var keys = [], valueFns = [];
12386    if (this.peekToken().text !== '}') {
12387      do {
12388        if (this.peek('}')) {
12389          // Support trailing commas per ES5.1.
12390          break;
12391        }
12392        var token = this.consume();
12393        if (token.constant) {
12394          keys.push(token.value);
12395        } else if (token.identifier) {
12396          keys.push(token.text);
12397        } else {
12398          this.throwError("invalid key", token);
12399        }
12400        this.consume(':');
12401        valueFns.push(this.expression());
12402      } while (this.expect(','));
12403    }
12404    this.consume('}');
12405
12406    return extend(function $parseObjectLiteral(self, locals) {
12407      var object = {};
12408      for (var i = 0, ii = valueFns.length; i < ii; i++) {
12409        object[keys[i]] = valueFns[i](self, locals);
12410      }
12411      return object;
12412    }, {
12413      literal: true,
12414      constant: valueFns.every(isConstant),
12415      inputs: valueFns
12416    });
12417  }
12418};
12419
12420
12421//////////////////////////////////////////////////
12422// Parser helper functions
12423//////////////////////////////////////////////////
12424
12425function setter(obj, locals, path, setValue, fullExp) {
12426  ensureSafeObject(obj, fullExp);
12427  ensureSafeObject(locals, fullExp);
12428
12429  var element = path.split('.'), key;
12430  for (var i = 0; element.length > 1; i++) {
12431    key = ensureSafeMemberName(element.shift(), fullExp);
12432    var propertyObj = (i === 0 && locals && locals[key]) || obj[key];
12433    if (!propertyObj) {
12434      propertyObj = {};
12435      obj[key] = propertyObj;
12436    }
12437    obj = ensureSafeObject(propertyObj, fullExp);
12438  }
12439  key = ensureSafeMemberName(element.shift(), fullExp);
12440  ensureSafeObject(obj[key], fullExp);
12441  obj[key] = setValue;
12442  return setValue;
12443}
12444
12445var getterFnCacheDefault = createMap();
12446var getterFnCacheExpensive = createMap();
12447
12448function isPossiblyDangerousMemberName(name) {
12449  return name == 'constructor';
12450}
12451
12452/**
12453 * Implementation of the "Black Hole" variant from:
12454 * - http://jsperf.com/angularjs-parse-getter/4
12455 * - http://jsperf.com/path-evaluation-simplified/7
12456 */
12457function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) {
12458  ensureSafeMemberName(key0, fullExp);
12459  ensureSafeMemberName(key1, fullExp);
12460  ensureSafeMemberName(key2, fullExp);
12461  ensureSafeMemberName(key3, fullExp);
12462  ensureSafeMemberName(key4, fullExp);
12463  var eso = function(o) {
12464    return ensureSafeObject(o, fullExp);
12465  };
12466  var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity;
12467  var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity;
12468  var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity;
12469  var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity;
12470  var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity;
12471
12472  return function cspSafeGetter(scope, locals) {
12473    var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
12474
12475    if (pathVal == null) return pathVal;
12476    pathVal = eso0(pathVal[key0]);
12477
12478    if (!key1) return pathVal;
12479    if (pathVal == null) return undefined;
12480    pathVal = eso1(pathVal[key1]);
12481
12482    if (!key2) return pathVal;
12483    if (pathVal == null) return undefined;
12484    pathVal = eso2(pathVal[key2]);
12485
12486    if (!key3) return pathVal;
12487    if (pathVal == null) return undefined;
12488    pathVal = eso3(pathVal[key3]);
12489
12490    if (!key4) return pathVal;
12491    if (pathVal == null) return undefined;
12492    pathVal = eso4(pathVal[key4]);
12493
12494    return pathVal;
12495  };
12496}
12497
12498function getterFnWithEnsureSafeObject(fn, fullExpression) {
12499  return function(s, l) {
12500    return fn(s, l, ensureSafeObject, fullExpression);
12501  };
12502}
12503
12504function getterFn(path, options, fullExp) {
12505  var expensiveChecks = options.expensiveChecks;
12506  var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault);
12507  var fn = getterFnCache[path];
12508  if (fn) return fn;
12509
12510
12511  var pathKeys = path.split('.'),
12512      pathKeysLength = pathKeys.length;
12513
12514  // http://jsperf.com/angularjs-parse-getter/6
12515  if (options.csp) {
12516    if (pathKeysLength < 6) {
12517      fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks);
12518    } else {
12519      fn = function cspSafeGetter(scope, locals) {
12520        var i = 0, val;
12521        do {
12522          val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
12523                                pathKeys[i++], fullExp, expensiveChecks)(scope, locals);
12524
12525          locals = undefined; // clear after first iteration
12526          scope = val;
12527        } while (i < pathKeysLength);
12528        return val;
12529      };
12530    }
12531  } else {
12532    var code = '';
12533    if (expensiveChecks) {
12534      code += 's = eso(s, fe);\nl = eso(l, fe);\n';
12535    }
12536    var needsEnsureSafeObject = expensiveChecks;
12537    forEach(pathKeys, function(key, index) {
12538      ensureSafeMemberName(key, fullExp);
12539      var lookupJs = (index
12540                      // we simply dereference 's' on any .dot notation
12541                      ? 's'
12542                      // but if we are first then we check locals first, and if so read it first
12543                      : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key;
12544      if (expensiveChecks || isPossiblyDangerousMemberName(key)) {
12545        lookupJs = 'eso(' + lookupJs + ', fe)';
12546        needsEnsureSafeObject = true;
12547      }
12548      code += 'if(s == null) return undefined;\n' +
12549              's=' + lookupJs + ';\n';
12550    });
12551    code += 'return s;';
12552
12553    /* jshint -W054 */
12554    var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject
12555    /* jshint +W054 */
12556    evaledFnGetter.toString = valueFn(code);
12557    if (needsEnsureSafeObject) {
12558      evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp);
12559    }
12560    fn = evaledFnGetter;
12561  }
12562
12563  fn.sharedGetter = true;
12564  fn.assign = function(self, value, locals) {
12565    return setter(self, locals, path, value, path);
12566  };
12567  getterFnCache[path] = fn;
12568  return fn;
12569}
12570
12571var objectValueOf = Object.prototype.valueOf;
12572
12573function getValueOf(value) {
12574  return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
12575}
12576
12577///////////////////////////////////
12578
12579/**
12580 * @ngdoc service
12581 * @name $parse
12582 * @kind function
12583 *
12584 * @description
12585 *
12586 * Converts Angular {@link guide/expression expression} into a function.
12587 *
12588 * ```js
12589 *   var getter = $parse('user.name');
12590 *   var setter = getter.assign;
12591 *   var context = {user:{name:'angular'}};
12592 *   var locals = {user:{name:'local'}};
12593 *
12594 *   expect(getter(context)).toEqual('angular');
12595 *   setter(context, 'newValue');
12596 *   expect(context.user.name).toEqual('newValue');
12597 *   expect(getter(context, locals)).toEqual('local');
12598 * ```
12599 *
12600 *
12601 * @param {string} expression String expression to compile.
12602 * @returns {function(context, locals)} a function which represents the compiled expression:
12603 *
12604 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
12605 *      are evaluated against (typically a scope object).
12606 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
12607 *      `context`.
12608 *
12609 *    The returned function also has the following properties:
12610 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
12611 *        literal.
12612 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
12613 *        constant literals.
12614 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
12615 *        set to a function to change its value on the given context.
12616 *
12617 */
12618
12619
12620/**
12621 * @ngdoc provider
12622 * @name $parseProvider
12623 *
12624 * @description
12625 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
12626 *  service.
12627 */
12628function $ParseProvider() {
12629  var cacheDefault = createMap();
12630  var cacheExpensive = createMap();
12631
12632
12633
12634  this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
12635    var $parseOptions = {
12636          csp: $sniffer.csp,
12637          expensiveChecks: false
12638        },
12639        $parseOptionsExpensive = {
12640          csp: $sniffer.csp,
12641          expensiveChecks: true
12642        };
12643
12644    function wrapSharedExpression(exp) {
12645      var wrapped = exp;
12646
12647      if (exp.sharedGetter) {
12648        wrapped = function $parseWrapper(self, locals) {
12649          return exp(self, locals);
12650        };
12651        wrapped.literal = exp.literal;
12652        wrapped.constant = exp.constant;
12653        wrapped.assign = exp.assign;
12654      }
12655
12656      return wrapped;
12657    }
12658
12659    return function $parse(exp, interceptorFn, expensiveChecks) {
12660      var parsedExpression, oneTime, cacheKey;
12661
12662      switch (typeof exp) {
12663        case 'string':
12664          cacheKey = exp = exp.trim();
12665
12666          var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
12667          parsedExpression = cache[cacheKey];
12668
12669          if (!parsedExpression) {
12670            if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
12671              oneTime = true;
12672              exp = exp.substring(2);
12673            }
12674
12675            var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
12676            var lexer = new Lexer(parseOptions);
12677            var parser = new Parser(lexer, $filter, parseOptions);
12678            parsedExpression = parser.parse(exp);
12679
12680            if (parsedExpression.constant) {
12681              parsedExpression.$$watchDelegate = constantWatchDelegate;
12682            } else if (oneTime) {
12683              //oneTime is not part of the exp passed to the Parser so we may have to
12684              //wrap the parsedExpression before adding a $$watchDelegate
12685              parsedExpression = wrapSharedExpression(parsedExpression);
12686              parsedExpression.$$watchDelegate = parsedExpression.literal ?
12687                oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
12688            } else if (parsedExpression.inputs) {
12689              parsedExpression.$$watchDelegate = inputsWatchDelegate;
12690            }
12691
12692            cache[cacheKey] = parsedExpression;
12693          }
12694          return addInterceptor(parsedExpression, interceptorFn);
12695
12696        case 'function':
12697          return addInterceptor(exp, interceptorFn);
12698
12699        default:
12700          return addInterceptor(noop, interceptorFn);
12701      }
12702    };
12703
12704    function collectExpressionInputs(inputs, list) {
12705      for (var i = 0, ii = inputs.length; i < ii; i++) {
12706        var input = inputs[i];
12707        if (!input.constant) {
12708          if (input.inputs) {
12709            collectExpressionInputs(input.inputs, list);
12710          } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better?
12711            list.push(input);
12712          }
12713        }
12714      }
12715
12716      return list;
12717    }
12718
12719    function expressionInputDirtyCheck(newValue, oldValueOfValue) {
12720
12721      if (newValue == null || oldValueOfValue == null) { // null/undefined
12722        return newValue === oldValueOfValue;
12723      }
12724
12725      if (typeof newValue === 'object') {
12726
12727        // attempt to convert the value to a primitive type
12728        // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
12729        //             be cheaply dirty-checked
12730        newValue = getValueOf(newValue);
12731
12732        if (typeof newValue === 'object') {
12733          // objects/arrays are not supported - deep-watching them would be too expensive
12734          return false;
12735        }
12736
12737        // fall-through to the primitive equality check
12738      }
12739
12740      //Primitive or NaN
12741      return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
12742    }
12743
12744    function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12745      var inputExpressions = parsedExpression.$$inputs ||
12746                    (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, []));
12747
12748      var lastResult;
12749
12750      if (inputExpressions.length === 1) {
12751        var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails
12752        inputExpressions = inputExpressions[0];
12753        return scope.$watch(function expressionInputWatch(scope) {
12754          var newInputValue = inputExpressions(scope);
12755          if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) {
12756            lastResult = parsedExpression(scope);
12757            oldInputValue = newInputValue && getValueOf(newInputValue);
12758          }
12759          return lastResult;
12760        }, listener, objectEquality);
12761      }
12762
12763      var oldInputValueOfValues = [];
12764      for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12765        oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
12766      }
12767
12768      return scope.$watch(function expressionInputsWatch(scope) {
12769        var changed = false;
12770
12771        for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
12772          var newInputValue = inputExpressions[i](scope);
12773          if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
12774            oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
12775          }
12776        }
12777
12778        if (changed) {
12779          lastResult = parsedExpression(scope);
12780        }
12781
12782        return lastResult;
12783      }, listener, objectEquality);
12784    }
12785
12786    function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12787      var unwatch, lastValue;
12788      return unwatch = scope.$watch(function oneTimeWatch(scope) {
12789        return parsedExpression(scope);
12790      }, function oneTimeListener(value, old, scope) {
12791        lastValue = value;
12792        if (isFunction(listener)) {
12793          listener.apply(this, arguments);
12794        }
12795        if (isDefined(value)) {
12796          scope.$$postDigest(function() {
12797            if (isDefined(lastValue)) {
12798              unwatch();
12799            }
12800          });
12801        }
12802      }, objectEquality);
12803    }
12804
12805    function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12806      var unwatch, lastValue;
12807      return unwatch = scope.$watch(function oneTimeWatch(scope) {
12808        return parsedExpression(scope);
12809      }, function oneTimeListener(value, old, scope) {
12810        lastValue = value;
12811        if (isFunction(listener)) {
12812          listener.call(this, value, old, scope);
12813        }
12814        if (isAllDefined(value)) {
12815          scope.$$postDigest(function() {
12816            if (isAllDefined(lastValue)) unwatch();
12817          });
12818        }
12819      }, objectEquality);
12820
12821      function isAllDefined(value) {
12822        var allDefined = true;
12823        forEach(value, function(val) {
12824          if (!isDefined(val)) allDefined = false;
12825        });
12826        return allDefined;
12827      }
12828    }
12829
12830    function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
12831      var unwatch;
12832      return unwatch = scope.$watch(function constantWatch(scope) {
12833        return parsedExpression(scope);
12834      }, function constantListener(value, old, scope) {
12835        if (isFunction(listener)) {
12836          listener.apply(this, arguments);
12837        }
12838        unwatch();
12839      }, objectEquality);
12840    }
12841
12842    function addInterceptor(parsedExpression, interceptorFn) {
12843      if (!interceptorFn) return parsedExpression;
12844      var watchDelegate = parsedExpression.$$watchDelegate;
12845
12846      var regularWatch =
12847          watchDelegate !== oneTimeLiteralWatchDelegate &&
12848          watchDelegate !== oneTimeWatchDelegate;
12849
12850      var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
12851        var value = parsedExpression(scope, locals);
12852        return interceptorFn(value, scope, locals);
12853      } : function oneTimeInterceptedExpression(scope, locals) {
12854        var value = parsedExpression(scope, locals);
12855        var result = interceptorFn(value, scope, locals);
12856        // we only return the interceptor's result if the
12857        // initial value is defined (for bind-once)
12858        return isDefined(value) ? result : value;
12859      };
12860
12861      // Propagate $$watchDelegates other then inputsWatchDelegate
12862      if (parsedExpression.$$watchDelegate &&
12863          parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
12864        fn.$$watchDelegate = parsedExpression.$$watchDelegate;
12865      } else if (!interceptorFn.$stateful) {
12866        // If there is an interceptor, but no watchDelegate then treat the interceptor like
12867        // we treat filters - it is assumed to be a pure function unless flagged with $stateful
12868        fn.$$watchDelegate = inputsWatchDelegate;
12869        fn.inputs = [parsedExpression];
12870      }
12871
12872      return fn;
12873    }
12874  }];
12875}
12876
12877/**
12878 * @ngdoc service
12879 * @name $q
12880 * @requires $rootScope
12881 *
12882 * @description
12883 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
12884 * when they are done processing.
12885 *
12886 * This is an implementation of promises/deferred objects inspired by
12887 * [Kris Kowal's Q](https://github.com/kriskowal/q).
12888 *
12889 * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
12890 * implementations, and the other which resembles ES6 promises to some degree.
12891 *
12892 * # $q constructor
12893 *
12894 * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
12895 * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
12896 * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
12897 *
12898 * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
12899 * available yet.
12900 *
12901 * It can be used like so:
12902 *
12903 * ```js
12904 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
12905 *   // are available in the current lexical scope (they could have been injected or passed in).
12906 *
12907 *   function asyncGreet(name) {
12908 *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
12909 *     return $q(function(resolve, reject) {
12910 *       setTimeout(function() {
12911 *         if (okToGreet(name)) {
12912 *           resolve('Hello, ' + name + '!');
12913 *         } else {
12914 *           reject('Greeting ' + name + ' is not allowed.');
12915 *         }
12916 *       }, 1000);
12917 *     });
12918 *   }
12919 *
12920 *   var promise = asyncGreet('Robin Hood');
12921 *   promise.then(function(greeting) {
12922 *     alert('Success: ' + greeting);
12923 *   }, function(reason) {
12924 *     alert('Failed: ' + reason);
12925 *   });
12926 * ```
12927 *
12928 * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
12929 *
12930 * However, the more traditional CommonJS-style usage is still available, and documented below.
12931 *
12932 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
12933 * interface for interacting with an object that represents the result of an action that is
12934 * performed asynchronously, and may or may not be finished at any given point in t
12934ime.
12935 *
12936 * From the perspective of dealing with error handling, deferred and promise APIs are to
12937 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
12938 *
12939 * ```js
12940 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
12941 *   // are available in the current lexical scope (they could have been injected or passed in).
12942 *
12943 *   function asyncGreet(name) {
12944 *     var deferred = $q.defer();
12945 *
12946 *     setTimeout(function() {
12947 *       deferred.notify('About to greet ' + name + '.');
12948 *
12949 *       if (okToGreet(name)) {
12950 *         deferred.resolve('Hello, ' + name + '!');
12951 *       } else {
12952 *         deferred.reject('Greeting ' + name + ' is not allowed.');
12953 *       }
12954 *     }, 1000);
12955 *
12956 *     return deferred.promise;
12957 *   }
12958 *
12959 *   var promise = asyncGreet('Robin Hood');
12960 *   promise.then(function(greeting) {
12961 *     alert('Success: ' + greeting);
12962 *   }, function(reason) {
12963 *     alert('Failed: ' + reason);
12964 *   }, function(update) {
12965 *     alert('Got notification: ' + update);
12966 *   });
12967 * ```
12968 *
12969 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
12970 * comes in the way of guarantees that promise and deferred APIs make, see
12971 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
12972 *
12973 * Additionally the promise api allows for composition that is very hard to do with the
12974 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
12975 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
12976 * section on serial or parallel joining of promises.
12977 *
12978 * # The Deferred API
12979 *
12980 * A new instance of deferred is constructed by calling `$q.defer()`.
12981 *
12982 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
12983 * that can be used for signaling the successful or unsuccessful completion, as well as the status
12984 * of the task.
12985 *
12986 * **Methods**
12987 *
12988 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
12989 *   constructed via `$q.reject`, the promise will be rejected instead.
12990 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
12991 *   resolving it with a rejection constructed via `$q.reject`.
12992 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
12993 *   multiple times before the promise is either resolved or rejected.
12994 *
12995 * **Properties**
12996 *
12997 * - promise – `{Promise}` – promise object associated with this deferred.
12998 *
12999 *
13000 * # The Promise API
13001 *
13002 * A new promise instance is created when a deferred instance is created and can be retrieved by
13003 * calling `deferred.promise`.
13004 *
13005 * The purpose of the promise object is to allow for interested parties to get access to the result
13006 * of the deferred task when it completes.
13007 *
13008 * **Methods**
13009 *
13010 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
13011 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
13012 *   as soon as the result is available. The callbacks are called with a single argument: the result
13013 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
13014 *   provide a progress indication, before the promise is resolved or rejected.
13015 *
13016 *   This method *returns a new promise* which is resolved or rejected via the return value of the
13017 *   `successCallback`, `errorCallback`. It also notifies via the return value of the
13018 *   `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback
13019 *   method.
13020 *
13021 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
13022 *
13023 * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
13024 *   but to do so without modifying the final value. This is useful to release resources or do some
13025 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
13026 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
13027 *   more information.
13028 *
13029 * # Chaining promises
13030 *
13031 * Because calling the `then` method of a promise returns a new derived promise, it is easily
13032 * possible to create a chain of promises:
13033 *
13034 * ```js
13035 *   promiseB = promiseA.then(function(result) {
13036 *     return result + 1;
13037 *   });
13038 *
13039 *   // promiseB will be resolved immediately after promiseA is resolved and its value
13040 *   // will be the result of promiseA incremented by 1
13041 * ```
13042 *
13043 * It is possible to create chains of any length and since a promise can be resolved with another
13044 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
13045 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
13046 * $http's response interceptors.
13047 *
13048 *
13049 * # Differences between Kris Kowal's Q and $q
13050 *
13051 *  There are two main differences:
13052 *
13053 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
13054 *   mechanism in angular, which means faster propagation of resolution or rejection into your
13055 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
13056 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
13057 *   all the important functionality needed for common async tasks.
13058 *
13059 *  # Testing
13060 *
13061 *  ```js
13062 *    it('should simulate promise', inject(function($q, $rootScope) {
13063 *      var deferred = $q.defer();
13064 *      var promise = deferred.promise;
13065 *      var resolvedValue;
13066 *
13067 *      promise.then(function(value) { resolvedValue = value; });
13068 *      expect(resolvedValue).toBeUndefined();
13069 *
13070 *      // Simulate resolving of promise
13071 *      deferred.resolve(123);
13072 *      // Note that the 'then' function does not get called synchronously.
13073 *      // This is because we want the promise API to always be async, whether or not
13074 *      // it got called synchronously or asynchronously.
13075 *      expect(resolvedValue).toBeUndefined();
13076 *
13077 *      // Propagate promise resolution to 'then' functions using $apply().
13078 *      $rootScope.$apply();
13079 *      expect(resolvedValue).toEqual(123);
13080 *    }));
13081 *  ```
13082 *
13083 * @param {function(function, function)} resolver Function which is responsible for resolving or
13084 *   rejecting the newly created promise. The first parameter is a function which resolves the
13085 *   promise, the second parameter is a function which rejects the promise.
13086 *
13087 * @returns {Promise} The newly created promise.
13088 */
13089function $QProvider() {
13090
13091  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
13092    return qFactory(function(callback) {
13093      $rootScope.$evalAsync(callback);
13094    }, $exceptionHandler);
13095  }];
13096}
13097
13098function $$QProvider() {
13099  this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
13100    return qFactory(function(callback) {
13101      $browser.defer(callback);
13102    }, $exceptionHandler);
13103  }];
13104}
13105
13106/**
13107 * Constructs a promise manager.
13108 *
13109 * @param {function(function)} nextTick Function for executing functions in the next turn.
13110 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
13111 *     debugging purposes.
13112 * @returns {object} Promise manager.
13113 */
13114function qFactory(nextTick, exceptionHandler) {
13115  var $qMinErr = minErr('$q', TypeError);
13116  function callOnce(self, resolveFn, rejectFn) {
13117    var called = false;
13118    function wrap(fn) {
13119      return function(value) {
13120        if (called) return;
13121        called = true;
13122        fn.call(self, value);
13123      };
13124    }
13125
13126    return [wrap(resolveFn), wrap(rejectFn)];
13127  }
13128
13129  /**
13130   * @ngdoc method
13131   * @name ng.$q#defer
13132   * @kind function
13133   *
13134   * @description
13135   * Creates a `Deferred` object which represents a task which will finish in the future.
13136   *
13137   * @returns {Deferred} Returns a new instance of deferred.
13138   */
13139  var defer = function() {
13140    return new Deferred();
13141  };
13142
13143  function Promise() {
13144    this.$$state = { status: 0 };
13145  }
13146
13147  Promise.prototype = {
13148    then: function(onFulfilled, onRejected, progressBack) {
13149      var result = new Deferred();
13150
13151      this.$$state.pending = this.$$state.pending || [];
13152      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
13153      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
13154
13155      return result.promise;
13156    },
13157
13158    "catch": function(callback) {
13159      return this.then(null, callback);
13160    },
13161
13162    "finally": function(callback, progressBack) {
13163      return this.then(function(value) {
13164        return handleCallback(value, true, callback);
13165      }, function(error) {
13166        return handleCallback(error, false, callback);
13167      }, progressBack);
13168    }
13169  };
13170
13171  //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
13172  function simpleBind(context, fn) {
13173    return function(value) {
13174      fn.call(context, value);
13175    };
13176  }
13177
13178  function processQueue(state) {
13179    var fn, promise, pending;
13180
13181    pending = state.pending;
13182    state.processScheduled = false;
13183    state.pending = undefined;
13184    for (var i = 0, ii = pending.length; i < ii; ++i) {
13185      promise = pending[i][0];
13186      fn = pending[i][state.status];
13187      try {
13188        if (isFunction(fn)) {
13189          promise.resolve(fn(state.value));
13190        } else if (state.status === 1) {
13191          promise.resolve(state.value);
13192        } else {
13193          promise.reject(state.value);
13194        }
13195      } catch (e) {
13196        promise.reject(e);
13197        exceptionHandler(e);
13198      }
13199    }
13200  }
13201
13202  function scheduleProcessQueue(state) {
13203    if (state.processScheduled || !state.pending) return;
13204    state.processScheduled = true;
13205    nextTick(function() { processQueue(state); });
13206  }
13207
13208  function Deferred() {
13209    this.promise = new Promise();
13210    //Necessary to support unbound execution :/
13211    this.resolve = simpleBind(this, this.resolve);
13212    this.reject = simpleBind(this, this.reject);
13213    this.notify = simpleBind(this, this.notify);
13214  }
13215
13216  Deferred.prototype = {
13217    resolve: function(val) {
13218      if (this.promise.$$state.status) return;
13219      if (val === this.promise) {
13220        this.$$reject($qMinErr(
13221          'qcycle',
13222          "Expected promise to be resolved with value other than itself '{0}'",
13223          val));
13224      } else {
13225        this.$$resolve(val);
13226      }
13227
13228    },
13229
13230    $$resolve: function(val) {
13231      var then, fns;
13232
13233      fns = callOnce(this, this.$$resolve, this.$$reject);
13234      try {
13235        if ((isObject(val) || isFunction(val))) then = val && val.then;
13236        if (isFunction(then)) {
13237          this.promise.$$state.status = -1;
13238          then.call(val, fns[0], fns[1], this.notify);
13239        } else {
13240          this.promise.$$state.value = val;
13241          this.promise.$$state.status = 1;
13242          scheduleProcessQueue(this.promise.$$state);
13243        }
13244      } catch (e) {
13245        fns[1](e);
13246        exceptionHandler(e);
13247      }
13248    },
13249
13250    reject: function(reason) {
13251      if (this.promise.$$state.status) return;
13252      this.$$reject(reason);
13253    },
13254
13255    $$reject: function(reason) {
13256      this.promise.$$state.value = reason;
13257      this.promise.$$state.status = 2;
13258      scheduleProcessQueue(this.promise.$$state);
13259    },
13260
13261    notify: function(progress) {
13262      var callbacks = this.promise.$$state.pending;
13263
13264      if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
13265        nextTick(function() {
13266          var callback, result;
13267          for (var i = 0, ii = callbacks.length; i < ii; i++) {
13268            result = callbacks[i][0];
13269            callback = callbacks[i][3];
13270            try {
13271              result.notify(isFunction(callback) ? callback(progress) : progress);
13272            } catch (e) {
13273              exceptionHandler(e);
13274            }
13275          }
13276        });
13277      }
13278    }
13279  };
13280
13281  /**
13282   * @ngdoc method
13283   * @name $q#reject
13284   * @kind function
13285   *
13286   * @description
13287   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
13288   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
13289   * a promise chain, you don't need to worry about it.
13290   *
13291   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
13292   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
13293   * a promise error callback and you want to forward the error to the promise derived from the
13294   * current promise, you have to "rethrow" the error by returning a rejection constructed via
13295   * `reject`.
13296   *
13297   * ```js
13298   *   promiseB = promiseA.then(function(result) {
13299   *     // success: do something and resolve promiseB
13300   *     //          with the old or a new result
13301   *     return result;
13302   *   }, function(reason) {
13303   *     // error: handle the error if possible and
13304   *     //        resolve promiseB with newPromiseOrValue,
13305   *     //        otherwise forward the rejection to promiseB
13306   *     if (canHandle(reason)) {
13307   *      // handle the error and recover
13308   *      return newPromiseOrValue;
13309   *     }
13310   *     return $q.reject(reason);
13311   *   });
13312   * ```
13313   *
13314   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
13315   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
13316   */
13317  var reject = function(reason) {
13318    var result = new Deferred();
13319    result.reject(reason);
13320    return result.promise;
13321  };
13322
13323  var makePromise = function makePromise(value, resolved) {
13324    var result = new Deferred();
13325    if (resolved) {
13326      result.resolve(value);
13327    } else {
13328      result.reject(value);
13329    }
13330    return result.promise;
13331  };
13332
13333  var handleCallback = function handleCallback(value, isResolved, callback) {
13334    var callbackOutput = null;
13335    try {
13336      if (isFunction(callback)) callbackOutput = callback();
13337    } catch (e) {
13338      return makePromise(e, false);
13339    }
13340    if (isPromiseLike(callbackOutput)) {
13341      return callbackOutput.then(function() {
13342        return makePromise(value, isResolved);
13343      }, function(error) {
13344        return makePromise(error, false);
13345      });
13346    } else {
13347      return makePromise(value, isResolved);
13348    }
13349  };
13350
13351  /**
13352   * @ngdoc method
13353   * @name $q#when
13354   * @kind function
13355   *
13356   * @description
13357   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
13358   * This is useful when you are dealing with an object that might or might not be a promise, or if
13359   * the promise comes from a source that can't be trusted.
13360   *
13361   * @param {*} value Value or a promise
13362   * @returns {Promise} Returns a promise of the passed value or promise
13363   */
13364
13365
13366  var when = function(value, callback, errback, progressBack) {
13367    var result = new Deferred();
13368    result.resolve(value);
13369    return result.promise.then(callback, errback, progressBack);
13370  };
13371
13372  /**
13373   * @ngdoc method
13374   * @name $q#all
13375   * @kind function
13376   *
13377   * @description
13378   * Combines multiple promises into a single promise that is resolved when all of the input
13379   * promises are resolved.
13380   *
13381   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
13382   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
13383   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
13384   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
13385   *   with the same rejection value.
13386   */
13387
13388  function all(promises) {
13389    var deferred = new Deferred(),
13390        counter = 0,
13391        results = isArray(promises) ? [] : {};
13392
13393    forEach(promises, function(promise, key) {
13394      counter++;
13395      when(promise).then(function(value) {
13396        if (results.hasOwnProperty(key)) return;
13397        results[key] = value;
13398        if (!(--counter)) deferred.resolve(results);
13399      }, function(reason) {
13400        if (results.hasOwnProperty(key)) return;
13401        deferred.reject(reason);
13402      });
13403    });
13404
13405    if (counter === 0) {
13406      deferred.resolve(results);
13407    }
13408
13409    return deferred.promise;
13410  }
13411
13412  var $Q = function Q(resolver) {
13413    if (!isFunction(resolver)) {
13414      throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
13415    }
13416
13417    if (!(this instanceof Q)) {
13418      // More useful when $Q is the Promise itself.
13419      return new Q(resolver);
13420    }
13421
13422    var deferred = new Deferred();
13423
13424    function resolveFn(value) {
13425      deferred.resolve(value);
13426    }
13427
13428    function rejectFn(reason) {
13429      deferred.reject(reason);
13430    }
13431
13432    resolver(resolveFn, rejectFn);
13433
13434    return deferred.promise;
13435  };
13436
13437  $Q.defer = defer;
13438  $Q.reject = reject;
13439  $Q.when = when;
13440  $Q.all = all;
13441
13442  return $Q;
13443}
13444
13445function $$RAFProvider() { //rAF
13446  this.$get = ['$window', '$timeout', function($window, $timeout) {
13447    var requestAnimationFrame = $window.requestAnimationFrame ||
13448                                $window.webkitRequestAnimationFrame;
13449
13450    var cancelAnimationFrame = $window.cancelAnimationFrame ||
13451                               $window.webkitCancelAnimationFrame ||
13452                               $window.webkitCancelRequestAnimationFrame;
13453
13454    var rafSupported = !!requestAnimationFrame;
13455    var raf = rafSupported
13456      ? function(fn) {
13457          var id = requestAnimationFrame(fn);
13458          return function() {
13459            cancelAnimationFrame(id);
13460          };
13461        }
13462      : function(fn) {
13463          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
13464          return function() {
13465            $timeout.cancel(timer);
13466          };
13467        };
13468
13469    raf.supported = rafSupported;
13470
13471    return raf;
13472  }];
13473}
13474
13475/**
13476 * DESIGN NOTES
13477 *
13478 * The design decisions behind the scope are heavily favored for speed and memory consumption.
13479 *
13480 * The typical use of scope is to watch the expressions, which most of the time return the same
13481 * value as last time so we optimize the operation.
13482 *
13483 * Closures construction is expensive in terms of speed as well as memory:
13484 *   - No closures, instead use prototypical inheritance for API
13485 *   - Internal state needs to be stored on scope directly, which means that private state is
13486 *     exposed as $$____ properties
13487 *
13488 * Loop operations are optimized by using while(count--) { ... }
13489 *   - this means that in order to keep the same order of execution as addition we have to add
13490 *     items to the array at the beginning (unshift) instead of at the end (push)
13491 *
13492 * Child scopes are created and removed often
13493 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
13494 *
13495 * There are few watches then a lot of observers. This is why you don't want the observer to be
13496 * implemented in the same way as watch. Watch requires return of initialization function which
13497 * are expensive to construct.
13498 */
13499
13500
13501/**
13502 * @ngdoc provider
13503 * @name $rootScopeProvider
13504 * @description
13505 *
13506 * Provider for the $rootScope service.
13507 */
13508
13509/**
13510 * @ngdoc method
13511 * @name $rootScopeProvider#digestTtl
13512 * @description
13513 *
13514 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
13515 * assuming that the model is unstable.
13516 *
13517 * The current default is 10 iterations.
13518 *
13519 * In complex applications it's possible that the dependencies between `$watch`s will result in
13520 * several digest iterations. However if an application needs more than the default 10 digest
13521 * iterations for its model to stabilize then you should investigate what is causing the model to
13522 * continuously change during the digest.
13523 *
13524 * Increasing the TTL could have performance implications, so you should not change it without
13525 * proper justification.
13526 *
13527 * @param {number} limit The number of digest iterations.
13528 */
13529
13530
13531/**
13532 * @ngdoc service
13533 * @name $rootScope
13534 * @description
13535 *
13536 * Every application has a single root {@link ng.$rootScope.Scope scope}.
13537 * All other scopes are descendant scopes of the root scope. Scopes provide separation
13538 * between the model and the view, via a mechanism for watching the model for changes.
13539 * They also provide an event emission/broadcast and subscription facility. See the
13540 * {@link guide/scope developer guide on scopes}.
13541 */
13542function $RootScopeProvider() {
13543  var TTL = 10;
13544  var $rootScopeMinErr = minErr('$rootScope');
13545  var lastDirtyWatch = null;
13546  var applyAsyncId = null;
13547
13548  this.digestTtl = function(value) {
13549    if (arguments.length) {
13550      TTL = value;
13551    }
13552    return TTL;
13553  };
13554
13555  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
13556      function($injector, $exceptionHandler, $parse, $browser) {
13557
13558    /**
13559     * @ngdoc type
13560     * @name $rootScope.Scope
13561     *
13562     * @description
13563     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
13564     * {@link auto.$injector $injector}. Child scopes are created using the
13565     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
13566     * compiled HTML template is executed.)
13567     *
13568     * Here is a simple scope snippet to show how you can interact with the scope.
13569     * ```html
13570     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
13571     * ```
13572     *
13573     * # Inheritance
13574     * A scope can inherit from a parent scope, as in this example:
13575     * ```js
13576         var parent = $rootScope;
13577         var child = parent.$new();
13578
13579         parent.salutation = "Hello";
13580         expect(child.salutation).toEqual('Hello');
13581
13582         child.salutation = "Welcome";
13583         expect(child.salutation).toEqual('Welcome');
13584         expect(parent.salutation).toEqual('Hello');
13585     * ```
13586     *
13587     * When interacting with `Scope` in tests, additional helper methods are available on the
13588     * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
13589     * details.
13590     *
13591     *
13592     * @param {Object.<string, function()>=} providers Map of service factory which need to be
13593     *                                       provided for the current scope. Defaults to {@link ng}.
13594     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
13595     *                              append/override services provided by `providers`. This is handy
13596     *                              when unit-testing and having the need to override a default
13597     *                              service.
13598     * @returns {Object} Newly created scope.
13599     *
13600     */
13601    function Scope() {
13602      this.$id = nextUid();
13603      this.$$phase = this.$parent = this.$$watchers =
13604                     this.$$nextSibling = this.$$prevSibling =
13605                     this.$$childHead = this.$$childTail = null;
13606      this.$root = this;
13607      this.$$destroyed = false;
13608      this.$$listeners = {};
13609      this.$$listenerCount = {};
13610      this.$$isolateBindings = null;
13611    }
13612
13613    /**
13614     * @ngdoc property
13615     * @name $rootScope.Scope#$id
13616     *
13617     * @description
13618     * Unique scope ID (monotonically increasing) useful for debugging.
13619     */
13620
13621     /**
13622      * @ngdoc property
13623      * @name $rootScope.Scope#$parent
13624      *
13625      * @description
13626      * Reference to the parent scope.
13627      */
13628
13629      /**
13630       * @ngdoc property
13631       * @name $rootScope.Scope#$root
13632       *
13633       * @description
13634       * Reference to the root scope.
13635       */
13636
13637    Scope.prototype = {
13638      constructor: Scope,
13639      /**
13640       * @ngdoc method
13641       * @name $rootScope.Scope#$new
13642       * @kind function
13643       *
13644       * @description
13645       * Creates a new child {@link ng.$rootScope.Scope scope}.
13646       *
13647       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
13648       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
13649       *
13650       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
13651       * desired for the scope and its child scopes to be permanently detached from the parent and
13652       * thus stop participating in model change detection and listener notification by invoking.
13653       *
13654       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
13655       *         parent scope. The scope is isolated, as it can not see parent scope properties.
13656       *         When creating widgets, it is useful for the widget to not accidentally read parent
13657       *         state.
13658       *
13659       * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
13660       *                              of the newly created scope. Defaults to `this` scope if not provided.
13661       *                              This is used when creating a transclude scope to correctly place it
13662       *                              in the scope hierarchy while maintaining the correct prototypical
13663       *                              inheritance.
13664       *
13665       * @returns {Object} The newly created child scope.
13666       *
13667       */
13668      $new: function(isolate, parent) {
13669        var child;
13670
13671        parent = parent || this;
13672
13673        if (isolate) {
13674          child = new Scope();
13675          child.$root = this.$root;
13676        } else {
13677          // Only create a child scope class if somebody asks for one,
13678          // but cache it to allow the VM to optimize lookups.
13679          if (!this.$$ChildScope) {
13680            this.$$ChildScope = function ChildScope() {
13681              this.$$watchers = this.$$nextSibling =
13682                  this.$$childHead = this.$$childTail = null;
13683              this.$$listeners = {};
13684              this.$$listenerCount = {};
13685              this.$id = nextUid();
13686              this.$$ChildScope = null;
13687            };
13688            this.$$ChildScope.prototype = this;
13689          }
13690          child = new this.$$ChildScope();
13691        }
13692        child.$parent = parent;
13693        child.$$prevSibling = parent.$$childTail;
13694        if (parent.$$childHead) {
13695          parent.$$childTail.$$nextSibling = child;
13696          parent.$$childTail = child;
13697        } else {
13698          parent.$$childHead = parent.$$childTail = child;
13699        }
13700
13701        // When the new scope is not isolated or we inherit from `this`, and
13702        // the parent scope is destroyed, the property `$$destroyed` is inherited
13703        // prototypically. In all other cases, this property needs to be set
13704        // when the parent scope is destroyed.
13705        // The listener needs to be added after the parent is set
13706        if (isolate || parent != this) child.$on('$destroy', destroyChild);
13707
13708        return child;
13709
13710        function destroyChild() {
13711          child.$$destroyed = true;
13712        }
13713      },
13714
13715      /**
13716       * @ngdoc method
13717       * @name $rootScope.Scope#$watch
13718       * @kind function
13719       *
13720       * @description
13721       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
13722       *
13723       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
13724       *   $digest()} and should return the value that will be watched. (Since
13725       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
13726       *   `watchExpression` can execute multiple times per
13727       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
13728       * - The `listener` is called only when the value from the current `watchExpression` and the
13729       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
13730       *   see below). Inequality is determined according to reference inequality,
13731       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
13732       *    via the `!==` Javascript operator, unless `objectEquality == true`
13733       *   (see next point)
13734       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
13735       *   according to the {@link angular.equals} function. To save the value of the object for
13736       *   later comparison, the {@link angular.copy} function is used. This therefore means that
13737       *   watching complex objects will have adverse memory and performance implications.
13738       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
13739       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
13740       *   iteration limit is 10 to prevent an infinite loop deadlock.
13741       *
13742       *
13743       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
13744       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
13745       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
13746       * change is detected, be prepared for multiple calls to your listener.)
13747       *
13748       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
13749       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
13750       * watcher. In rare cases, this is undesirable because the listener is called when the result
13751       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
13752       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
13753       * listener was called due to initialization.
13754       *
13755       *
13756       *
13757       * # Example
13758       * ```js
13759           // let's assume that scope was dependency injected as the $rootScope
13760           var scope = $rootScope;
13761           scope.name = 'misko';
13762           scope.counter = 0;
13763
13764           expect(scope.counter).toEqual(0);
13765           scope.$watch('name', function(newValue, oldValue) {
13766             scope.counter = scope.counter + 1;
13767           });
13768           expect(scope.counter).toEqual(0);
13769
13770           scope.$digest();
13771           // the listener is always called during the first $digest loop after it was registered
13772           expect(scope.counter).toEqual(1);
13773
13774           scope.$digest();
13775           // but now it will not be called unless the value changes
13776           expect(scope.counter).toEqual(1);
13777
13778           scope.name = 'adam';
13779           scope.$digest();
13780           expect(scope.counter).toEqual(2);
13781
13782
13783
13784           // Using a function as a watchExpression
13785           var food;
13786           scope.foodCounter = 0;
13787           expect(scope.foodCounter).toEqual(0);
13788           scope.$watch(
13789             // This function returns the value being watched. It is called for each turn of the $digest loop
13790             function() { return food; },
13791             // This is the change listener, called when the value returned from the above function changes
13792             function(newValue, oldValue) {
13793               if ( newValue !== oldValue ) {
13794                 // Only increment the counter if the value changed
13795                 scope.foodCounter = scope.foodCounter + 1;
13796               }
13797             }
13798           );
13799           // No digest has been run so the counter will be zero
13800           expect(scope.foodCounter).toEqual(0);
13801
13802           // Run the digest but since food has not changed count will still be zero
13803           scope.$digest();
13804           expect(scope.foodCounter).toEqual(0);
13805
13806           // Update food and run digest.  Now the counter will increment
13807           food = 'cheeseburger';
13808           scope.$digest();
13809           expect(scope.foodCounter).toEqual(1);
13810
13811       * ```
13812       *
13813       *
13814       *
13815       * @param {(function()|string)} watchExpression Expression that is evaluated on each
13816       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
13817       *    a call to the `listener`.
13818       *
13819       *    - `string`: Evaluated as {@link guide/expression expression}
13820       *    - `function(scope)`: called with current `scope` as a parameter.
13821       * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
13822       *    of `watchExpression` changes.
13823       *
13824       *    - `newVal` contains the current value of the `watchExpression`
13825       *    - `oldVal` contains the previous value of the `watchExpression`
13826       *    - `scope` refers to the current scope
13827       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
13828       *     comparing for reference equality.
13829       * @returns {function()} Returns a deregistration function for this listener.
13830       */
13831      $watch: function(watchExp, listener, objectEquality) {
13832        var get = $parse(watchExp);
13833
13834        if (get.$$watchDelegate) {
13835          return get.$$watchDelegate(this, listener, objectEquality, get);
13836        }
13837        var scope = this,
13838            array = scope.$$watchers,
13839            watcher = {
13840              fn: listener,
13841              last: initWatchVal,
13842              get: get,
13843              exp: watchExp,
13844              eq: !!objectEquality
13845            };
13846
13847        lastDirtyWatch = null;
13848
13849        if (!isFunction(listener)) {
13850          watcher.fn = noop;
13851        }
13852
13853        if (!array) {
13854          array = scope.$$watchers = [];
13855        }
13856        // we use unshift since we use a while loop in $digest for speed.
13857        // the while loop reads in reverse order.
13858        array.unshift(watcher);
13859
13860        return function deregisterWatch() {
13861          arrayRemove(array, watcher);
13862          lastDirtyWatch = null;
13863        };
13864      },
13865
13866      /**
13867       * @ngdoc method
13868       * @name $rootScope.Scope#$watchGroup
13869       * @kind function
13870       *
13871       * @description
13872       * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
13873       * If any one expression in the collection changes the `listener` is executed.
13874       *
13875       * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
13876       *   call to $digest() to see if any items changes.
13877       * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
13878       *
13879       * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
13880       * watched using {@link ng.$rootScope.Scope#$watch $watch()}
13881       *
13882       * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
13883       *    expression in `watchExpressions` changes
13884       *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
13885       *    those of `watchExpression`
13886       *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
13887       *    those of `watchExpression`
13888       *    The `scope` refers to the current scope.
13889       * @returns {function()} Returns a de-registration function for all listeners.
13890       */
13891      $watchGroup: function(watchExpressions, listener) {
13892        var oldValues = new Array(watchExpressions.length);
13893        var newValues = new Array(watchExpressions.length);
13894        var deregisterFns = [];
13895        var self = this;
13896        var changeReactionScheduled = false;
vendor: 10,180 bytes, lines 13897-14159
13897        var firstRun = true;
13898
13899        if (!watchExpressions.length) {
13900          // No expressions means we call the listener ASAP
13901          var shouldCall = true;
13902          self.$evalAsync(function() {
13903            if (shouldCall) listener(newValues, newValues, self);
13904          });
13905          return function deregisterWatchGroup() {
13906            shouldCall = false;
13907          };
13908        }
13909
13910        if (watchExpressions.length === 1) {
13911          // Special case size of one
13912          return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
13913            newValues[0] = value;
13914            oldValues[0] = oldValue;
13915            listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
13916          });
13917        }
13918
13919        forEach(watchExpressions, function(expr, i) {
13920          var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
13921            newValues[i] = value;
13922            oldValues[i] = oldValue;
13923            if (!changeReactionScheduled) {
13924              changeReactionScheduled = true;
13925              self.$evalAsync(watchGroupAction);
13926            }
13927          });
13928          deregisterFns.push(unwatchFn);
13929        });
13930
13931        function watchGroupAction() {
13932          changeReactionScheduled = false;
13933
13934          if (firstRun) {
13935            firstRun = false;
13936            listener(newValues, newValues, self);
13937          } else {
13938            listener(newValues, oldValues, self);
13939          }
13940        }
13941
13942        return function deregisterWatchGroup() {
13943          while (deregisterFns.length) {
13944            deregisterFns.shift()();
13945          }
13946        };
13947      },
13948
13949
13950      /**
13951       * @ngdoc method
13952       * @name $rootScope.Scope#$watchCollection
13953       * @kind function
13954       *
13955       * @description
13956       * Shallow watches the properties of an object and fires whenever any of the properties change
13957       * (for arrays, this implies watching the array items; for object maps, this implies watching
13958       * the properties). If a change is detected, the `listener` callback is fired.
13959       *
13960       * - The `obj` collection is observed via standard $watch operation and is examined on every
13961       *   call to $digest() to see if any items have been added, removed, or moved.
13962       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
13963       *   adding, removing, and moving items belonging to an object or array.
13964       *
13965       *
13966       * # Example
13967       * ```js
13968          $scope.names = ['igor', 'matias', 'misko', 'james'];
13969          $scope.dataCount = 4;
13970
13971          $scope.$watchCollection('names', function(newNames, oldNames) {
13972            $scope.dataCount = newNames.length;
13973          });
13974
13975          expect($scope.dataCount).toEqual(4);
13976          $scope.$digest();
13977
13978          //still at 4 ... no changes
13979          expect($scope.dataCount).toEqual(4);
13980
13981          $scope.names.pop();
13982          $scope.$digest();
13983
13984          //now there's been a change
13985          expect($scope.dataCount).toEqual(3);
13986       * ```
13987       *
13988       *
13989       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
13990       *    expression value should evaluate to an object or an array which is observed on each
13991       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
13992       *    collection will trigger a call to the `listener`.
13993       *
13994       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
13995       *    when a change is detected.
13996       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
13997       *    - The `oldCollection` object is a copy of the former collection data.
13998       *      Due to performance considerations, the`oldCollection` value is computed only if the
13999       *      `listener` function declares two or more arguments.
14000       *    - The `scope` argument refers to the current scope.
14001       *
14002       * @returns {function()} Returns a de-registration function for this listener. When the
14003       *    de-registration function is executed, the internal watch operation is terminated.
14004       */
14005      $watchCollection: function(obj, listener) {
14006        $watchCollectionInterceptor.$stateful = true;
14007
14008        var self = this;
14009        // the current value, updated on each dirty-check run
14010        var newValue;
14011        // a shallow copy of the newValue from the last dirty-check run,
14012        // updated to match newValue during dirty-check run
14013        var oldValue;
14014        // a shallow copy of the newValue from when the last change happened
14015        var veryOldValue;
14016        // only track veryOldValue if the listener is asking for it
14017        var trackVeryOldValue = (listener.length > 1);
14018        var changeDetected = 0;
14019        var changeDetector = $parse(obj, $watchCollectionInterceptor);
14020        var internalArray = [];
14021        var internalObject = {};
14022        var initRun = true;
14023        var oldLength = 0;
14024
14025        function $watchCollectionInterceptor(_value) {
14026          newValue = _value;
14027          var newLength, key, bothNaN, newItem, oldItem;
14028
14029          // If the new value is undefined, then return undefined as the watch may be a one-time watch
14030          if (isUndefined(newValue)) return;
14031
14032          if (!isObject(newValue)) { // if primitive
14033            if (oldValue !== newValue) {
14034              oldValue = newValue;
14035              changeDetected++;
14036            }
14037          } else if (isArrayLike(newValue)) {
14038            if (oldValue !== internalArray) {
14039              // we are transitioning from something which was not an array into array.
14040              oldValue = internalArray;
14041              oldLength = oldValue.length = 0;
14042              changeDetected++;
14043            }
14044
14045            newLength = newValue.length;
14046
14047            if (oldLength !== newLength) {
14048              // if lengths do not match we need to trigger change notification
14049              changeDetected++;
14050              oldValue.length = oldLength = newLength;
14051            }
14052            // copy the items to oldValue and look for changes.
14053            for (var i = 0; i < newLength; i++) {
14054              oldItem = oldValue[i];
14055              newItem = newValue[i];
14056
14057              bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14058              if (!bothNaN && (oldItem !== newItem)) {
14059                changeDetected++;
14060                oldValue[i] = newItem;
14061              }
14062            }
14063          } else {
14064            if (oldValue !== internalObject) {
14065              // we are transitioning from something which was not an object into object.
14066              oldValue = internalObject = {};
14067              oldLength = 0;
14068              changeDetected++;
14069            }
14070            // copy the items to oldValue and look for changes.
14071            newLength = 0;
14072            for (key in newValue) {
14073              if (newValue.hasOwnProperty(key)) {
14074                newLength++;
14075                newItem = newValue[key];
14076                oldItem = oldValue[key];
14077
14078                if (key in oldValue) {
14079                  bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
14080                  if (!bothNaN && (oldItem !== newItem)) {
14081                    changeDetected++;
14082                    oldValue[key] = newItem;
14083                  }
14084                } else {
14085                  oldLength++;
14086                  oldValue[key] = newItem;
14087                  changeDetected++;
14088                }
14089              }
14090            }
14091            if (oldLength > newLength) {
14092              // we used to have more keys, need to find them and destroy them.
14093              changeDetected++;
14094              for (key in oldValue) {
14095                if (!newValue.hasOwnProperty(key)) {
14096                  oldLength--;
14097                  delete oldValue[key];
14098                }
14099              }
14100            }
14101          }
14102          return changeDetected;
14103        }
14104
14105        function $watchCollectionAction() {
14106          if (initRun) {
14107            initRun = false;
14108            listener(newValue, newValue, self);
14109          } else {
14110            listener(newValue, veryOldValue, self);
14111          }
14112
14113          // make a copy for the next time a collection is changed
14114          if (trackVeryOldValue) {
14115            if (!isObject(newValue)) {
14116              //primitive
14117              veryOldValue = newValue;
14118            } else if (isArrayLike(newValue)) {
14119              veryOldValue = new Array(newValue.length);
14120              for (var i = 0; i < newValue.length; i++) {
14121                veryOldValue[i] = newValue[i];
14122              }
14123            } else { // if object
14124              veryOldValue = {};
14125              for (var key in newValue) {
14126                if (hasOwnProperty.call(newValue, key)) {
14127                  veryOldValue[key] = newValue[key];
14128                }
14129              }
14130            }
14131          }
14132        }
14133
14134        return this.$watch(changeDetector, $watchCollectionAction);
14135      },
14136
14137      /**
14138       * @ngdoc method
14139       * @name $rootScope.Scope#$digest
14140       * @kind function
14141       *
14142       * @description
14143       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
14144       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
14145       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
14146       * until no more listeners are firing. This means that it is possible to get into an infinite
14147       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
14148       * iterations exceeds 10.
14149       *
14150       * Usually, you don't call `$digest()` directly in
14151       * {@link ng.directive:ngController controllers} or in
14152       * {@link ng.$compileProvider#directive directives}.
14153       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
14154       * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
14155       *
14156       * If you want to be notified whenever `$digest()` is called,
14157       * you can register a `watchExpression` function with
14158       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
14159       *
14160       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
14161       *
14162       * # Example
14163       * ```js
14164           var scope = ...;
14165           scope.name = 'misko';
14166           scope.counter = 0;
14167
14168           expect(scope.counter).toEqual(0);
14169           scope.$watch('name', function(newValue, oldValue) {
14170             scope.counter = scope.counter + 1;
14171           });
14172           expect(scope.counter).toEqual(0);
14173
14174           scope.$digest();
14175           // the listener is always called during the first $digest loop after it was registered
14176           expect(scope.counter).toEqual(1);
14177
14178           scope.$digest();
14179           // but now it will not be called unless the value changes
14180           expect(scope.counter).toEqual(1);
14181
14182           scope.name = 'adam';
14183           scope.$digest();
14184           expect(scope.counter).toEqual(2);
14185       * ```
14186       *
14187       */
14188      $digest: function() {
14189        var watch, value, last,
14190            watchers,
14191            length,
14192            dirty, ttl = TTL,
14193            next, current, target = this,
14194            watchLog = [],
14195            logIdx, logMsg, asyncTask;
14196
14197        beginPhase('$digest');
14198        // Check for changes to browser url that happened in sync before the call to $digest
14199        $browser.$$checkUrlChange();
14200
14201        if (this === $rootScope && applyAsyncId !== null) {
14202          // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
14203          // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
14204          $browser.defer.cancel(applyAsyncId);
14205          flushApplyAsync();
14206        }
14207
14208        lastDirtyWatch = null;
14209
14210        do { // "while dirty" loop
14211          dirty = false;
14212          current = target;
14213
14214          while (asyncQueue.length) {
14215            try {
14216              asyncTask = asyncQueue.shift();
14217              asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
14218            } catch (e) {
14219              $exceptionHandler(e);
14220            }
14221            lastDirtyWatch = null;
14222          }
14223
14224          traverseScopesLoop:
14225          do { // "traverse the scopes" loop
14226            if ((watchers = current.$$watchers)) {
14227              // process our watches
14228              length = watchers.length;
14229              while (length--) {
14230                try {
14231                  watch = watchers[length];
14232                  // Most common watches are on primitives, in which case we can short
14233                  // circuit it with === operator, only when === fails do we use .equals
14234                  if (watch) {
14235                    if ((value = watch.get(current)) !== (last = watch.last) &&
14236                        !(watch.eq
14237                            ? equals(value, last)
14238                            : (typeof value === 'number' && typeof last === 'number'
14239                               && isNaN(value) && isNaN(last)))) {
14240                      dirty = true;
14241                      lastDirtyWatch = watch;
14242                      watch.last = watch.eq ? copy(value, null) : value;
14243                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
14244                      if (ttl < 5) {
14245                        logIdx = 4 - ttl;
14246                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
14247                        watchLog[logIdx].push({
14248                          msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
14249                          newVal: value,
14250                          oldVal: last
14251                        });
14252                      }
14253                    } else if (watch === lastDirtyWatch) {
14254                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
14255                      // have already been tested.
14256                      dirty = false;
14257                      break traverseScopesLoop;
14258                    }
14259                  }
14260                } catch (e) {
14261                  $exceptionHandler(e);
14262                }
14263              }
14264            }
14265
14266            // Insanity Warning: scope depth-first traversal
14267            // yes, this code is a bit crazy, but it works and we have tests to prove it!
14268            // this piece should be kept in sync with the traversal in $broadcast
14269            if (!(next = (current.$$childHead ||
14270                (current !== target && current.$$nextSibling)))) {
14271              while (current !== target && !(next = current.$$nextSibling)) {
14272                current = current.$parent;
14273              }
14274            }
14275          } while ((current = next));
14276
14277          // `break traverseScopesLoop;` takes us to here
14278
14279          if ((dirty || asyncQueue.length) && !(ttl--)) {
14280            clearPhase();
14281            throw $rootScopeMinErr('infdig',
14282                '{0} $digest() iterations reached. Aborting!\n' +
14283                'Watchers fired in the last 5 iterations: {1}',
14284                TTL, watchLog);
14285          }
14286
14287        }
14287 while (dirty || asyncQueue.length);
14288
14289        clearPhase();
14290
14291        while (postDigestQueue.length) {
14292          try {
14293            postDigestQueue.shift()();
14294          } catch (e) {
14295            $exceptionHandler(e);
14296          }
14297        }
14298      },
14299
14300
14301      /**
14302       * @ngdoc event
14303       * @name $rootScope.Scope#$destroy
14304       * @eventType broadcast on scope being destroyed
14305       *
14306       * @description
14307       * Broadcasted when a scope and its children are being destroyed.
14308       *
14309       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14310       * clean up DOM bindings before an element is removed from the DOM.
14311       */
14312
14313      /**
14314       * @ngdoc method
14315       * @name $rootScope.Scope#$destroy
14316       * @kind function
14317       *
14318       * @description
14319       * Removes the current scope (and all of its children) from the parent scope. Removal implies
14320       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
14321       * propagate to the current scope and its children. Removal also implies that the current
14322       * scope is eligible for garbage collection.
14323       *
14324       * The `$destroy()` is usually used by directives such as
14325       * {@link ng.directive:ngRepeat ngRepeat} for managing the
14326       * unrolling of the loop.
14327       *
14328       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
14329       * Application code can register a `$destroy` event handler that will give it a chance to
14330       * perform any necessary cleanup.
14331       *
14332       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
14333       * clean up DOM bindings before an element is removed from the DOM.
14334       */
14335      $destroy: function() {
14336        // we can't destroy the root scope or a scope that has been already destroyed
14337        if (this.$$destroyed) return;
14338        var parent = this.$parent;
14339
14340        this.$broadcast('$destroy');
14341        this.$$destroyed = true;
14342        if (this === $rootScope) return;
14343
14344        for (var eventName in this.$$listenerCount) {
14345          decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
14346        }
14347
14348        // sever all the references to parent scopes (after this cleanup, the current scope should
14349        // not be retained by any of our references and should be eligible for garbage collection)
14350        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
14351        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
14352        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
14353        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
14354
14355        // Disable listeners, watchers and apply/digest methods
14356        this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
14357        this.$on = this.$watch = this.$watchGroup = function() { return noop; };
14358        this.$$listeners = {};
14359
14360        // All of the code below is bogus code that works around V8's memory leak via optimized code
14361        // and inline caches.
14362        //
14363        // see:
14364        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
14365        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
14366        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
14367
14368        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
14369            this.$$childTail = this.$root = this.$$watchers = null;
14370      },
14371
14372      /**
14373       * @ngdoc method
14374       * @name $rootScope.Scope#$eval
14375       * @kind function
14376       *
14377       * @description
14378       * Executes the `expression` on the current scope and returns the result. Any exceptions in
14379       * the expression are propagated (uncaught). This is useful when evaluating Angular
14380       * expressions.
14381       *
14382       * # Example
14383       * ```js
14384           var scope = ng.$rootScope.Scope();
14385           scope.a = 1;
14386           scope.b = 2;
14387
14388           expect(scope.$eval('a+b')).toEqual(3);
14389           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
14390       * ```
14391       *
14392       * @param {(string|function())=} expression An angular expression to be executed.
14393       *
14394       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
14395       *    - `function(scope)`: execute the function with the current `scope` parameter.
14396       *
14397       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14398       * @returns {*} The result of evaluating the expression.
14399       */
14400      $eval: function(expr, locals) {
14401        return $parse(expr)(this, locals);
14402      },
14403
14404      /**
14405       * @ngdoc method
14406       * @name $rootScope.Scope#$evalAsync
14407       * @kind function
14408       *
14409       * @description
14410       * Executes the expression on the current scope at a later point in time.
14411       *
14412       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
14413       * that:
14414       *
14415       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
14416       *     rendering).
14417       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
14418       *     `expression` execution.
14419       *
14420       * Any exceptions from the execution of the expression are forwarded to the
14421       * {@link ng.$exceptionHandler $exceptionHandler} service.
14422       *
14423       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
14424       * will be scheduled. However, it is encouraged to always call code that changes the model
14425       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
14426       *
14427       * @param {(string|function())=} expression An angular expression to be executed.
14428       *
14429       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14430       *    - `function(scope)`: execute the function with the current `scope` parameter.
14431       *
14432       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
14433       */
14434      $evalAsync: function(expr, locals) {
14435        // if we are outside of an $digest loop and this is the first time we are scheduling async
14436        // task also schedule async auto-flush
14437        if (!$rootScope.$$phase && !asyncQueue.length) {
14438          $browser.defer(function() {
14439            if (asyncQueue.length) {
14440              $rootScope.$digest();
14441            }
14442          });
14443        }
14444
14445        asyncQueue.push({scope: this, expression: expr, locals: locals});
14446      },
14447
14448      $$postDigest: function(fn) {
14449        postDigestQueue.push(fn);
14450      },
14451
14452      /**
14453       * @ngdoc method
14454       * @name $rootScope.Scope#$apply
14455       * @kind function
14456       *
14457       * @description
14458       * `$apply()` is used to execute an expression in angular from outside of the angular
14459       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
14460       * Because we are calling into the angular framework we need to perform proper scope life
14461       * cycle of {@link ng.$exceptionHandler exception handling},
14462       * {@link ng.$rootScope.Scope#$digest executing watches}.
14463       *
14464       * ## Life cycle
14465       *
14466       * # Pseudo-Code of `$apply()`
14467       * ```js
14468           function $apply(expr) {
14469             try {
14470               return $eval(expr);
14471             } catch (e) {
14472               $exceptionHandler(e);
14473             } finally {
14474               $root.$digest();
14475             }
14476           }
14477       * ```
14478       *
14479       *
14480       * Scope's `$apply()` method transitions through the following stages:
14481       *
14482       * 1. The {@link guide/expression expression} is executed using the
14483       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
14484       * 2. Any exceptions from the execution of the expression are forwarded to the
14485       *    {@link ng.$exceptionHandler $exceptionHandler} service.
14486       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
14487       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
14488       *
14489       *
14490       * @param {(string|function())=} exp An angular expression to be executed.
14491       *
14492       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14493       *    - `function(scope)`: execute the function with current `scope` parameter.
14494       *
14495       * @returns {*} The result of evaluating the expression.
14496       */
14497      $apply: function(expr) {
14498        try {
14499          beginPhase('$apply');
14500          return this.$eval(expr);
14501        } catch (e) {
14502          $exceptionHandler(e);
14503        } finally {
14504          clearPhase();
14505          try {
14506            $rootScope.$digest();
14507          } catch (e) {
14508            $exceptionHandler(e);
14509            throw e;
14510          }
14511        }
14512      },
14513
14514      /**
14515       * @ngdoc method
14516       * @name $rootScope.Scope#$applyAsync
14517       * @kind function
14518       *
14519       * @description
14520       * Schedule the invocation of $apply to occur at a later time. The actual time difference
14521       * varies across browsers, but is typically around ~10 milliseconds.
14522       *
14523       * This can be used to queue up multiple expressions which need to be evaluated in the same
14524       * digest.
14525       *
14526       * @param {(string|function())=} exp An angular expression to be executed.
14527       *
14528       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
14529       *    - `function(scope)`: execute the function with current `scope` parameter.
14530       */
14531      $applyAsync: function(expr) {
14532        var scope = this;
14533        expr && applyAsyncQueue.push($applyAsyncExpression);
14534        scheduleApplyAsync();
14535
14536        function $applyAsyncExpression() {
14537          scope.$eval(expr);
14538        }
14539      },
14540
14541      /**
14542       * @ngdoc method
14543       * @name $rootScope.Scope#$on
14544       * @kind function
14545       *
14546       * @description
14547       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
14548       * discussion of event life cycle.
14549       *
14550       * The event listener function format is: `function(event, args...)`. The `event` object
14551       * passed into the listener has the following attributes:
14552       *
14553       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
14554       *     `$broadcast`-ed.
14555       *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
14556       *     event propagates through the scope hierarchy, this property is set to null.
14557       *   - `name` - `{string}`: name of the event.
14558       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
14559       *     further event propagation (available only for events that were `$emit`-ed).
14560       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
14561       *     to true.
14562       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
14563       *
14564       * @param {string} name Event name to listen on.
14565       * @param {function(event, ...args)} listener Function to call when the event is emitted.
14566       * @returns {function()} Returns a deregistration function for this listener.
14567       */
14568      $on: function(name, listener) {
14569        var namedListeners = this.$$listeners[name];
14570        if (!namedListeners) {
14571          this.$$listeners[name] = namedListeners = [];
14572        }
14573        namedListeners.push(listener);
14574
14575        var current = this;
14576        do {
14577          if (!current.$$listenerCount[name]) {
14578            current.$$listenerCount[name] = 0;
14579          }
14580          current.$$listenerCount[name]++;
14581        } while ((current = current.$parent));
14582
14583        var self = this;
14584        return function() {
14585          var indexOfListener = namedListeners.indexOf(listener);
14586          if (indexOfListener !== -1) {
14587            namedListeners[indexOfListener] = null;
14588            decrementListenerCount(self, 1, name);
14589          }
14590        };
14591      },
14592
14593
14594      /**
14595       * @ngdoc method
14596       * @name $rootScope.Scope#$emit
14597       * @kind function
14598       *
14599       * @description
14600       * Dispatches an event `name` upwards through the scope hierarchy notifying the
14601       * registered {@link ng.$rootScope.Scope#$on} listeners.
14602       *
14603       * The event life cycle starts at the scope on which `$emit` was called. All
14604       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14605       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
14606       * registered listeners along the way. The event will stop propagating if one of the listeners
14607       * cancels it.
14608       *
14609       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14610       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14611       *
14612       * @param {string} name Event name to emit.
14613       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14614       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
14615       */
14616      $emit: function(name, args) {
14617        var empty = [],
14618            namedListeners,
14619            scope = this,
14620            stopPropagation = false,
14621            event = {
14622              name: name,
14623              targetScope: scope,
14624              stopPropagation: function() {stopPropagation = true;},
14625              preventDefault: function() {
14626                event.defaultPrevented = true;
14627              },
14628              defaultPrevented: false
14629            },
14630            listenerArgs = concat([event], arguments, 1),
14631            i, length;
14632
14633        do {
14634          namedListeners = scope.$$listeners[name] || empty;
14635          event.currentScope = scope;
14636          for (i = 0, length = namedListeners.length; i < length; i++) {
14637
14638            // if listeners were deregistered, defragment the array
14639            if (!namedListeners[i]) {
14640              namedListeners.splice(i, 1);
14641              i--;
14642              length--;
14643              continue;
14644            }
14645            try {
14646              //allow all listeners attached to the current scope to run
14647              namedListeners[i].apply(null, listenerArgs);
14648            } catch (e) {
14649              $exceptionHandler(e);
14650            }
14651          }
14652          //if any listener on the current scope stops propagation, prevent bubbling
14653          if (stopPropagation) {
14654            event.currentScope = null;
14655            return event;
14656          }
14657          //traverse upwards
14658          scope = scope.$parent;
14659        } while (scope);
14660
14661        event.currentScope = null;
14662
14663        return event;
14664      },
14665
14666
14667      /**
14668       * @ngdoc method
14669       * @name $rootScope.Scope#$broadcast
14670       * @kind function
14671       *
14672       * @description
14673       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
14674       * registered {@link ng.$rootScope.Scope#$on} listeners.
14675       *
14676       * The event life cycle starts at the scope on which `$broadcast` was called. All
14677       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
14678       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
14679       * scope and calls all registered listeners along the way. The event cannot be canceled.
14680       *
14681       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
14682       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
14683       *
14684       * @param {string} name Event name to broadcast.
14685       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
14686       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
14687       */
14688      $broadcast: function(name, args) {
14689        var target = this,
14690            current = target,
14691            next = target,
14692            event = {
14693              name: name,
14694              targetScope: target,
14695              preventDefault: function() {
14696                event.defaultPrevented = true;
14697              },
14698              defaultPrevented: false
14699            };
14700
14701        if (!target.$$listenerCount[name]) return event;
14702
14703        var listenerArgs = concat([event], arguments, 1),
14704            listeners, i, length;
14705
14706        //down while you can, then up and next sibling or up and next sibling until back at root
14707        while ((current = next)) {
14708          event.currentScope = current;
14709          listeners = current.$$listeners[name] || [];
14710          for (i = 0, length = listeners.length; i < length; i++) {
14711            // if listeners were deregistered, defragment the array
14712            if (!listeners[i]) {
14713              listeners.splice(i, 1);
14714              i--;
14715              length--;
14716              continue;
14717            }
14718
14719            try {
14720              listeners[i].apply(null, listenerArgs);
14721            } catch (e) {
14722              $exceptionHandler(e);
14723            }
14724          }
14725
14726          // Insanity Warning: scope depth-first traversal
14727          // yes, this code is a bit crazy, but it works and we have tests to prove it!
14728          // this piece should be kept in sync with the traversal in $digest
14729          // (though it differs due to having the extra check for $$listenerCount)
14730          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
14731              (current !== target && current.$$nextSibling)))) {
14732            while (current !== target && !(next = current.$$nextSibling)) {
14733              current = current.$parent;
14734            }
14735          }
14736        }
14737
14738        event.currentScope = null;
14739        return event;
14740      }
14741    };
14742
14743    var $rootScope = new Scope();
14744
14745    //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
14746    var asyncQueue = $rootScope.$$asyncQueue = [];
14747    var postDigestQueue = $rootScope.$$postDigestQueue = [];
14748    var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
14749
14750    return $rootScope;
14751
14752
14753    function beginPhase(phase) {
14754      if ($rootScope.$$phase) {
14755        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
14756      }
14757
14758      $rootScope.$$phase = phase;
14759    }
14760
14761    function clearPhase() {
14762      $rootScope.$$phase = null;
14763    }
14764
14765
14766    function decrementListenerCount(current, count, name) {
14767      do {
14768        current.$$listenerCount[name] -= count;
14769
14770        if (current.$$listenerCount[name] === 0) {
14771          delete current.$$listenerCount[name];
14772        }
14773      } while ((current = current.$parent));
14774    }
14775
14776    /**
14777     * function used as an initial value for watchers.
14778     * because it's unique we can easily tell it apart from other values
14779     */
14780    function initWatchVal() {}
14781
14782    function flushApplyAsync() {
14783      while (applyAsyncQueue.length) {
14784        try {
14785          applyAsyncQueue.shift()();
14786        } catch (e) {
14787          $exceptionHandler(e);
14788        }
14789      }
14790      applyAsyncId = null;
14791    }
14792
14793    function scheduleApplyAsync() {
vendor: 3,834 bytes, lines 14794-14899
14794      if (applyAsyncId === null) {
14795        applyAsyncId = $browser.defer(function() {
14796          $rootScope.$apply(flushApplyAsync);
14797        });
14798      }
14799    }
14800  }];
14801}
14802
14803/**
14804 * @description
14805 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
14806 */
14807function $$SanitizeUriProvider() {
14808  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
14809    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
14810
14811  /**
14812   * @description
14813   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
14814   * urls during a[href] sanitization.
14815   *
14816   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
14817   *
14818   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
14819   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
14820   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
14821   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
14822   *
14823   * @param {RegExp=} regexp New regexp to whitelist urls with.
14824   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
14825   *    chaining otherwise.
14826   */
14827  this.aHrefSanitizationWhitelist = function(regexp) {
14828    if (isDefined(regexp)) {
14829      aHrefSanitizationWhitelist = regexp;
14830      return this;
14831    }
14832    return aHrefSanitizationWhitelist;
14833  };
14834
14835
14836  /**
14837   * @description
14838   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
14839   * urls during img[src] sanitization.
14840   *
14841   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
14842   *
14843   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
14844   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
14845   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
14846   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
14847   *
14848   * @param {RegExp=} regexp New regexp to whitelist urls with.
14849   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
14850   *    chaining otherwise.
14851   */
14852  this.imgSrcSanitizationWhitelist = function(regexp) {
14853    if (isDefined(regexp)) {
14854      imgSrcSanitizationWhitelist = regexp;
14855      return this;
14856    }
14857    return imgSrcSanitizationWhitelist;
14858  };
14859
14860  this.$get = function() {
14861    return function sanitizeUri(uri, isImage) {
14862      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
14863      var normalizedVal;
14864      normalizedVal = urlResolve(uri).href;
14865      if (normalizedVal !== '' && !normalizedVal.match(regex)) {
14866        return 'unsafe:' + normalizedVal;
14867      }
14868      return uri;
14869    };
14870  };
14871}
14872
14873var $sceMinErr = minErr('$sce');
14874
14875var SCE_CONTEXTS = {
14876  HTML: 'html',
14877  CSS: 'css',
14878  URL: 'url',
14879  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
14880  // url.  (e.g. ng-include, script src, templateUrl)
14881  RESOURCE_URL: 'resourceUrl',
14882  JS: 'js'
14883};
14884
14885// Helper functions follow.
14886
14887function adjustMatcher(matcher) {
14888  if (matcher === 'self') {
14889    return matcher;
14890  } else if (isString(matcher)) {
14891    // Strings match exactly except for 2 wildcards - '*' and '**'.
14892    // '*' matches any character except those from the set ':/.?&'.
14893    // '**' matches any character (like .* in a RegExp).
14894    // More than 2 *'s raises an error as it's ill defined.
14895    if (matcher.indexOf('***') > -1) {
14896      throw $sceMinErr('iwcard',
14897          'Illegal sequence *** in string matcher.  String: {0}', matcher);
14898    }
14899    matcher = escapeForRegexp(matcher).
14900                  replace('\\*\\*', '.*').
14901                  replace('\\*', '[^:/.?&;]*');
14902    return new RegExp('^' + matcher + '$');
14903  } else if (isRegExp(matcher)) {
14904    // The only other type of matcher allowed is a Regexp.
14905    // Match entire URL / disallow partial matches.
14906    // Flags are reset (i.e. no global, ignoreCase or multiline)
14907    return new RegExp('^' + matcher.source + '$');
14908  } else {
14909    throw $sceMinErr('imatcher',
14910        'Matchers may only be "self", string patterns or RegExp objects');
14911  }
14912}
14913
14914
14915function adjustMatchers(matchers) {
14916  var adjustedMatchers = [];
14917  if (isDefined(matchers)) {
14918    forEach(matchers, function(matcher) {
14919      adjustedMatchers.push(adjustMatcher(matcher));
14920    });
14921  }
14922  return adjustedMatchers;
14923}
14924
14925
14926/**
14927 * @ngdoc service
14928 * @name $sceDelegate
14929 * @kind function
14930 *
14931 * @description
14932 *
14933 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
14934 * Contextual Escaping (SCE)} services to AngularJS.
14935 *
14936 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
14937 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
14938 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
14939 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
14940 * work because `$sce` delegates to `$sceDelegate` for these operations.
14941 *
14942 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
14943 *
14944 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
14945 * can override it completely to change the behavior of `$sce`, the common case would
14946 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
14947 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
14948 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
14949 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
14950 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
14951 */
14952
14953/**
14954 * @ngdoc provider
14955 * @name $sceDelegateProvider
14956 * @description
14957 *
14958 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
14959 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
14960 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
14961 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
14962 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
14963 *
14964 * For the general details about this service in Angular, read the main page for {@link ng.$sce
14965 * Strict Contextual Escaping (SCE)}.
14966 *
14967 * **Example**:  Consider the following case. <a name="example"></a>
14968 *
14969 * - your app is hosted at url `http://myapp.example.com/`
14970 * - but some of your templates are hosted on other domains you control such as
14971 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
14972 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
14973 *
14974 * Here is what a secure configuration for this scenario might look like:
14975 *
14976 * ```
14977 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
14978 *    $sceDelegateProvider.resourceUrlWhitelist([
14979 *      // Allow same origin resource loads.
14980 *      'self',
14981 *      // Allow loading from our assets domain.  Notice the difference between * and **.
14982 *      'http://srv*.assets.example.com/**'
14983 *    ]);
14984 *
14985 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
14986 *    $sceDelegateProvider.resourceUrlBlacklist([
14987 *      'http://myapp.example.com/clickThru**'
14988 *    ]);
14989 *  });
14990 * ```
14991 */
14992
14993function $SceDelegateProvider() {
14994  this.SCE_CONTEXTS = SCE_CONTEXTS;
14995
14996  // Resource URLs can also be trusted by policy.
14997  var resourceUrlWhitelist = ['self'],
14998      resourceUrlBlacklist = [];
14999
15000  /**
15001   * @ngdoc method
15002   * @name $sceDelegateProvider#resourceUrlWhitelist
15003   * @kind function
15004   *
15005   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
15006   *     provided.  This must be an array or null.  A snapshot of this array is used so further
15007   *     changes to the array are ignored.
15008   *
15009   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15010   *     allowed in this array.
vendor: 4,148 bytes, lines 15011-15135
15011   *
15012   *     Note: **an empty whitelist array will block all URLs**!
15013   *
15014   * @return {Array} the currently set whitelist array.
15015   *
15016   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
15017   * same origin resource requests.
15018   *
15019   * @description
15020   * Sets/Gets the whitelist of trusted resource URLs.
15021   */
15022  this.resourceUrlWhitelist = function(value) {
15023    if (arguments.length) {
15024      resourceUrlWhitelist = adjustMatchers(value);
15025    }
15026    return resourceUrlWhitelist;
15027  };
15028
15029  /**
15030   * @ngdoc method
15031   * @name $sceDelegateProvider#resourceUrlBlacklist
15032   * @kind function
15033   *
15034   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
15035   *     provided.  This must be an array or null.  A snapshot of this array is used so further
15036   *     changes to the array are ignored.
15037   *
15038   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
15039   *     allowed in this array.
15040   *
15041   *     The typical usage for the blacklist is to **block
15042   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
15043   *     these would otherwise be trusted but actually return content from the redirected domain.
15044   *
15045   *     Finally, **the blacklist overrides the whitelist** and has the final say.
15046   *
15047   * @return {Array} the currently set blacklist array.
15048   *
15049   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
15050   * is no blacklist.)
15051   *
15052   * @description
15053   * Sets/Gets the blacklist of trusted resource URLs.
15054   */
15055
15056  this.resourceUrlBlacklist = function(value) {
15057    if (arguments.length) {
15058      resourceUrlBlacklist = adjustMatchers(value);
15059    }
15060    return resourceUrlBlacklist;
15061  };
15062
15063  this.$get = ['$injector', function($injector) {
15064
15065    var htmlSanitizer = function htmlSanitizer(html) {
15066      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15067    };
15068
15069    if ($injector.has('$sanitize')) {
15070      htmlSanitizer = $injector.get('$sanitize');
15071    }
15072
15073
15074    function matchUrl(matcher, parsedUrl) {
15075      if (matcher === 'self') {
15076        return urlIsSameOrigin(parsedUrl);
15077      } else {
15078        // definitely a regex.  See adjustMatchers()
15079        return !!matcher.exec(parsedUrl.href);
15080      }
15081    }
15082
15083    function isResourceUrlAllowedByPolicy(url) {
15084      var parsedUrl = urlResolve(url.toString());
15085      var i, n, allowed = false;
15086      // Ensure that at least one item from the whitelist allows this url.
15087      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
15088        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
15089          allowed = true;
15090          break;
15091        }
15092      }
15093      if (allowed) {
15094        // Ensure that no item from the blacklist blocked this url.
15095        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
15096          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
15097            allowed = false;
15098            break;
15099          }
15100        }
15101      }
15102      return allowed;
15103    }
15104
15105    function generateHolderType(Base) {
15106      var holderType = function TrustedValueHolderType(trustedValue) {
15107        this.$$unwrapTrustedValue = function() {
15108          return trustedValue;
15109        };
15110      };
15111      if (Base) {
15112        holderType.prototype = new Base();
15113      }
15114      holderType.prototype.valueOf = function sceValueOf() {
15115        return this.$$unwrapTrustedValue();
15116      };
15117      holderType.prototype.toString = function sceToString() {
15118        return this.$$unwrapTrustedValue().toString();
15119      };
15120      return holderType;
15121    }
15122
15123    var trustedValueHolderBase = generateHolderType(),
15124        byType = {};
15125
15126    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
15127    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
15128    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
15129    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
15130    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
15131
15132    /**
15133     * @ngdoc method
15134     * @name $sceDelegate#trustAs
15135     *
15136     * @description
15137     * Returns an object that is trusted by angular for use in specified strict
15138     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
15139     * attribute interpolation, any dom event binding attribute interpolation
15140     * such as for onclick,  etc.) that uses the provided value.
15141     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
15142     *
15143     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15144     *   resourceUrl, html, js and css.
15145     * @param {*} value The value that that should be considered trusted/safe.
15146     * @returns {*} A value that can be used to stand in for the provided `value` in places
15147     * where Angular expects a $sce.trustAs() return value.
15148     */
15149    function trustAs(type, trustedValue) {
15150      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15151      if (!Constructor) {
15152        throw $sceMinErr('icontext',
15153            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
15154            type, trustedValue);
15155      }
15156      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
15157        return trustedValue;
15158      }
15159      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
15160      // mutable objects, we ensure here that the value passed in is actually a string.
15161      if (typeof trustedValue !== 'string') {
15162        throw $sceMinErr('itype',
15163            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
15164            type);
15165      }
15166      return new Constructor(trustedValue);
15167    }
15168
15169    /**
15170     * @ngdoc method
15171     * @name $sceDelegate#valueOf
15172     *
15173     * @description
15174     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
15175     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
15176     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
15177     *
15178     * If the passed parameter is not a value that had been returned by {@link
15179     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
15180     *
15181     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
15182     *      call or anything else.
15183     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
15184     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
15185     *     `value` unchanged.
15186     */
15187    function valueOf(maybeTrusted) {
15188      if (maybeTrusted instanceof trustedValueHolderBase) {
15189        return maybeTrusted.$$unwrapTrustedValue();
15190      } else {
15191        return maybeTrusted;
15192      }
15193    }
15194
15195    /**
15196     * @ngdoc method
15197     * @name $sceDelegate#getTrusted
15198     *
15199     * @description
15200     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
15201     * returns the originally supplied value if the queried context type is a supertype of the
15202     * created type.  If this condition isn't satisfied, throws an exception.
15203     *
15204     * @param {string} type The kind of context in which this value is to be used.
15205     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
15206     *     `$sceDelegate.trustAs`} call.
15207     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
15208     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
15209     */
15210    function getTrusted(type, maybeTrusted) {
15211      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
15212        return maybeTrusted;
15213      }
15214      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
15215      if (constructor && maybeTrusted instanceof constructor) {
15216        return maybeTrusted.$$unwrapTrustedValue();
15217      }
15218      // If we get here, then we may only take one of two actions.
15219      // 1. sanitize the value for the requested type, or
15220      // 2. throw an exception.
15221      if (type === SCE_CONTEXTS.RESOURCE_URL) {
15222        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
15223          return maybeTrusted;
15224        } else {
15225          throw $sceMinErr('insecurl',
15226              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
15227              maybeTrusted.toString());
15228        }
15229      } else if (type === SCE_CONTEXTS.HTML) {
15230        return htmlSanitizer(maybeTrusted);
15231      }
15232      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
15233    }
15234
15235    return { trustAs: trustAs,
15236             getTrusted: getTrusted,
15237             valueOf: valueOf };
15238  }];
15239}
15240
15241
15242/**
15243 * @ngdoc provider
15244 * @name $sceProvider
15245 * @description
15246 *
15247 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
15248 * -   enable/disable Strict Contextual Escaping (SCE) in a module
15249 * -   override the default implementation with a custom delegate
15250 *
15251 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
15252 */
15253
15254/* jshint maxlen: false*/
15255
15256/**
15257 * @ngdoc service
15258 * @name $sce
15259 * @kind function
15260 *
15261 * @description
15262 *
15263 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
15264 *
15265 * # Strict Contextual Escaping
15266 *
15267 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
15268 * contexts to result in a value that is marked as safe to use for that context.  One example of
15269 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
15270 * to these contexts as privileged or SCE contexts.
15271 *
15272 * As of version 1.2, Angular ships with SCE enabled by default.
15273 *
15274 * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
15275 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
15276 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
15277 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
15278 * to the top of your HTML document.
15279 *
15280 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
15281 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
15282 *
15283 * Here's an example of a binding in a privileged context:
15284 *
15285 * ```
15286 * <input ng-model="userHtml">
15287 * <div ng-bind-html="userHtml"></div>
15288 * ```
15289 *
15290 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
15291 * disabled, this application allows the user to render arbitrary HTML into the DIV.
15292 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
15293 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
15294 * security vulnerabilities.)
15295 *
15296 * For the case of HTML, you might use a library, either on the client side, or on the server side,
15297 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
15298 *
15299 * How would you ensure that every place that used these types of bindings was bound to a value that
15300 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
15301 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
15302 * properties/fields and forgot to update the binding to the sanitized value?
15303 *
15304 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
15305 * determine that something explicitly says it's safe to use a value for binding in that
15306 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
15307 * for those values that you can easily tell are safe - because they were received from your server,
15308 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
15309 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
15310 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
15311 *
15312 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
15313 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
15314 * obtain values that will be accepted by SCE / privileged contexts.
15315 *
15316 *
15317 * ## How does it work?
15318 *
15319 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
15320 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
15321 * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
15322 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
15323 *
15324 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
15325 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
15326 * simplified):
15327 *
15328 * ```
15329 * var ngBindHtmlDirective = ['$sce', function($sce) {
15330 *   return function(scope, element, attr) {
15331 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
15332 *       element.html(value || '');
15333 *     });
15334 *   };
15335 * }];
15336 * ```
15337 *
15338 * ## Impact on loading templates
15339 *
15340 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
15341 * `templateUrl`'s specified by {@link guide/directive directives}.
15342 *
15343 * By default, Angular only loads templates from the same domain and protocol as the application
15344 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
15345 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
15346 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
15347 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
15348 *
15349 * *Please note*:
15350 * The browser's
15351 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
15352 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
15353 * policy apply in addition to this and may further restrict whether the template is successfully
15354 * loaded.  This means that without the right CORS policy, loading templates from a different domain
15355 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
15356 * browsers.
15357 *
15358 * ## This feels like too much overhead
15359 *
15360 * It's important to remember that SCE only applies to interpolation expressions.
15361 *
15362 * If your expressions are constant literals, they're automatically trusted and you don't need to
15363 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
15364 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
15365 *
15366 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
15367 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
15368 *
15369 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
15370 * templates in `ng-include` from your application's domain without having to even know about SCE.
15371 * It blocks loading templates from other domains or loading templates over http from an https
15372 * served document.  You can change these by setting your own custom {@link
15373 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
15374 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
15375 *
15376 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
15377 * application that's secure and can be audited to verify that with much more ease than bolting
15378 * security onto an application later.
15379 *
15380 * <a name="contexts"></a>
15381 * ## What trusted context types are supported?
15382 *
15383 * | Context             | Notes          |
15384 * |---------------------|----------------|
15385 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
15386 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
15387 * | `$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. |
15388 * | `$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. |
15389 * | `$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. |
15390 *
15391 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
15392 *
15393 *  Each element in these arrays must be one of the following:
15394 *
15395 *  - **'self'**
15396 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
15397 *      domain** as the application document using the **same protocol**.
15398 *  - **String** (except the special value `'self'`)
15399 *    - The string is matched against the full *normalized / absolute URL* of the resource
15400 *      being tested (substring matches are not good enough.)
15401 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
15402 *      match themselves.
15403 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
15404 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
15405 *      in a whitelist.
15406 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
15407 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
15408 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
15409 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
15410 *      http://foo.example.com/templates/**).
15411 *  - **RegExp** (*see caveat below*)
15412 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
15413 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
15414 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
15415 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
15416 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
15417 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
15418 *      is highly recommended to use the string patterns and only fall back to regular expressions
15419 *      if they as a last resort.
15420 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
15421 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
15422 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
15423 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
15424 *    - If you are generating your JavaScript from some other templating engine (not
15425 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
15426 *      remember to escape your regular expression (and be aware that you might need more than
15427 *      one level of escaping depending on your templating engine and the way you interpolated
15428 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
15429 *      enough before coding your own.  e.g. Ruby has
15430 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
15431 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
15432 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
15433 *      Closure library's [goog.string.regExpEscape(s)](
15434 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
15435 *
15436 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
15437 *
15438 * ## Show me an example using SCE.
15439 *
15440 * <example module="mySceApp" deps="angular-sanitize.js">
15441 * <file name="index.html">
15442 *   <div ng-controller="AppController as myCtrl">
15443 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
15444 *     <b>User comments</b><br>
15445 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
15446 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
15447 *     exploit.
15448 *     <div class="well">
15449 *       <div ng-repeat="userComment in myCtrl.userComments">
15450 *         <b>{{userComment.name}}</b>:
15451 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
15452 *         <br>
15453 *       </div>
15454 *     </div>
15455 *   </div>
15456 * </file>
15457 *
15458 * <file name="script.js">
15459 *   angular.module('mySceApp', ['ngSanitize'])
15460 *     .controller('AppController', ['$http', '$templateCache', '$sce',
15461 *       function($http, $templateCache, $sce) {
15462 *         var self = this;
15463 *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
15464 *           self.userComments = userComments;
15465 *         });
15466 *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
15467 *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15468 *             'sanitization.&quot;">Hover over this text.</span>');
15469 *       }]);
15470 * </file>
15471 *
15472 * <file name="test_data.json">
15473 * [
15474 *   { "name": "Alice",
15475 *     "htmlComment":
15476 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
15477 *   },
15478 *   { "name": "Bob",
15479 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
15480 *   }
15481 * ]
15482 * </file>
15483 *
15484 * <file name="protractor.js" type="protractor">
15485 *   describe('SCE doc demo', function() {
15486 *     it('should sanitize untrusted values', function() {
15487 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
15488 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
15489 *     });
15490 *
15491 *     it('should NOT sanitize explicitly trusted values', function() {
15492 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
15493 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
15494 *           'sanitization.&quot;">Hover over this text.</span>');
15495 *     });
15496 *   });
15497 * </file>
15498 * </example>
15499 *
15500 *
15501 *
15502 * ## Can I disable SCE completely?
15503 *
15504 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
15505 * for little coding overhead.  It will be much harder to take an SCE disabled application and
15506 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
15507 * for cases where you have a lot of existing code that was written before SCE was introduced and
15508 * you're migrating them a module at a time.
15509 *
15510 * That said, here's how you can completely disable SCE:
15511 *
15512 * ```
15513 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
15514 *   // Completely disable SCE.  For demonstration purposes only!
15515 *   // Do not use in new projects.
15516 *   $sceProvider.enabled(false);
15517 * });
15518 * ```
15519 *
15520 */
15521/* jshint maxlen: 100 */
15522
15523function $SceProvider() {
15524  var enabled = true;
15525
15526  /**
15527   * @ngdoc method
15528   * @name $sceProvider#enabled
15529   * @kind function
15530   *
15531   * @param {boolean=} value If provided, then enables/disables SCE.
15532   * @return {boolean} true if SCE is enabled, false otherwise.
15533   *
15534   * @description
15535   * Enables/disables SCE and returns the current value.
15536   */
15537  this.enabled = function(value) {
15538    if (arguments.length) {
15539      enabled = !!value;
15540    }
15541    return enabled;
15542  };
15543
15544
15545  /* Design notes on the default implementation for SCE.
15546   *
15547   * The API contract for the SCE delegate
15548   * -------------------------------------
15549   * The SCE delegate object must provide the following 3 methods:
15550   *
15551   * - trustAs(contextEnum, value)
15552   *     This method is used to tell the SCE service that the provided value is OK to use in the
15553   *     contexts specified by contextEnum.  It must return an object that will be accepted by
15554   *     getTrusted() for a compatible contextEnum and return this value.
15555   *
15556   * - valueOf(value)
15557   *     For values that were not produced by trustAs(), return them as is.  For values that were
15558   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
15559   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
15560   *     such a value.
15561   *
15562   * - getTrusted(contextEnum, value)
15563   *     This function should return the a value that is safe to use in the context specified by
15564   *     contextEnum or throw and exception otherwise.
15565   *
15566   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
15567   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
15568   * instance, an implementation could maintain a registry of all trusted objects by context.  In
15569   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
15570   * return the same object passed in if it was found in the registry under a compatible context or
15571   * throw an exception otherwise.  An implementation might only wrap values some of the time based
15572   * on some criteria.  getTrusted() might return a value and not throw an exception for special
15573   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
15574   *
15575   *
15576   * A note on the inheritance model for SCE contexts
15577   * ------------------------------------------------
15578   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
15579   * is purely an implementation details.
15580   *
15581   * The contract is simply this:
15582   *
15583   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
15584   *     will also succeed.
15585   *
15586   * Inheritance happens to capture this in a natural way.  In some future, we
15587   * may not use inheritance anymore.  That is OK because no code outside of
15588   * sce.js and sceSpecs.js would need to be aware of this detail.
15589   */
15590
15591  this.$get = ['$parse', '$sceDelegate', function(
15592                $parse,   $sceDelegate) {
15593    // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
15594    // the "expression(javascript expression)" syntax which is insecure.
15595    if (enabled && msie < 8) {
15596      throw $sceMinErr('iequirks',
15597        'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
15598        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
15599        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
15600    }
15601
15602    var sce = shallowCopy(SCE_CONTEXTS);
15603
15604    /**
15605     * @ngdoc method
15606     * @name $sce#isEnabled
15607     * @kind function
15608     *
15609     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
15610     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
15611     *
15612     * @description
15613     * Returns a boolean indicating if SCE is enabled.
15614     */
15615    sce.isEnabled = function() {
15616      return enabled;
15617    };
15618    sce.trustAs = $sceDelegate.trustAs;
15619    sce.getTrusted = $sceDelegate.getTrusted;
15620    sce.valueOf = $sceDelegate.valueOf;
15621
15622    if (!enabled) {
15623      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
15624      sce.valueOf = identity;
15625    }
15626
15627    /**
15628     * @ngdoc method
15629     * @name $sce#parseAs
15630     *
15631     * @description
15632     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
15633     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
15634     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
15635     * *result*)}
15636     *
15637     * @param {string} type The kind of SCE context in which this result will be used.
15638     * @param {string} expression String expression to compile.
15639     * @returns {function(context, locals)} a function which represents the compiled expression:
15640     *
15641     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15642     *      are evaluated against (typically a scope object).
15643     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15644     *      `context`.
15645     */
15646    sce.parseAs = function sceParseAs(type, expr) {
15647      var parsed = $parse(expr);
15648      if (parsed.literal && parsed.constant) {
15649        return parsed;
15650      } else {
15651        return $parse(expr, function(value) {
15652          return sce.getTrusted(type, value);
15653        });
15654      }
15655    };
15656
15657    /**
15658     * @ngdoc method
15659     * @name $sce#trustAs
15660     *
15661     * @description
15662     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
15663     * returns an object that is trusted by angular for use in specified strict contextual
15664     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
15665     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
15666     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
15667     * escaping.
15668     *
15669     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
15670     *   resource_url, html, js and css.
15671     * @param {*} value The value that that should be considered trusted/safe.
15672     * @returns {*} A value that can be used to stand in for the provided `value` in places
15673     * where Angular expects a $sce.trustAs() return value.
15674     */
15675
15676    /**
15677     * @ngdoc method
15678     * @name $sce#trustAsHtml
15679     *
15680     * @description
15681     * Shorthand method.  `$sce.trustAsHtml(value)` →
15682     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
15683     *
15684     * @param {*} value The value to trustAs.
15685     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
15686     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
15687     *     only accept expressions that are either literal constants or are the
15688     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15689     */
15690
15691    /**
15692     * @ngdoc method
15693     * @name $sce#trustAsUrl
15694     *
15695     * @description
15696     * Shorthand method.  `$sce.trustAsUrl(value)` →
15697     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
15698     *
15699     * @param {*} value The value to trustAs.
15700     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
15701     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
15702     *     only accept expressions that are either literal constants or are the
15703     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15704     */
15705
15706    /**
15707     * @ngdoc method
15708     * @name $sce#trustAsResourceUrl
15709     *
15710     * @description
15711     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
15712     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
15713     *
15714     * @param {*} value The value to trustAs.
15715     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
15716     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
15717     *     only accept expressions that are either literal constants or are the return
15718     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
15719     */
15720
15721    /**
15722     * @ngdoc method
15723     * @name $sce#trustAsJs
15724     *
15725     * @description
15726     * Shorthand method.  `$sce.trustAsJs(value)` →
15727     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
15728     *
15729     * @param {*} value The value to trustAs.
15730     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
15731     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
15732     *     only accept expressions that are either literal constants or are the
15733     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
15734     */
15735
15736    /**
15737     * @ngdoc method
15738     * @name $sce#getTrusted
15739     *
15740     * @description
15741     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
15742     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
15743     * originally supplied value if the queried context type is a supertype of the created type.
15744     * If this condition isn't satisfied, throws an exception.
15745     *
15746     * @param {string} type The kind of context in which this value is to be used.
15747     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
15748     *                         call.
15749     * @returns {*} The value the was originally provided to
15750     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
15751     *              Otherwise, throws an exception.
15752     */
15753
15754    /**
15755     * @ngdoc method
15756     * @name $sce#getTrustedHtml
15757     *
15758     * @description
15759     * Shorthand method.  `$sce.getTrustedHtml(value)` →
15760     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
15761     *
15762     * @param {*} value The value to pass to `$sce.getTrusted`.
15763     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
15764     */
15765
15766    /**
15767     * @ngdoc method
15768     * @name $sce#getTrustedCss
15769     *
15770     * @description
15771     * Shorthand method.  `$sce.getTrustedCss(value)` →
15772     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
15773     *
15774     * @param {*} value The value to pass to `$sce.getTrusted`.
15775     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
15776     */
15777
15778    /**
15779     * @ngdoc method
15780     * @name $sce#getTrustedUrl
15781     *
15782     * @description
15783     * Shorthand method.  `$sce.getTrustedUrl(value)` →
15784     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
15785     *
15786     * @param {*} value The value to pass to `$sce.getTrusted`.
15787     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
15788     */
15789
15790    /**
15791     * @ngdoc method
15792     * @name $sce#getTrustedResourceUrl
15793     *
15794     * @description
15795     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
15796     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
15797     *
15798     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
15799     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
15800     */
15801
15802    /**
15803     * @ngdoc method
15804     * @name $sce#getTrustedJs
15805     *
15806     * @description
15807     * Shorthand method.  `$sce.getTrustedJs(value)` →
15808     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
15809     *
15810     * @param {*} value The value to pass to `$sce.getTrusted`.
15811     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
15812     */
15813
15814    /**
15815     * @ngdoc method
15816     * @name $sce#parseAsHtml
15817     *
15818     * @description
15819     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
15820     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
15821     *
15822     * @param {string} expression String expression to compile.
15823     * @returns {function(context, locals)} a function which represents the compiled expression:
15824     *
15825     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15826     *      are evaluated against (typically a scope object).
15827     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15828     *      `context`.
15829     */
15830
15831    /**
15832     * @ngdoc method
15833     * @name $sce#parseAsCss
15834     *
15835     * @description
15836     * Shorthand method.  `$sce.parseAsCss(value)` →
15837     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
15838     *
15839     * @param {string} expression String expression to compile.
15840     * @returns {function(context, locals)} a function which represents the compiled expression:
15841     *
15842     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15843     *      are evaluated against (typically a scope object).
15844     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15845     *      `context`.
15846     */
15847
15848    /**
15849     * @ngdoc method
15850     * @name $sce#parseAsUrl
15851     *
15852     * @description
15853     * Shorthand method.  `$sce.parseAsUrl(value)` →
15854     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
15855     *
15856     * @param {string} expression String expression to compile.
15857     * @returns {function(context, locals)} a function which represents the compiled expression:
15858     *
15859     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15860     *      are evaluated against (typically a scope object).
15861     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15862     *      `context`.
15863     */
15864
15865    /**
15866     * @ngdoc method
15867     * @name $sce#parseAsResourceUrl
15868     *
15869     * @description
15870     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
15871     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
15872     *
15873     * @param {string} expression String expression to compile.
15874     * @returns {function(context, locals)} a function which represents the compiled expression:
15875     *
15876     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15877     *      are evaluated against (typically a scope object).
15878     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15879     *      `context`.
15880     */
15881
15882    /**
15883     * @ngdoc method
15884     * @name $sce#parseAsJs
15885     *
15886     * @description
15887     * Shorthand method.  `$sce.parseAsJs(value)` →
15888     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
15889     *
15890     * @param {string} expression String expression to compile.
15891     * @returns {function(context, locals)} a function which represents the compiled expression:
15892     *
15893     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
15894     *      are evaluated against (typically a scope object).
15895     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
15896     *      `context`.
15897     */
15898
15899    // Shorthand delegations.
15900    var parse = sce.parseAs,
15901        getTrusted = sce.getTrusted,
15902        trustAs = sce.trustAs;
15903
15904    forEach(SCE_CONTEXTS, function(enumValue, name) {
15905      var lName = lowercase(name);
15906      sce[camelCase("parse_as_" + lName)] = function(expr) {
15907        return parse(enumValue, expr);
15908      };
15909      sce[camelCase("get_trusted_" + lName)] = function(value) {
15910        return getTrusted(enumValue, value);
15911      };
15912      sce[camelCase("trust_as_" + lName)] = function(value) {
15913        return trustAs(enumValue, value);
15914      };
15915    });
15916
15917    return sce;
15918  }];
15919}
15920
15921/**
15922 * !!! This is an undocumented "private" service !!!
15923 *
15924 * @name $sniffer
15925 * @requires $window
15926 * @requires $document
15927 *
15928 * @property {boolean} history Does the browser support html5 history api ?
15929 * @property {boolean} transitions Does the browser support CSS transition events ?
15930 * @property {boolean} animations Does the browser support CSS animation events ?
15931 *
15932 * @description
15933 * This is very simple implementation of testing browser's features.
15934 */
15935function $SnifferProvider() {
15936  this.$get = ['$window', '$document', function($window, $document) {
15937    var eventSupport = {},
15938        android =
15939          int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
15940        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
15941        document = $document[0] || {},
15942        vendorPrefix,
15943        vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
15944        bodyStyle = document.body && document.body.style,
15945        transitions = false,
15946        animations = false,
15947        match;
15948
15949    if (bodyStyle) {
15950      for (var prop in bodyStyle) {
15951        if (match = vendorRegex.exec(prop)) {
15952          vendorPrefix = match[0];
15953          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
15954          break;
15955        }
15956      }
15957
15958      if (!vendorPrefix) {
15959        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
15960      }
15961
15962      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
15963      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
15964
15965      if (android && (!transitions ||  !animations)) {
15966        transitions = isString(document.body.style.webkitTransition);
15967        animations = isString(document.body.style.webkitAnimation);
15968      }
15969    }
15970
15971
15972    return {
15973      // Android has history.pushState, but it does not update location correctly
15974      // so let's not use the history API at all.
15975      // http://code.google.com/p/android/issues/detail?id=17471
15976      // https://github.com/angular/angular.js/issues/904
15977
15978      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
15979      // so let's not use the history API also
15980      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
15981      // jshint -W018
15982      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
15983      // jshint +W018
15984      hasEvent: function(event) {
15985        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
15986        // it. In particular the event is not fired when backspace or delete key are pressed or
15987        // when cut operation is performed.
15988        // IE10+ implements 'input' event but it erroneously fires under various situations,
15989        // e.g. when placeholder changes, or a form is focused.
15990        if (event === 'input' && msie <= 11) return false;
15991
15992        if (isUndefined(eventSupport[event])) {
15993          var divElm = document.createElement('div');
15994          eventSupport[event] = 'on' + event in divElm;
15995        }
15996
15997        return eventSupport[event];
15998      },
15999      csp: csp(),
16000      vendorPrefix: vendorPrefix,
16001      transitions: transitions,
16002      animations: animations,
16003      android: android
16004    };
16005  }];
16006}
16007
16008var $compileMinErr = minErr('$compile');
16009
16010/**
16011 * @ngdoc service
16012 * @name $templateRequest
16013 *
16014 * @description
16015 * The `$templateRequest` service downloads the provided template using `$http` and, upon success,
16016 * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
16017 * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
16018 * by setting the 2nd parameter of the function to true).
16019 *
16020 * @param {string} tpl The HTTP request template URL
16021 * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
16022 *
16023 * @return {Promise} the HTTP Promise for the given.
16024 *
16025 * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
16026 */
16027function $TemplateRequestProvider() {
16028  this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
16029    function handleRequestFn(tpl, ignoreRequestError) {
16030      handleRequestFn.totalPendingRequests++;
16031
16032      var transformResponse = $http.defaults && $http.defaults.transformResponse;
16033
16034      if (isArray(transformResponse)) {
16035        transformResponse = transformResponse.filter(function(transformer) {
16036          return transformer !== defaultHttpResponseTransform;
16037        });
16038      } else if (transformResponse === defaultHttpResponseTransform) {
16039        transformResponse = null;
16040      }
16041
16042      var httpOptions = {
16043        cache: $templateCache,
16044        transformResponse: transformResponse
16045      };
16046
16047      return $http.get(tpl, httpOptions)
16048        .finally(function() {
16049          handleRequestFn.totalPendingRequests--;
16050        })
16051        .then(function(response) {
16052          return response.data;
16053        }, handleError);
16054
16055      function handleError(resp) {
16056        if (!ignoreRequestError) {
16057          throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
16058        }
16059        return $q.reject(resp);
16060      }
16061    }
16062
16063    handleRequestFn.totalPendingRequests = 0;
16064
16065    return handleRequestFn;
16066  }];
16067}
16068
vendor: 5,832 bytes, lines 16069-16245
16069function $$TestabilityProvider() {
16070  this.$get = ['$rootScope', '$browser', '$location',
16071       function($rootScope,   $browser,   $location) {
16072
16073    /**
16074     * @name $testability
16075     *
16076     * @description
16077     * The private $$testability service provides a collection of methods for use when debugging
16078     * or by automated test and debugging tools.
16079     */
16080    var testability = {};
16081
16082    /**
16083     * @name $$testability#findBindings
16084     *
16085     * @description
16086     * Returns an array of elements that are bound (via ng-bind or {{}})
16087     * to expressions matching the input.
16088     *
16089     * @param {Element} element The element root to search from.
16090     * @param {string} expression The binding expression to match.
16091     * @param {boolean} opt_exactMatch If true, only returns exact matches
16092     *     for the expression. Filters and whitespace are ignored.
16093     */
16094    testability.findBindings = function(element, expression, opt_exactMatch) {
16095      var bindings = element.getElementsByClassName('ng-binding');
16096      var matches = [];
16097      forEach(bindings, function(binding) {
16098        var dataBinding = angular.element(binding).data('$binding');
16099        if (dataBinding) {
16100          forEach(dataBinding, function(bindingName) {
16101            if (opt_exactMatch) {
16102              var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
16103              if (matcher.test(bindingName)) {
16104                matches.push(binding);
16105              }
16106            } else {
16107              if (bindingName.indexOf(expression) != -1) {
16108                matches.push(binding);
16109              }
16110            }
16111          });
16112        }
16113      });
16114      return matches;
16115    };
16116
16117    /**
16118     * @name $$testability#findModels
16119     *
16120     * @description
16121     * Returns an array of elements that are two-way found via ng-model to
16122     * expressions matching the input.
16123     *
16124     * @param {Element} element The element root to search from.
16125     * @param {string} expression The model expression to match.
16126     * @param {boolean} opt_exactMatch If true, only returns exact matches
16127     *     for the expression.
16128     */
16129    testability.findModels = function(element, expression, opt_exactMatch) {
16130      var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
16131      for (var p = 0; p < prefixes.length; ++p) {
16132        var attributeEquals = opt_exactMatch ? '=' : '*=';
16133        var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
16134        var elements = element.querySelectorAll(selector);
16135        if (elements.length) {
16136          return elements;
16137        }
16138      }
16139    };
16140
16141    /**
16142     * @name $$testability#getLocation
16143     *
16144     * @description
16145     * Shortcut for getting the location in a browser agnostic way. Returns
16146     *     the path, search, and hash. (e.g. /path?a=b#hash)
16147     */
16148    testability.getLocation = function() {
16149      return $location.url();
16150    };
16151
16152    /**
16153     * @name $$testability#setLocation
16154     *
16155     * @description
16156     * Shortcut for navigating to a location without doing a full page reload.
16157     *
16158     * @param {string} url The location url (path, search and hash,
16159     *     e.g. /path?a=b#hash) to go to.
16160     */
16161    testability.setLocation = function(url) {
16162      if (url !== $location.url()) {
16163        $location.url(url);
16164        $rootScope.$digest();
16165      }
16166    };
16167
16168    /**
16169     * @name $$testability#whenStable
16170     *
16171     * @description
16172     * Calls the callback when $timeout and $http requests are completed.
16173     *
16174     * @param {function} callback
16175     */
16176    testability.whenStable = function(callback) {
16177      $browser.notifyWhenNoOutstandingRequests(callback);
16178    };
16179
16180    return testability;
16181  }];
16182}
16183
16184function $TimeoutProvider() {
16185  this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
16186       function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
16187    var deferreds = {};
16188
16189
16190     /**
16191      * @ngdoc service
16192      * @name $timeout
16193      *
16194      * @description
16195      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
16196      * block and delegates any exceptions to
16197      * {@link ng.$exceptionHandler $exceptionHandler} service.
16198      *
16199      * The return value of registering a timeout function is a promise, which will be resolved when
16200      * the timeout is reached and the timeout function is executed.
16201      *
16202      * To cancel a timeout request, call `$timeout.cancel(promise)`.
16203      *
16204      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
16205      * synchronously flush the queue of deferred functions.
16206      *
16207      * @param {function()} fn A function, whose execution should be delayed.
16208      * @param {number=} [delay=0] Delay in milliseconds.
16209      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
16210      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
16211      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
16212      *   promise will be resolved with is the return value of the `fn` function.
16213      *
16214      */
16215    function timeout(fn, delay, invokeApply) {
16216      var skipApply = (isDefined(invokeApply) && !invokeApply),
16217          deferred = (skipApply ? $$q : $q).defer(),
16218          promise = deferred.promise,
16219          timeoutId;
16220
16221      timeoutId = $browser.defer(function() {
16222        try {
16223          deferred.resolve(fn());
16224        } catch (e) {
16225          deferred.reject(e);
16226          $exceptionHandler(e);
16227        }
16228        finally {
16229          delete deferreds[promise.$$timeoutId];
16230        }
16231
16232        if (!skipApply) $rootScope.$apply();
16233      }, delay);
16234
16235      promise.$$timeoutId = timeoutId;
16236      deferreds[timeoutId] = deferred;
16237
16238      return promise;
16239    }
16240
16241
16242     /**
16243      * @ngdoc method
16244      * @name $timeout#cancel
16245      *
16246      * @description
16247      * Cancels a task associated with the `promise`. As a result of this, the promise will be
16248      * resolved with a rejection.
16249      *
16250      * @param {Promise=} promise Promise returned by the `$timeout` function.
16251      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
16252      *   canceled.
16253      */
16254    timeout.cancel = function(promise) {
16255      if (promise && promise.$$timeoutId in deferreds) {
16256        deferreds[promise.$$timeoutId].reject('canceled');
16257        delete deferreds[promise.$$timeoutId];
16258        return $browser.defer.cancel(promise.$$timeoutId);
16259      }
16260      return false;
16261    };
16262
16263    return timeout;
16264  }];
16265}
16266
16267// NOTE:  The usage of window and document instead of $window and $document here is
16268// deliberate.  This service depends on the specific behavior of anchor nodes created by the
16269// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
16270// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
16271// doesn't know about mocked locations and resolves URLs to the real document - which is
16272// exactly the behavior needed here.  There is little value is mocking these out for this
16273// service.
16274var urlParsingNode = document.createElement("a");
16275var originUrl = urlResolve(window.location.href);
16276
16277
16278/**
16279 *
16280 * Implementation Notes for non-IE browsers
16281 * ----------------------------------------
16282 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
16283 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
16284 * URL will be resolved into an absolute URL in the context of the application document.
16285 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
16286 * properties are all populated to reflect the normalized URL.  This approach has wide
16287 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
16288 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16289 *
16290 * Implementation Notes for IE
16291 * ---------------------------
16292 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
16293 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
16294 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
16295 * work around that by performing the parsing in a 2nd step by taking a previously normalized
16296 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
16297 * properties such as protocol, hostname, port, etc.
16298 *
16299 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
16300 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
16301 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
16302 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
16303 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
16304 * method and IE < 8 is unsupported.
16305 *
16306 * References:
16307 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
16308 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
16309 *   http://url.spec.whatwg.org/#urlutils
16310 *   https://github.com/angular/angular.js/pull/2902
16311 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
16312 *
16313 * @kind function
16314 * @param {string} url The URL to be parsed.
16315 * @description Normalizes and parses a URL.
16316 * @returns {object} Returns the normalized URL as a dictionary.
16317 *
16318 *   | member name   | Description    |
16319 *   |---------------|----------------|
16320 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
16321 *   | protocol      | The protocol including the trailing colon                              |
16322 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
16323 *   | search        | The search params, minus the question mark                             |
16324 *   | hash          | The hash string, minus the hash symbol
16325 *   | hostname      | The hostname
16326 *   | port          | The port, without ":"
16327 *   | pathname      | The pathname, beginning with "/"
16328 *
16329 */
16330function urlResolve(url) {
16331  var href = url;
16332
16333  if (msie) {
16334    // Normalize before parse.  Refer Implementation Notes on why this is
16335    // done in two steps on IE.
16336    urlParsingNode.setAttribute("href", href);
16337    href = urlParsingNode.href;
16338  }
16339
16340  urlParsingNode.setAttribute('href', href);
16341
16342  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
16343  return {
16344    href: urlParsingNode.href,
16345    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
16346    host: urlParsingNode.host,
16347    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
16348    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
16349    hostname: urlParsingNode.hostname,
16350    port: urlParsingNode.port,
16351    pathname: (urlParsingNode.pathname.charAt(0) === '/')
16352      ? urlParsingNode.pathname
16353      : '/' + urlParsingNode.pathname
16354  };
16355}
16356
16357/**
16358 * Parse a request URL and determine whether this is a same-origin request as the application document.
16359 *
16360 * @param {string|object} requestUrl The url of the request as a string that will be resolved
16361 * or a parsed URL object.
16362 * @returns {boolean} Whether the request is for the same origin as the application document.
16363 */
16364function urlIsSameOrigin(requestUrl) {
16365  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
16366  return (parsed.protocol === originUrl.protocol &&
16367          parsed.host === originUrl.host);
16368}
16369
16370/**
16371 * @ngdoc service
16372 * @name $window
16373 *
16374 * @description
16375 * A reference to the browser's `window` object. While `window`
16376 * is globally available in JavaScript, it causes testability problems, because
16377 * it is a global variable. In angular we always refer to it through the
16378 * `$window` service, so it may be overridden, removed or mocked for testing.
16379 *
16380 * Expressions, like the one defined for the `ngClick` directive in the example
16381 * below, are evaluated with respect to the current scope.  Therefore, there is
16382 * no risk of inadvertently coding in a dependency on a global value in such an
16383 * expression.
16384 *
16385 * @example
16386   <example module="windowExample">
16387     <file name="index.html">
16388       <script>
16389         angular.module('windowExample', [])
16390           .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
16391             $scope.greeting = 'Hello, World!';
16392             $scope.doGreeting = function(greeting) {
16393               $window.alert(greeting);
16394             };
16395           }]);
16396       </script>
16397       <div ng-controller="ExampleController">
16398         <input type="text" ng-model="greeting" />
16399         <button ng-click="doGreeting(greeting)">ALERT</button>
16400       </div>
16401     </file>
16402     <file name="protractor.js" type="protractor">
16403      it('should display the greeting in the input box', function() {
16404       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
16405       // If we click the button it will block the test runner
16406       // element(':button').click();
16407      });
16408     </file>
16409   </example>
16410 */
16411function $WindowProvider() {
16412  this.$get = valueFn(window);
16413}
16414
16415/* global currencyFilter: true,
16416 dateFilter: true,
16417 filterFilter: true,
16418 jsonFilter: true,
16419 limitToFilter: true,
16420 lowercaseFilter: true,
16421 numberFilter: true,
16422 orderByFilter: true,
16423 uppercaseFilter: true,
16424 */
16425
16426/**
16427 * @ngdoc provider
16428 * @name $filterProvider
16429 * @description
16430 *
16431 * Filters are just functions which transform input to an output. However filters need to be
16432 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
16433 * annotated with dependencies and is responsible for creating a filter function.
16434 *
16435 * ```js
16436 *   // Filter registration
16437 *   function MyModule($provide, $filterProvider) {
16438 *     // create a service to demonstrate injection (not always needed)
16439 *     $provide.value('greet', function(name){
16440 *       return 'Hello ' + name + '!';
16441 *     });
16442 *
16443 *     // register a filter factory which uses the
16444 *     // greet service to demonstrate DI.
16445 *     $filterProvider.register('greet', function(greet){
16446 *       // return the filter function which uses the greet service
16447 *       // to generate salutation
16448 *       return function(text) {
16449 *         // filters need to be forgiving so check input validity
16450 *         return text && greet(text) || text;
16451 *       };
16452 *     });
16453 *   }
16454 * ```
16455 *
16456 * The filter function is registered with the `$injector` under the filter name suffix with
16457 * `Filter`.
16458 *
16459 * ```js
16460 *   it('should be the same instance', inject(
16461 *     function($filterProvider) {
16462 *       $filterProvider.register('reverse', function(){
16463 *         return ...;
16464 *       });
16465 *     },
16466 *     function($filter, reverseFilter) {
16467 *       expect($filter('reverse')).toBe(reverseFilter);
16468 *     });
16469 * ```
16470 *
16471 *
16472 * For more information about how angular filters work, and how to create your own filters, see
16473 * {@link guide/filter Filters} in the Angular Developer Guide.
16474 */
16475
16476/**
16477 * @ngdoc service
16478 * @name $filter
16479 * @kind function
16480 * @description
16481 * Filters are used for formatting data displayed to the user.
16482 *
16483 * The general syntax in templates is as follows:
16484 *
16485 *         {{ expression [| filter_name[:parameter_value] ... ] }}
16486 *
16487 * @param {String} name Name of the filter function to retrieve
16488 * @return {Function} the filter function
16489 * @example
16490   <example name="$filter" module="filterExample">
16491     <file name="index.html">
16492       <div ng-controller="MainCtrl">
16493        <h3>{{ originalText }}</h3>
16494        <h3>{{ filteredText }}</h3>
16495       </div>
16496     </file>
16497
16498     <file name="script.js">
16499      angular.module('filterExample', [])
16500      .controller('MainCtrl', function($scope, $filter) {
16501        $scope.originalText = 'hello';
16502        $scope.filteredText = $filter('uppercase')($scope.originalText);
16503      });
16504     </file>
16505   </example>
16506  */
16507$FilterProvider.$inject = ['$provide'];
16508function $FilterProvider($provide) {
16509  var suffix = 'Filter';
16510
16511  /**
16512   * @ngdoc method
16513   * @name $filterProvider#register
16514   * @param {string|Object} name Name of the filter function, or an object map of filters where
16515   *    the keys are the filter names and the values are the filter factories.
16516   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
16517   *    of the registered filter instances.
16518   */
16519  function register(name, factory) {
16520    if (isObject(name)) {
16521      var filters = {};
16522      forEach(name, function(filter, key) {
16523        filters[key] = register(key, filter);
16524      });
16525      return filters;
16526    } else {
16527      return $provide.factory(name + suffix, factory);
16528    }
16529  }
16530  this.register = register;
16531
16532  this.$get = ['$injector', function($injector) {
16533    return function(name) {
16534      return $injector.get(name + suffix);
16535    };
16536  }];
16537
16538  ////////////////////////////////////////
16539
16540  /* global
16541    currencyFilter: false,
16542    dateFilter: false,
16543    filterFilter: false,
16544    jsonFilter: false,
16545    limitToFilter: false,
16546    lowercaseFilter: false,
16547    numberFilter: false,
16548    orderByFilter: false,
16549    uppercaseFilter: false,
16550  */
16551
16552  register('currency', currencyFilter);
16553  register('date', dateFilter);
16554  register('filter', filterFilter);
16555  register('json', jsonFilter);
16556  register('limitTo', limitToFilter);
16557  register('lowercase', lowercaseFilter);
16558  register('number', numberFilter);
16559  register('orderBy', orderByFilter);
16560  register('uppercase', uppercaseFilter);
16561}
16562
16563/**
16564 * @ngdoc filter
16565 * @name filter
16566 * @kind function
16567 *
16568 * @description
16569 * Selects a subset of items from `array` and returns it as a new array.
16570 *
16571 * @param {Array} array The source array.
16572 * @param {string|Object|function()} expression The predicate to be used for selecting items from
16573 *   `array`.
16574 *
16575 *   Can be one of:
16576 *
16577 *   - `string`: The string is used for matching against the contents of the `array`. All strings or
16578 *     objects with string properties in `array` that match this string will be returned. This also
16579 *     applies to nested object properties.
16580 *     The predicate can be negated by prefixing the string with `!`.
16581 *
16582 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
16583 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
16584 *     which have property `name` containing "M" and property `phone` containing "1". A special
16585 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
16586 *     property of the object or its nested object properties. That's equivalent to the simple
16587 *     substring match with a `string` as described above. The predicate can be negated by prefixing
16588 *     the string with `!`.
16589 *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
16590 *     not containing "M".
16591 *
16592 *     Note that a named property will match properties on the same level only, while the special
16593 *     `$` property will match properties on the same level or deeper. E.g. an array item like
16594 *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
16595 *     **will** be matched by `{$: 'John'}`.
16596 *
16597 *   - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
16598 *     function is called for each element of `array`. The final result is an array of those
16599 *     elements that the predicate returned true for.
16600 *
16601 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
16602 *     determining if the expected value (from the filter expression) and actual value (from
16603 *     the object in the array) should be considered a match.
16604 *
16605 *   Can be one of:
16606 *
16607 *   - `function(actual, expected)`:
16608 *     The function will be given the object value and the predicate value to compare and
16609 *     should return true if both values should be considered equal.
16610 *
16611 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
16612 *     This is essentially strict comparison of expected and actual.
16613 *
16614 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
16615 *     insensitive way.
16616 *
16617 * @example
16618   <example>
16619     <file name="index.html">
16620       <div ng-init="friends = [{name:'John', phone:'555-1276'},
16621                                {name:'Mary', phone:'800-BIG-MARY'},
16622                                {name:'Mike', phone:'555-4321'},
16623                                {name:'Adam', phone:'555-5678'},
16624                                {name:'Julie', phone:'555-8765'},
16625                                {name:'Juliette', phone:'555-5678'}]"></div>
16626
16627       Search: <input ng-model="searchText">
16628       <table id="searchTextResults">
16629         <tr><th>
16629Name</th><th>Phone</th></tr>
16630         <tr ng-repeat="friend in friends | filter:searchText">
16631           <td>{{friend.name}}</td>
16632           <td>{{friend.phone}}</td>
16633         </tr>
16634       </table>
16635       <hr>
16636       Any: <input ng-model="search.$"> <br>
16637       Name only <input ng-model="search.name"><br>
16638       Phone only <input ng-model="search.phone"><br>
16639       Equality <input type="checkbox" ng-model="strict"><br>
16640       <table id="searchObjResults">
16641         <tr><th>Name</th><th>Phone</th></tr>
16642         <tr ng-repeat="friendObj in friends | filter:search:strict">
16643           <td>{{friendObj.name}}</td>
16644           <td>{{friendObj.phone}}</td>
16645         </tr>
16646       </table>
16647     </file>
16648     <file name="protractor.js" type="protractor">
16649       var expectFriendNames = function(expectedNames, key) {
16650         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
16651           arr.forEach(function(wd, i) {
16652             expect(wd.getText()).toMatch(expectedNames[i]);
16653           });
16654         });
16655       };
16656
16657       it('should search across all fields when filtering with a string', function() {
16658         var searchText = element(by.model('searchText'));
16659         searchText.clear();
16660         searchText.sendKeys('m');
16661         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
16662
16663         searchText.clear();
16664         searchText.sendKeys('76');
16665         expectFriendNames(['John', 'Julie'], 'friend');
16666       });
16667
16668       it('should search in specific fields when filtering with a predicate object', function() {
16669         var searchAny = element(by.model('search.$'));
16670         searchAny.clear();
16671         searchAny.sendKeys('i');
16672         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
16673       });
16674       it('should use a equal comparison when comparator is true', function() {
16675         var searchName = element(by.model('search.name'));
16676         var strict = element(by.model('strict'));
16677         searchName.clear();
16678         searchName.sendKeys('Julie');
16679         strict.click();
16680         expectFriendNames(['Julie'], 'friendObj');
16681       });
16682     </file>
16683   </example>
16684 */
16685function filterFilter() {
16686  return function(array, expression, comparator) {
16687    if (!isArray(array)) return array;
16688
16689    var predicateFn;
16690    var matchAgainstAnyProp;
16691
16692    switch (typeof expression) {
16693      case 'function':
16694        predicateFn = expression;
16695        break;
16696      case 'boolean':
16697      case 'number':
16698      case 'string':
16699        matchAgainstAnyProp = true;
16700        //jshint -W086
16701      case 'object':
16702        //jshint +W086
16703        predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
16704        break;
16705      default:
16706        return array;
16707    }
16708
16709    return array.filter(predicateFn);
16710  };
16711}
16712
16713// Helper functions for `filterFilter`
16714function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
16715  var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
16716  var predicateFn;
16717
16718  if (comparator === true) {
16719    comparator = equals;
16720  } else if (!isFunction(comparator)) {
16721    comparator = function(actual, expected) {
16722      if (isObject(actual) || isObject(expected)) {
16723        // Prevent an object to be considered equal to a string like `'[object'`
16724        return false;
16725      }
16726
16727      actual = lowercase('' + actual);
16728      expected = lowercase('' + expected);
16729      return actual.indexOf(expected) !== -1;
16730    };
16731  }
16732
16733  predicateFn = function(item) {
16734    if (shouldMatchPrimitives && !isObject(item)) {
16735      return deepCompare(item, expression.$, comparator, false);
16736    }
16737    return deepCompare(item, expression, comparator, matchAgainstAnyProp);
16738  };
16739
16740  return predicateFn;
16741}
16742
16743function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
16744  var actualType = typeof actual;
16745  var expectedType = typeof expected;
16746
16747  if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
16748    return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
16749  } else if (isArray(actual)) {
16750    // In case `actual` is an array, consider it a match
16751    // if ANY of it's items matches `expected`
16752    return actual.some(function(item) {
16753      return deepCompare(item, expected, comparator, matchAgainstAnyProp);
16754    });
16755  }
16756
16757  switch (actualType) {
16758    case 'object':
16759      var key;
16760      if (matchAgainstAnyProp) {
16761        for (key in actual) {
16762          if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
16763            return true;
16764          }
16765        }
16766        return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
16767      } else if (expectedType === 'object') {
16768        for (key in expected) {
16769          var expectedVal = expected[key];
16770          if (isFunction(expectedVal)) {
16771            continue;
16772          }
16773
16774          var matchAnyProperty = key === '$';
16775          var actualVal = matchAnyProperty ? actual : actual[key];
16776          if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
16777            return false;
16778          }
16779        }
16780        return true;
16781      } else {
16782        return comparator(actual, expected);
16783      }
16784      break;
16785    case 'function':
16786      return false;
16787    default:
16788      return comparator(actual, expected);
16789  }
16790}
16791
16792/**
16793 * @ngdoc filter
16794 * @name currency
16795 * @kind function
16796 *
16797 * @description
16798 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
16799 * symbol for current locale is used.
16800 *
16801 * @param {number} amount Input to filter.
16802 * @param {string=} symbol Currency symbol or identifier to be displayed.
16803 * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
16804 * @returns {string} Formatted number.
16805 *
16806 *
16807 * @example
16808   <example module="currencyExample">
16809     <file name="index.html">
16810       <script>
16811         angular.module('currencyExample', [])
16812           .controller('ExampleController', ['$scope', function($scope) {
16813             $scope.amount = 1234.56;
16814           }]);
16815       </script>
16816       <div ng-controller="ExampleController">
16817         <input type="number" ng-model="amount"> <br>
16818         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
16819         custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
16820         no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
16821       </div>
16822     </file>
16823     <file name="protractor.js" type="protractor">
16824       it('should init with 1234.56', function() {
16825         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
16826         expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
16827         expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
16828       });
16829       it('should update', function() {
16830         if (browser.params.browser == 'safari') {
16831           // Safari does not understand the minus key. See
16832           // https://github.com/angular/protractor/issues/481
16833           return;
16834         }
16835         element(by.model('amount')).clear();
16836         element(by.model('amount')).sendKeys('-1234');
16837         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
16838         expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
16839         expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
16840       });
16841     </file>
16842   </example>
16843 */
16844currencyFilter.$inject = ['$locale'];
16845function currencyFilter($locale) {
16846  var formats = $locale.NUMBER_FORMATS;
16847  return function(amount, currencySymbol, fractionSize) {
16848    if (isUndefined(currencySymbol)) {
16849      currencySymbol = formats.CURRENCY_SYM;
16850    }
16851
16852    if (isUndefined(fractionSize)) {
16853      fractionSize = formats.PATTERNS[1].maxFrac;
16854    }
16855
16856    // if null or undefined pass it through
16857    return (amount == null)
16858        ? amount
16859        : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
16860            replace(/\u00A4/g, currencySymbol);
16861  };
16862}
16863
16864/**
16865 * @ngdoc filter
16866 * @name number
16867 * @kind function
16868 *
16869 * @description
16870 * Formats a number as text.
16871 *
16872 * If the input is not a number an empty string is returned.
16873 *
16874 * @param {number|string} number Number to format.
16875 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
16876 * If this is not provided then the fraction size is computed from the current locale's number
16877 * formatting pattern. In the case of the default locale, it will be 3.
16878 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
16879 *
16880 * @example
16881   <example module="numberFilterExample">
16882     <file name="index.html">
16883       <script>
16884         angular.module('numberFilterExample', [])
16885           .controller('ExampleController', ['$scope', function($scope) {
16886             $scope.val = 1234.56789;
16887           }]);
16888       </script>
16889       <div ng-controller="ExampleController">
16890         Enter number: <input ng-model='val'><br>
16891         Default formatting: <span id='number-default'>{{val | number}}</span><br>
16892         No fractions: <span>{{val | number:0}}</span><br>
16893         Negative number: <span>{{-val | number:4}}</span>
16894       </div>
16895     </file>
16896     <file name="protractor.js" type="protractor">
16897       it('should format numbers', function() {
16898         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
16899         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
16900         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
16901       });
16902
16903       it('should update', function() {
16904         element(by.model('val')).clear();
16905         element(by.model('val')).sendKeys('3374.333');
16906         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
16907         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
16908         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
16909      });
16910     </file>
16911   </example>
16912 */
16913
16914
16915numberFilter.$inject = ['$locale'];
16916function numberFilter($locale) {
16917  var formats = $locale.NUMBER_FORMATS;
16918  return function(number, fractionSize) {
16919
16920    // if null or undefined pass it through
16921    return (number == null)
16922        ? number
16923        : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
16924                       fractionSize);
16925  };
16926}
16927
16928var DECIMAL_SEP = '.';
16929function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16930  if (!isFinite(number) || isObject(number)) return '';
16931
16932  var isNegative = number < 0;
16933  number = Math.abs(number);
16934  var numStr = number + '',
16935      formatedText = '',
16936      parts = [];
16937
16938  var hasExponent = false;
16939  if (numStr.indexOf('e') !== -1) {
16940    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
16941    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
16942      number = 0;
16943    } else {
16944      formatedText = numStr;
16945      hasExponent = true;
16946    }
16947  }
16948
16949  if (!hasExponent) {
16950    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
16951
16952    // determine fractionSize if it is not specified
16953    if (isUndefined(fractionSize)) {
16954      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
16955    }
16956
16957    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
16958    // inspired by:
16959    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
16960    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
16961
16962    var fraction = ('' + number).split(DECIMAL_SEP);
16963    var whole = fraction[0];
16964    fraction = fraction[1] || '';
16965
16966    var i, pos = 0,
16967        lgroup = pattern.lgSize,
16968        group = pattern.gSize;
16969
16970    if (whole.length >= (lgroup + group)) {
16971      pos = whole.length - lgroup;
16972      for (i = 0; i < pos; i++) {
16973        if ((pos - i) % group === 0 && i !== 0) {
16974          formatedText += groupSep;
16975        }
16976        formatedText += whole.charAt(i);
16977      }
16978    }
16979
16980    for (i = pos; i < whole.length; i++) {
16981      if ((whole.length - i) % lgroup === 0 && i !== 0) {
16982        formatedText += groupSep;
16983      }
16984      formatedText += whole.charAt(i);
16985    }
16986
16987    // format fraction part.
16988    while (fraction.length < fractionSize) {
16989      fraction += '0';
16990    }
16991
16992    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
16993  } else {
16994    if (fractionSize > 0 && number < 1) {
16995      formatedText = number.toFixed(fractionSize);
16996      number = parseFloat(formatedText);
16997    }
16998  }
16999
17000  if (number === 0) {
17001    isNegative = false;
17002  }
17003
17004  parts.push(isNegative ? pattern.negPre : pattern.posPre,
17005             formatedText,
17006             isNegative ? pattern.negSuf : pattern.posSuf);
17007  return parts.join('');
17008}
17009
17010function padNumber(num, digits, trim) {
17011  var neg = '';
17012  if (num < 0) {
17013    neg =  '-';
17014    num = -num;
17015  }
17016  num = '' + num;
17017  while (num.length < digits) num = '0' + num;
17018  if (trim)
17019    num = num.substr(num.length - digits);
17020  return neg + num;
17021}
17022
17023
17024function dateGetter(name, size, offset, trim) {
17025  offset = offset || 0;
17026  return function(date) {
17027    var value = date['get' + name]();
17028    if (offset > 0 || value > -offset)
17029      value += offset;
17030    if (value === 0 && offset == -12) value = 12;
17031    return padNumber(value, size, trim);
17032  };
17033}
17034
17035function dateStrGetter(name, shortForm) {
17036  return function(date, formats) {
17037    var value = date['get' + name]();
17038    var get = uppercase(shortForm ? ('SHORT' + name) : name);
17039
17040    return formats[get][value];
17041  };
17042}
17043
17044function timeZoneGetter(date) {
17045  var zone = -1 * date.getTimezoneOffset();
17046  var paddedZone = (zone >= 0) ? "+" : "";
17047
17048  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
17049                padNumber(Math.abs(zone % 60), 2);
17050
17051  return paddedZone;
17052}
17053
17054function getFirstThursdayOfYear(year) {
17055    // 0 = index of January
17056    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
17057    // 4 = index of Thursday (+1 to account for 1st = 5)
17058    // 11 = index of *next* Thursday (+1 account for 1st = 12)
17059    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
17060}
17061
17062function getThursdayThisWeek(datetime) {
17063    return new Date(datetime.getFullYear(), datetime.getMonth(),
17064      // 4 = index of Thursday
17065      datetime.getDate() + (4 - datetime.getDay()));
17066}
17067
17068function weekGetter(size) {
17069   return function(date) {
17070      var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
17071         thisThurs = getThursdayThisWeek(date);
17072
17073      var diff = +thisThurs - +firstThurs,
17074         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
17075
17076      return padNumber(result, size);
17077   };
17078}
17079
17080function ampmGetter(date, formats) {
17081  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
17082}
17083
17084var DATE_FORMATS = {
17085  yyyy: dateGetter('FullYear', 4),
17086    yy: dateGetter('FullYear', 2, 0, true),
17087     y: dateGetter('FullYear', 1),
17088  MMMM: dateStrGetter('Month'),
17089   MMM: dateStrGetter('Month', true),
17090    MM: dateGetter('Month', 2, 1),
17091     M: dateGetter('Month', 1, 1),
17092    dd: dateGetter('Date', 2),
17093     d: dateGetter('Date', 1),
17094    HH: dateGetter('Hours', 2),
17095     H: dateGetter('Hours', 1),
17096    hh: dateGetter('Hours', 2, -12),
17097     h: dateGetter('Hours', 1, -12),
17098    mm: dateGetter('Minutes', 2),
17099     m: dateGetter('Minutes', 1),
17100    ss: dateGetter('Seconds', 2),
17101     s: dateGetter('Seconds', 1),
17102     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
17103     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
17104   sss: dateGetter('Milliseconds', 3),
17105  EEEE: dateStrGetter('Day'),
17106   EEE: dateStrGetter('Day', true),
17107     a: ampmGetter,
17108     Z: timeZoneGetter,
17109    ww: weekGetter(2),
17110     w: weekGetter(1)
17111};
17112
17113var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,
17114    NUMBER_STRING = /^\-?\d+$/;
17115
17116/**
17117 * @ngdoc filter
17118 * @name date
17119 * @kind function
17120 *
17121 * @description
17122 *   Formats `date` to a string based on the requested `format`.
17123 *
17124 *   `format` string can be composed of the following elements:
17125 *
17126 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
17127 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
17128 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
17129 *   * `'MMMM'`: Month in year (January-December)
17130 *   * `'MMM'`: Month in year (Jan-Dec)
17131 *   * `'MM'`: Month in year, padded (01-12)
17132 *   * `'M'`: Month in year (1-12)
17133 *   * `'dd'`: Day in month, padded (01-31)
17134 *   * `'d'`: Day in month (1-31)
17135 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
17136 *   * `'EEE'`: Day in Week, (Sun-Sat)
17137 *   * `'HH'`: Hour in day, padded (00-23)
17138 *   * `'H'`: Hour in day (0-23)
17139 *   * `'hh'`: Hour in AM/PM, padded (01-12)
17140 *   * `'h'`: Hour in AM/PM, (1-12)
17141 *   * `'mm'`: Minute in hour, padded (00-59)
17142 *   * `'m'`: Minute in hour (0-59)
17143 *   * `'ss'`: Second in minute, padded (00-59)
17144 *   * `'s'`: Second in minute (0-59)
17145 *   * `'sss'`: Millisecond in second, padded (000-999)
17146 *   * `'a'`: AM/PM marker
17147 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
17148 *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
17149 *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
17150 *
17151 *   `format` string can also be one of the following predefined
17152 *   {@link guide/i18n localizable formats}:
17153 *
17154 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
17155 *     (e.g. Sep 3, 2010 12:05:08 PM)
17156 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
17157 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
17158 *     (e.g. Friday, September 3, 2010)
17159 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
17160 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
17161 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
17162 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
17163 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
17164 *
17165 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
17166 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
17167 *   (e.g. `"h 'o''clock'"`).
17168 *
17169 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
17170 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
17171 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
17172 *    specified in the string input, the time is considered to be in the local timezone.
17173 * @param {string=} format Formatting rules (see Description). If not specified,
17174 *    `mediumDate` is used.
17175 * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported.
17176 *    If not specified, the timezone of the browser will be used.
17177 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
17178 *
17179 * @example
17180   <example>
17181     <file name="index.html">
17182       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
17183           <span>{{1288323623006 | date:'medium'}}</span><br>
17184       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
17185          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
17186       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
17187          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
17188       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
17189          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
17190     </file>
17191     <file name="protractor.js" type="protractor">
17192       it('should format date', function() {
17193         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
17194            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
17195         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
17196            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
17197         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
17198            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
17199         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
17200            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
17201       });
17202     </file>
17203   </example>
17204 */
17205dateFilter.$inject = ['$locale'];
17206function dateFilter($locale) {
17207
17208
17209  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
17210                     // 1        2       3         4          5          6          7          8  9     10      11
17211  function jsonStringToDate(string) {
17212    var match;
17213    if (match = string.match(R_ISO8601_STR)) {
17214      var date = new Date(0),
17215          tzHour = 0,
17216          tzMin  = 0,
17217          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
17218          timeSetter = match[8] ? date.setUTCHours : date.setHours;
17219
17220      if (match[9]) {
17221        tzHour = int(match[9] + match[10]);
17222        tzMin = int(match[9] + match[11]);
17223      }
17224      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
17225      var h = int(match[4] || 0) - tzHour;
17226      var m = int(match[5] || 0) - tzMin;
17227      var s = int(match[6] || 0);
17228      var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
17229      timeSetter.call(date, h, m, s, ms);
17230      return date;
17231    }
17232    return string;
17233  }
17234
17235
17236  return function(date, format, timezone) {
17237    var text = '',
17238        parts = [],
17239        fn, match;
17240
17241    format = format || 'mediumDate';
17242    format = $locale.DATETIME_FORMATS[format] || format;
17243    if (isString(date)) {
17244      date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
17245    }
17246
17247    if (isNumber(date)) {
17248      date = new Date(date);
17249    }
17250
17251    if (!isDate(date)) {
17252      return date;
17253    }
17254
17255    while (format) {
17256      match = DATE_FORMATS_SPLIT.exec(format);
17257      if (match) {
17258        parts = concat(parts, match, 1);
17259        format = parts.pop();
17260      } else {
17261        parts.push(format);
17262        format = null;
17263      }
17264    }
17265
17266    if (timezone && timezone === 'UTC') {
17267      date = new Date(date.getTime());
17268      date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
17269    }
17270    forEach(parts, function(value) {
17271      fn = DATE_FORMATS[value];
17272      text += fn ? fn(date, $locale.DATETIME_FORMATS)
17273                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
17274    });
17275
17276    return text;
17277  };
17278}
17279
17280
17281/**
17282 * @ngdoc filter
17283 * @name json
17284 * @kind function
17285 *
17286 * @description
17287 *   Allows you to convert a JavaScript object into JSON string.
17288 *
17289 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
17290 *   the binding is automatically converted to JSON.
17291 *
17292 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
17293 * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
17294 * @returns {string} JSON string.
17295 *
17296 *
17297 * @example
17298   <example>
17299     <file name="index.html">
17300       <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
17301       <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
17302     </file>
17303     <file name="protractor.js" type="protractor">
17304       it('should jsonify filtered objects', function() {
17305         expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
17306         expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
17307       });
17308     </file>
17309   </example>
17310 *
17311 */
17312function jsonFilter() {
17313  return function(object, spacing) {
17314    if (isUndefined(spacing)) {
17315        spacing = 2;
17316    }
17317    return toJson(object, spacing);
17318  };
17319}
17320
17321
17322/**
17323 * @ngdoc filter
17324 * @name lowercase
17325 * @kind function
17326 * @description
17327 * Converts string to lowercase.
17328 * @see angular.lowercase
17329 */
17330var lowercaseFilter = valueFn(lowercase);
17331
17332
17333/**
17334 * @ngdoc filter
17335 * @name uppercase
17336 * @kind function
17337 * @description
17338 * Converts string to uppercase.
17339 * @see angular.uppercase
17340 */
17341var uppercaseFilter = valueFn(uppercase);
17342
17343/**
17344 * @ngdoc filter
17345 * @name limitTo
17346 * @kind function
17347 *
17348 * @description
17349 * Creates a new array or string containing only a specified number of elements. The elements
17350 * are taken from either the beginning or the end of the source array, string or number, as specified by
17351 * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
17352 * converted to a string.
17353 *
17354 * @param {Array|string|number} input Source array, string or number to be limited.
17355 * @param {string|number} limit The length of the returned array or string. If the `limit` number
17356 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
17357 *     If the number is negative, `limit` number  of items from the end of the source array/string
17358 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
17359 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
17360 *     had less than `limit` elements.
17361 *
17362 * @example
17363   <example module="limitToExample">
17364     <file name="index.html">
17365       <script>
17366         angular.module('limitToExample', [])
17367           .controller('ExampleController', ['$scope', function($scope) {
17368             $scope.numbers = [1,2,3,4,5,6,7,8,9];
17369             $scope.letters = "abcdefghi";
17370             $scope.longNumber = 2345432342;
17371             $scope.numLimit = 3;
17372             $scope.letterLimit = 3;
17373             $scope.longNumberLimit = 3;
17374           }]);
17375       </script>
17376       <div ng-controller="ExampleController">
17377         Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
17378         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
17379         Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
17380         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
17381         Limit {{longNumber}} to: <input type="number" step="1" ng-model="longNumberLimit">
17382         <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
17383       </div>
17384     </file>
17385     <file name="protractor.js" type="protractor">
17386       var numLimitInput = element(by.model('numLimit'));
17387       var letterLimitInput = element(by.model('letterLimit'));
17388       var longNumberLimitInput = element(by.model('longNumberLimit'));
17389       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
17390       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
17391       var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
17392
17393       it('should limit the number array to first three items', function() {
17394         expect(numLimitInput.getAttribute('value')).toBe('3');
17395         expect(letterLimitInput.getAttribute('value')).toBe('3');
17396         expect(longNumberLimitInput.getAttribute('value')).toBe('3');
17397         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
17398         expect(limitedLetters.getText()).toEqual('Output letters: abc');
17399         expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
17400       });
17401
17402       // There is a bug in safari and protractor that doesn't like the minus key
17403       // it('should update the output when -3 is entered', function() {
17404       //   numLimitInput.clear();
17405       //   numLimitInput.sendKeys('-3');
17406       //   letterLimitInput.clear();
17407       //   letterLimitInput.sendKeys('-3');
17408       //   longNumberLimitInput.clear();
17409       //   longNumberLimitInput.sendKeys('-3');
17410       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
17411       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
17412       //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
17413       // });
17414
17415       it('should not exceed the maximum size of input array', function() {
17416         numLimitInput.clear();
17417         numLimitInput.sendKeys('100');
17418         letterLimitInput.clear();
17419         letterLimitInput.sendKeys('100');
17420         longNumberLimitInput.clear();
17421         longNumberLimitInput.sendKeys('100');
17422         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
17423         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
17424         expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
17425       });
17426     </file>
17427   </example>
17428*/
17429function limitToFilter() {
17430  return function(input, limit) {
17431    if (isNumber(input)) input = input.toString();
17432    if (!isArray(input) && !isString(input)) return input;
17433
17434    if (Math.abs(Number(limit)) === Infinity) {
17435      limit = Number(limit);
17436    } else {
17437      limit = int(limit);
17438    }
17439
17440    //NaN check on limit
17441    if (limit) {
17442      return limit > 0 ? input.slice(0, limit) : input.slice(limit);
17443    } else {
17444      return isString(input) ? "" : [];
17445    }
17446  };
17447}
17448
17449/**
17450 * @ngdoc filter
17451 * @name orderBy
17452 * @kind function
17453 *
17454 * @description
17455 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
17456 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
17457 * correctly, make sure they are actually being saved as numbers and not strings.
17458 *
17459 * @param {Array} array The array to sort.
17460 * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
17461 *    used by the comparator to determine the order of elements.
17462 *
17463 *    Can be one of:
17464 *
17465 *    - `function`: Getter function. The result of this function will be sorted using the
17466 *      `<`, `=`, `>` operator.
17467 *    - `string`: An Angular expression. The result of this expression is used to compare elements
17468 *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
17469 *      3 first characters of a property called `name`). The result of a constant expression
17470 *      is interpreted as a property name to be used in comparisons (for example `"special name"`
17471 *      to sort object by the value of their `special name` property). An expression can be
17472 *      optionally prefixed with `+` or `-` to control ascending or descending sort order
17473 *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
17474 *      element itself is used to compare where sorting.
17475 *    - `Array`: An array of function or string predicates. The first predicate in the array
17476 *      is used for sorting, but when two items are equivalent, the next predicate is used.
17477 *
17478 *    If the predicate is missing or empty then it defaults to `'+'`.
17479 *
17480 * @param {boolean=} reverse Reverse the order of the array.
17481 * @returns {Array} Sorted copy of the source array.
17482 *
17483 * @example
17484   <example module="orderByExample">
17485     <file name="index.html">
17486       <script>
17487         angular.module('orderByExample', [])
17488           .controller('ExampleController', ['$scope', function($scope) {
17489             $scope.friends =
17490                 [{name:'John', phone:'555-1212', age:10},
17491                  {name:'Mary', phone:'555-9876', age:19},
17492                  {name:'Mike', phone:'555-4321', age:21},
17493                  {name:'Adam', phone:'555-5678', age:35},
17494                  {name:'Julie', phone:'555-8765', age:29}];
17495             $scope.predicate = '-age';
17496           }]);
17497       </script>
17498       <div ng-controller="ExampleController">
17499         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
17500         <hr/>
17501         [ <a href="" ng-click="predicate=''">unsorted</a> ]
17502         <table class="friend">
17503           <tr>
17504             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
17505                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
17506             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
17507             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
17508           </tr>
17509           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
17510             <td>{{friend.name}}</td>
17511             <td>{{friend.phone}}</td>
17512             <td>{{friend.age}}</td>
17513           </tr>
17514         </table>
17515       </div>
17516     </file>
17517   </example>
17518 *
17519 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
17520 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
17521 * desired parameters.
17522 *
17523 * Example:
17524 *
17525 * @example
17526  <example module="orderByExample">
17527    <file name="index.html">
17528      <div ng-controller="ExampleController">
17529        <table class="friend">
17530          <tr>
17531            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
17532              (<a href="" ng-click="order('-name',false)">^</a>)</th>
17533            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
17534            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
17535          </tr>
17536          <tr ng-repeat="friend in friends">
17537            <td>{{friend.name}}</td>
17538            <td>{{friend.phone}}</td>
17539            <td>{{friend.age}}</td>
17540          </tr>
17541        </table>
17542      </div>
17543    </file>
17544
17545    <file name="script.js">
17546      angular.module('orderByExample', [])
17547        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
17548          var orderBy = $filter('orderBy');
17549          $scope.friends = [
17550            { name: 'John',    phone: '555-1212',    age: 10 },
17551            { name: 'Mary',    phone: '555-9876',    age: 19 },
17552            { name: 'Mike',    phone: '555-4321',    age: 21 },
17553            { name: 'Adam',    phone: '555-5678',    age: 35 },
17554            { name: 'Julie',   phone: '555-8765',    age: 29 }
17555          ];
17556          $scope.order = function(predicate, reverse) {
17557            $scope.friends = orderBy($scope.friends, predicate, reverse);
17558          };
17559          $scope.order('-age',false);
17560        }]);
17561    </file>
17562</example>
17563 */
17564orderByFilter.$inject = ['$parse'];
17565function orderByFilter($parse) {
17566  return function(array, sortPredicate, reverseOrder) {
17567    if (!(isArrayLike(array))) return array;
17568    sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
17569    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
17570    sortPredicate = sortPredicate.map(function(predicate) {
17571      var descending = false, get = predicate || identity;
17572      if (isString(predicate)) {
17573        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
17574          descending = predicate.charAt(0) == '-';
17575          predicate = predicate.substring(1);
17576        }
17577        if (predicate === '') {
17578          // Effectively no predicate was passed so we compare identity
17579          return reverseComparator(compare, descending);
17580        }
17581        get = $parse(predicate);
17582        if (get.constant) {
17583          var key = get();
17584          return reverseComparator(function(a, b) {
17585            return compare(a[key], b[key]);
17586          }, descending);
17587        }
17588      }
17589      return reverseComparator(function(a, b) {
17590        return compare(get(a),get(b));
17591      }, descending);
17592    });
17593    return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
17594
17595    function comparator(o1, o2) {
17596      for (var i = 0; i < sortPredicate.length; i++) {
17597        var comp = sortPredicate[i](o1, o2);
17598        if (comp !== 0) return comp;
17599      }
17600      return 0;
17601    }
17602    function reverseComparator(comp, descending) {
17603      return descending
17604          ? function(a, b) {return comp(b,a);}
17605          : comp;
17606    }
17607
17608    function isPrimitive(value) {
17609      switch (typeof value) {
17610        case 'number': /* falls through */
17611        case 'boolean': /* falls through */
17612        case 'string':
17613          return true;
17614        default:
17615          return false;
17616      }
17617    }
17618
17619    function objectToString(value) {
17620      if (value === null) return 'null';
17621      if (typeof value.valueOf === 'function') {
17622        value = value.valueOf();
17623        if (isPrimitive(value)) return value;
17624      }
17625      if (typeof value.toString === 'function') {
17626        value = value.toString();
17627        if (isPrimitive(value)) return value;
17628      }
17629      return '';
17630    }
17631
17632    function compare(v1, v2) {
17633      var t1 = typeof v1;
17634      var t2 = typeof v2;
17635      if (t1 === t2 && t1 === "object") {
17636        v1 = objectToString(v1);
17637        v2 = objectToString(v2);
17638      }
17639      if (t1 === t2) {
17640        if (t1 === "string") {
17641           v1 = v1.toLowerCase();
17642           v2 = v2.toLowerCase();
17643        }
17644        if (v1 === v2) return 0;
17645        return v1 < v2 ? -1 : 1;
17646      } else {
17647        return t1 < t2 ? -1 : 1;
17648      }
17649    }
17650  };
17651}
17652
17653function ngDirective(directive) {
17654  if (isFunction(directive)) {
17655    directive = {
17656      link: directive
17657    };
17658  }
17659  directive.restrict = directive.restrict || 'AC';
17660  return valueFn(directive);
17661}
17662
17663/**
17664 * @ngdoc directive
17665 * @name a
17666 * @restrict E
17667 *
17668 * @description
17669 * Modifies the default behavior of the html A tag so that the default action is prevented when
17670 * the href attribute is empty.
17671 *
17672 * This change permits the easy creation of action links with the `ngClick` directive
17673 * without changing the location or causing page reloads, e.g.:
17674 * `<a href="" ng-click="list.addItem()">Add Item</a>`
17675 */
17676var htmlAnchorDirective = valueFn({
17677  restrict: 'E',
17678  compile: function(element, attr) {
17679    if (!attr.href && !attr.xlinkHref && !attr.name) {
17680      return function(scope, element) {
17681        // If the linked element is not an anchor tag anymore, do nothing
17682        if (element[0].nodeName.toLowerCase() !== 'a') return;
17683
17684        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
17685        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
17686                   'xlink:href' : 'href';
17687        element.on('click', function(event) {
17688          // if we have no href url, then don't navigate anywhere.
17689          if (!element.attr(href)) {
17690            event.preventDefault();
17691          }
17692        });
17693      };
17694    }
17695  }
17696});
17697
17698/**
17699 * @ngdoc directive
17700 * @name ngHref
17701 * @restrict A
17702 * @priority 99
17703 *
17704 * @description
17705 * Using Angular markup like `{{hash}}` in an href attribute will
17706 * make the link go to the wrong URL if the user clicks it before
17707 * Angular has a chance to replace the `{{hash}}
17707` markup with its
17708 * value. Until Angular replaces the markup the link will be broken
17709 * and will most likely return a 404 error. The `ngHref` directive
17710 * solves this problem.
17711 *
17712 * The wrong way to write it:
17713 * ```html
17714 * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17715 * ```
17716 *
17717 * The correct way to write it:
17718 * ```html
17719 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
17720 * ```
17721 *
17722 * @element A
17723 * @param {template} ngHref any string which can contain `{{}}` markup.
17724 *
17725 * @example
17726 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
17727 * in links and their different behaviors:
17728    <example>
17729      <file name="index.html">
17730        <input ng-model="value" /><br />
17731        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
17732        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
17733        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
17734        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
17735        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
17736        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
17737      </file>
17738      <file name="protractor.js" type="protractor">
17739        it('should execute ng-click but not reload when href without value', function() {
17740          element(by.id('link-1')).click();
17741          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
17742          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
17743        });
17744
17745        it('should execute ng-click but not reload when href empty string', function() {
17746          element(by.id('link-2')).click();
17747          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
17748          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
17749        });
17750
17751        it('should execute ng-click and change url when ng-href specified', function() {
17752          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
17753
17754          element(by.id('link-3')).click();
17755
17756          // At this point, we navigate away from an Angular page, so we need
17757          // to use browser.driver to get the base webdriver.
17758
17759          browser.wait(function() {
17760            return browser.driver.getCurrentUrl().then(function(url) {
17761              return url.match(/\/123$/);
17762            });
17763          }, 5000, 'page should navigate to /123');
17764        });
17765
17766        xit('should execute ng-click but not reload when href empty string and name specified', function() {
17767          element(by.id('link-4')).click();
17768          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
17769          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
17770        });
17771
17772        it('should execute ng-click but not reload when no href but name specified', function() {
17773          element(by.id('link-5')).click();
17774          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
17775          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
17776        });
17777
17778        it('should only change url when only ng-href', function() {
17779          element(by.model('value')).clear();
17780          element(by.model('value')).sendKeys('6');
17781          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
17782
17783          element(by.id('link-6')).click();
17784
17785          // At this point, we navigate away from an Angular page, so we need
17786          // to use browser.driver to get the base webdriver.
17787          browser.wait(function() {
17788            return browser.driver.getCurrentUrl().then(function(url) {
17789              return url.match(/\/6$/);
17790            });
17791          }, 5000, 'page should navigate to /6');
17792        });
17793      </file>
17794    </example>
17795 */
17796
17797/**
17798 * @ngdoc directive
17799 * @name ngSrc
17800 * @restrict A
17801 * @priority 99
17802 *
17803 * @description
17804 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
17805 * work right: The browser will fetch from the URL with the literal
17806 * text `{{hash}}` until Angular replaces the expression inside
17807 * `{{hash}}`. The `ngSrc` directive solves this problem.
17808 *
17809 * The buggy way to write it:
17810 * ```html
17811 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
17812 * ```
17813 *
17814 * The correct way to write it:
17815 * ```html
17816 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
17817 * ```
17818 *
17819 * @element IMG
17820 * @param {template} ngSrc any string which can contain `{{}}` markup.
17821 */
17822
17823/**
17824 * @ngdoc directive
17825 * @name ngSrcset
17826 * @restrict A
17827 * @priority 99
17828 *
17829 * @description
17830 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
17831 * work right: The browser will fetch from the URL with the literal
17832 * text `{{hash}}` until Angular replaces the expression inside
17833 * `{{hash}}`. The `ngSrcset` directive solves this problem.
17834 *
17835 * The buggy way to write it:
17836 * ```html
17837 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
17838 * ```
17839 *
17840 * The correct way to write it:
17841 * ```html
17842 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
17843 * ```
17844 *
17845 * @element IMG
17846 * @param {template} ngSrcset any string which can contain `{{}}` markup.
17847 */
17848
17849/**
17850 * @ngdoc directive
17851 * @name ngDisabled
17852 * @restrict A
17853 * @priority 100
17854 *
17855 * @description
17856 *
17857 * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
17858 * ```html
17859 * <div ng-init="scope = { isDisabled: false }">
17860 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
17861 * </div>
17862 * ```
17863 *
17864 * The HTML specification does not require browsers to preserve the values of boolean attributes
17865 * such as disabled. (Their presence means true and their absence means false.)
17866 * If we put an Angular interpolation expression into such an attribute then the
17867 * binding information would be lost when the browser removes the attribute.
17868 * The `ngDisabled` directive solves this problem for the `disabled` attribute.
17869 * This complementary directive is not removed by the browser and so provides
17870 * a permanent reliable place to store the binding information.
17871 *
17872 * @example
17873    <example>
17874      <file name="index.html">
17875        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
17876        <button ng-model="button" ng-disabled="checked">Button</button>
17877      </file>
17878      <file name="protractor.js" type="protractor">
17879        it('should toggle button', function() {
17880          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
17881          element(by.model('checked')).click();
17882          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
17883        });
17884      </file>
17885    </example>
17886 *
17887 * @element INPUT
17888 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
17889 *     then special attribute "disabled" will be set on the element
17890 */
17891
17892
17893/**
17894 * @ngdoc directive
17895 * @name ngChecked
17896 * @restrict A
17897 * @priority 100
17898 *
17899 * @description
17900 * The HTML specification does not require browsers to preserve the values of boolean attributes
17901 * such as checked. (Their presence means true and their absence means false.)
17902 * If we put an Angular interpolation expression into such an attribute then the
17903 * binding information would be lost when the browser removes the attribute.
17904 * The `ngChecked` directive solves this problem for the `checked` attribute.
17905 * This complementary directive is not removed by the browser and so provides
17906 * a permanent reliable place to store the binding information.
17907 * @example
17908    <example>
17909      <file name="index.html">
17910        Check me to check both: <input type="checkbox" ng-model="master"><br/>
17911        <input id="checkSlave" type="checkbox" ng-checked="master">
17912      </file>
17913      <file name="protractor.js" type="protractor">
17914        it('should check both checkBoxes', function() {
17915          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
17916          element(by.model('master')).click();
17917          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
17918        });
17919      </file>
17920    </example>
17921 *
17922 * @element INPUT
17923 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
17924 *     then special attribute "checked" will be set on the element
17925 */
17926
17927
17928/**
17929 * @ngdoc directive
17930 * @name ngReadonly
17931 * @restrict A
17932 * @priority 100
17933 *
17934 * @description
17935 * The HTML specification does not require browsers to preserve the values of boolean attributes
17936 * such as readonly. (Their presence means true and their absence means false.)
17937 * If we put an Angular interpolation expression into such an attribute then the
17938 * binding information would be lost when the browser removes the attribute.
17939 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
17940 * This complementary directive is not removed by the browser and so provides
17941 * a permanent reliable place to store the binding information.
17942 * @example
17943    <example>
17944      <file name="index.html">
17945        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
17946        <input type="text" ng-readonly="checked" value="I'm Angular"/>
17947      </file>
17948      <file name="protractor.js" type="protractor">
17949        it('should toggle readonly attr', function() {
17950          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
17951          element(by.model('checked')).click();
17952          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
17953        });
17954      </file>
17955    </example>
17956 *
17957 * @element INPUT
17958 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
17959 *     then special attribute "readonly" will be set on the element
17960 */
17961
17962
17963/**
17964 * @ngdoc directive
17965 * @name ngSelected
17966 * @restrict A
17967 * @priority 100
17968 *
17969 * @description
17970 * The HTML specification does not require browsers to preserve the values of boolean attributes
17971 * such as selected. (Their presence means true and their absence means false.)
17972 * If we put an Angular interpolation expression into such an attribute then the
17973 * binding information would be lost when the browser removes the attribute.
17974 * The `ngSelected` directive solves this problem for the `selected` attribute.
17975 * This complementary directive is not removed by the browser and so provides
17976 * a permanent reliable place to store the binding information.
17977 *
17978 * @example
17979    <example>
17980      <file name="index.html">
17981        Check me to select: <input type="checkbox" ng-model="selected"><br/>
17982        <select>
17983          <option>Hello!</option>
17984          <option id="greet" ng-selected="selected">Greetings!</option>
17985        </select>
17986      </file>
17987      <file name="protractor.js" type="protractor">
17988        it('should select Greetings!', function() {
17989          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
17990          element(by.model('selected')).click();
17991          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
17992        });
17993      </file>
17994    </example>
17995 *
17996 * @element OPTION
17997 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
17998 *     then special attribute "selected" will be set on the element
17999 */
18000
18001/**
18002 * @ngdoc directive
18003 * @name ngOpen
18004 * @restrict A
18005 * @priority 100
18006 *
18007 * @description
18008 * The HTML specification does not require browsers to preserve the values of boolean attributes
18009 * such as open. (Their presence means true and their absence means false.)
18010 * If we put an Angular interpolation expression into such an attribute then the
18011 * binding information would be lost when the browser removes the attribute.
18012 * The `ngOpen` directive solves this problem for the `open` attribute.
18013 * This complementary directive is not removed by the browser and so provides
18014 * a permanent reliable place to store the binding information.
18015 * @example
18016     <example>
18017       <file name="index.html">
18018         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
18019         <details id="details" ng-open="open">
18020            <summary>Show/Hide me</summary>
18021         </details>
18022       </file>
18023       <file name="protractor.js" type="protractor">
18024         it('should toggle open', function() {
18025           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
18026           element(by.model('open')).click();
18027           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
18028         });
18029       </file>
18030     </example>
18031 *
18032 * @element DETAILS
18033 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
18034 *     then special attribute "open" will be set on the element
18035 */
18036
18037var ngAttributeAliasDirectives = {};
18038
18039
18040// boolean attrs are evaluated
18041forEach(BOOLEAN_ATTR, function(propName, attrName) {
18042  // binding to multiple is not supported
18043  if (propName == "multiple") return;
18044
18045  var normalized = directiveNormalize('ng-' + attrName);
18046  ngAttributeAliasDirectives[normalized] = function() {
18047    return {
18048      restrict: 'A',
18049      priority: 100,
18050      link: function(scope, element, attr) {
18051        scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
18052          attr.$set(attrName, !!value);
18053        });
18054      }
18055    };
18056  };
18057});
18058
18059// aliased input attrs are evaluated
18060forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
18061  ngAttributeAliasDirectives[ngAttr] = function() {
18062    return {
18063      priority: 100,
18064      link: function(scope, element, attr) {
18065        //special case ngPattern when a literal regular expression value
18066        //is used as the expression (this way we don't have to watch anything).
18067        if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
18068          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
18069          if (match) {
18070            attr.$set("ngPattern", new RegExp(match[1], match[2]));
18071            return;
18072          }
18073        }
18074
18075        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
18076          attr.$set(ngAttr, value);
18077        });
18078      }
18079    };
18080  };
18081});
18082
18083// ng-src, ng-srcset, ng-href are interpolated
18084forEach(['src', 'srcset', 'href'], function(attrName) {
18085  var normalized = directiveNormalize('ng-' + attrName);
18086  ngAttributeAliasDirectives[normalized] = function() {
18087    return {
18088      priority: 99, // it needs to run after the attributes are interpolated
18089      link: function(scope, element, attr) {
18090        var propName = attrName,
18091            name = attrName;
18092
18093        if (attrName === 'href' &&
18094            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
18095          name = 'xlinkHref';
18096          attr.$attr[name] = 'xlink:href';
18097          propName = null;
18098        }
18099
18100        attr.$observe(normalized, function(value) {
18101          if (!value) {
18102            if (attrName === 'href') {
18103              attr.$set(name, null);
18104            }
18105            return;
18106          }
18107
18108          attr.$set(name, value);
18109
18110          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
18111          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
18112          // to set the property as well to achieve the desired effect.
18113          // we use attr[attrName] value since $set can sanitize the url.
18114          if (msie && propName) element.prop(propName, attr[name]);
18115        });
18116      }
18117    };
18118  };
18119});
18120
18121/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
18122 */
18123var nullFormCtrl = {
18124  $addControl: noop,
18125  $$renameControl: nullFormRenameControl,
18126  $removeControl: noop,
18127  $setValidity: noop,
18128  $setDirty: noop,
18129  $setPristine: noop,
18130  $setSubmitted: noop
18131},
18132SUBMITTED_CLASS = 'ng-submitted';
18133
18134function nullFormRenameControl(control, name) {
18135  control.$name = name;
18136}
18137
18138/**
18139 * @ngdoc type
18140 * @name form.FormController
18141 *
18142 * @property {boolean} $pristine True if user has not interacted with the form yet.
18143 * @property {boolean} $dirty True if user has already interacted with the form.
18144 * @property {boolean} $valid True if all of the containing forms and controls are valid.
18145 * @property {boolean} $invalid True if at least one containing control or form is invalid.
18146 * @property {boolean} $submitted True if user has submitted the form even if its invalid.
18147 *
18148 * @property {Object} $error Is an object hash, containing references to controls or
18149 *  forms with failing validators, where:
18150 *
18151 *  - keys are validation tokens (error names),
18152 *  - values are arrays of controls or forms that have a failing validator for given error name.
18153 *
18154 *  Built-in validation tokens:
18155 *
18156 *  - `email`
18157 *  - `max`
18158 *  - `maxlength`
18159 *  - `min`
18160 *  - `minlength`
18161 *  - `number`
18162 *  - `pattern`
18163 *  - `required`
18164 *  - `url`
18165 *  - `date`
18166 *  - `datetimelocal`
18167 *  - `time`
18168 *  - `week`
18169 *  - `month`
18170 *
18171 * @description
18172 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
18173 * such as being valid/invalid or dirty/pristine.
18174 *
18175 * Each {@link ng.directive:form form} directive creates an instance
18176 * of `FormController`.
18177 *
18178 */
18179//asks for $scope to fool the BC controller module
18180FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
18181function FormController(element, attrs, $scope, $animate, $interpolate) {
18182  var form = this,
18183      controls = [];
18184
18185  var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
18186
18187  // init state
18188  form.$error = {};
18189  form.$$success = {};
18190  form.$pending = undefined;
18191  form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
18192  form.$dirty = false;
18193  form.$pristine = true;
18194  form.$valid = true;
18195  form.$invalid = false;
18196  form.$submitted = false;
18197
18198  parentForm.$addControl(form);
18199
18200  /**
18201   * @ngdoc method
18202   * @name form.FormController#$rollbackViewValue
18203   *
18204   * @description
18205   * Rollback all form controls pending updates to the `$modelValue`.
18206   *
18207   * Updates may be pending by a debounced event or because the input is waiting for a some future
18208   * event defined in `ng-model-options`. This method is typically needed by the reset button of
18209   * a form that uses `ng-model-options` to pend updates.
18210   */
18211  form.$rollbackViewValue = function() {
18212    forEach(controls, function(control) {
18213      control.$rollbackViewValue();
18214    });
18215  };
18216
18217  /**
18218   * @ngdoc method
18219   * @name form.FormController#$commitViewValue
18220   *
18221   * @description
18222   * Commit all form controls pending updates to the `$modelValue`.
18223   *
18224   * Updates may be pending by a debounced event or because the input is waiting for a some future
18225   * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
18226   * usually handles calling this in response to input events.
18227   */
18228  form.$commitViewValue = function() {
18229    forEach(controls, function(control) {
18230      control.$commitViewValue();
18231    });
18232  };
18233
18234  /**
18235   * @ngdoc method
18236   * @name form.FormController#$addControl
18237   *
18238   * @description
18239   * Register a control with the form.
18240   *
18241   * Input elements using ngModelController do this automatically when they are linked.
18242   */
18243  form.$addControl = function(control) {
18244    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
18245    // and not added to the scope.  Now we throw an error.
18246    assertNotHasOwnProperty(control.$name, 'input');
18247    controls.push(control);
18248
18249    if (control.$name) {
18250      form[control.$name] = control;
18251    }
18252  };
18253
18254  // Private API: rename a form control
18255  form.$$renameControl = function(control, newName) {
18256    var oldName = control.$name;
18257
18258    if (form[oldName] === control) {
18259      delete form[oldName];
18260    }
18261    form[newName] = control;
18262    control.$name = newName;
18263  };
18264
18265  /**
18266   * @ngdoc method
18267   * @name form.FormController#$removeControl
18268   *
18269   * @description
18270   * Deregister a control from the form.
18271   *
18272   * Input elements using ngModelController do this automatically when they are destroyed.
18273   */
18274  form.$removeControl = function(control) {
18275    if (control.$name && form[control.$name] === control) {
18276      delete form[control.$name];
18277    }
18278    forEach(form.$pending, function(value, name) {
18279      form.$setValidity(name, null, control);
18280    });
18281    forEach(form.$error, function(value, name) {
18282      form.$setValidity(name, null, control);
18283    });
18284    forEach(form.$$success, function(value, name) {
18285      form.$setValidity(name, null, control);
18286    });
18287
18288    arrayRemove(controls, control);
18289  };
18290
18291
18292  /**
18293   * @ngdoc method
18294   * @name form.FormController#$setValidity
18295   *
18296   * @description
18297   * Sets the validity of a form control.
18298   *
18299   * This method will also propagate to parent forms.
18300   */
18301  addSetValidityMethod({
18302    ctrl: this,
18303    $element: element,
18304    set: function(object, property, controller) {
18305      var list = object[property];
18306      if (!list) {
18307        object[property] = [controller];
18308      } else {
18309        var index = list.indexOf(controller);
18310        if (index === -1) {
18311          list.push(controller);
18312        }
18313      }
18314    },
18315    unset: function(object, property, controller) {
18316      var list = object[property];
18317      if (!list) {
18318        return;
18319      }
18320      arrayRemove(list, controller);
18321      if (list.length === 0) {
18322        delete object[property];
18323      }
18324    },
18325    parentForm: parentForm,
18326    $animate: $animate
18327  });
18328
18329  /**
18330   * @ngdoc method
18331   * @name form.FormController#$setDirty
18332   *
18333   * @description
18334   * Sets the form to a dirty state.
18335   *
18336   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
18337   * state (ng-dirty class). This method will also propagate to parent forms.
18338   */
18339  form.$setDirty = function() {
18340    $animate.removeClass(element, PRISTINE_CLASS);
18341    $animate.addClass(element, DIRTY_CLASS);
18342    form.$dirty = true;
18343    form.$pristine = false;
18344    parentForm.$setDirty();
18345  };
18346
18347  /**
18348   * @ngdoc method
18349   * @name form.FormController#$setPristine
18350   *
18351   * @description
18352   * Sets the form to its pristine state.
18353   *
18354   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
18355   * state (ng-pristine class). This method will also propagate to all the controls contained
18356   * in this form.
18357   *
18358   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
18359   * saving or resetting it.
18360   */
18361  form.$setPristine = function() {
18362    $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
18363    form.$dirty = false;
18364    form.$pristine = true;
18365    form.$submitted = false;
18366    forEach(controls, function(control) {
18367      control.$setPristine();
18368    });
18369  };
18370
18371  /**
18372   * @ngdoc method
18373   * @name form.FormController#$setUntouched
18374   *
18375   * @description
18376   * Sets the form to its untouched state.
18377   *
18378   * This method can be called to remove the 'ng-touched' class and set the form controls to their
18379   * untouched state (ng-untouched class).
18380   *
18381   * Setting a form controls back to their untouched state is often useful when setting the form
18382   * back to its pristine state.
18383   */
18384  form.$setUntouched = function() {
18385    forEach(controls, function(control) {
18386      control.$setUntouched();
18387    });
18388  };
18389
18390  /**
18391   * @ngdoc method
18392   * @name form.FormController#$setSubmitted
18393   *
18394   * @description
18395   * Sets the form to its submitted state.
18396   */
18397  form.$setSubmitted = function() {
18398    $animate.addClass(element, SUBMITTED_CLASS);
18399    form.$submitted = true;
18400    parentForm.$setSubmitted();
18401  };
18402}
18403
18404/**
18405 * @ngdoc directive
18406 * @name ngForm
18407 * @restrict EAC
18408 *
18409 * @description
18410 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
18411 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
18412 * sub-group of controls needs to be determined.
18413 *
18414 * Note: the purpose of `ngForm` is to group controls,
18415 * but not to be a replacement for the `<form>` tag with all of its capabilities
18416 * (e.g. posting to the server, ...).
18417 *
18418 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
18419 *                       related scope, under this name.
18420 *
18421 */
18422
18423 /**
18424 * @ngdoc directive
18425 * @name form
18426 * @restrict E
18427 *
18428 * @description
18429 * Directive that instantiates
18430 * {@link form.FormController FormController}.
18431 *
18432 * If the `name` attribute is specified, the form controller is published onto the current scope under
18433 * this name.
18434 *
18435 * # Alias: {@link ng.directive:ngForm `ngForm`}
18436 *
18437 * In Angular forms can be nested. This means that the outer form is valid when all of the child
18438 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
18439 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
18440 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
18441 * using Angular validation directives in forms that are dynamically generated using the
18442 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
18443 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
18444 * `ngForm` directive and nest these in an outer `form` element.
18445 *
18446 *
18447 * # CSS classes
18448 *  - `ng-valid` is set if the form is valid.
18449 *  - `ng-invalid` is set if the form is invalid.
18450 *  - `ng-pristine` is set if the form is pristine.
18451 *  - `ng-dirty` is set if the form is dirty.
18452 *  - `ng-submitted` is set if the form was submitted.
18453 *
18454 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
18455 *
18456 *
18457 * # Submitting a form and preventing the default action
18458 *
18459 * Since the role of forms in client-side Angular applications is different than in classical
18460 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
18461 * page reload that sends the data to the server. Instead some javascript logic should be triggered
18462 * to handle the form submission in an application-specific way.
18463 *
18464 * For this reason, Angular prevents the default action (form submission to the server) unless the
18465 * `<form>` element has an `action` attribute specified.
18466 *
18467 * You can use one of the following two ways to specify what javascript method should be called when
18468 * a form is submitted:
18469 *
18470 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
18471 * - {@link ng.directive:ngClick ngClick} directive on the first
18472  *  button or input field of type submit (input[type=submit])
18473 *
18474 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
18475 * or {@link ng.directive:ngClick ngClick} directives.
18476 * This is because of the following form submission rules in the HTML specification:
18477 *
18478 * - If a form has only one input field then hitting enter in this field triggers form submit
18479 * (`ngSubmit`)
18480 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
18481 * doesn't trigger submit
18482 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
18483 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
18484 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
18485 *
18486 * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
18487 * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
18488 * to have access to the updated model.
18489 *
18490 * ## Animation Hooks
18491 *
18492 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
18493 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
18494 * other validations that are performed within the form. Animations in ngForm are similar to how
18495 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
18496 * as JS animations.
18497 *
18498 * The following example shows a simple way to utilize CSS transitions to style a form element
18499 * that has been rendered as invalid after it has been validated:
18500 *
18501 * <pre>
18502 * //be sure to include ngAnimate as a module to hook into more
18503 * //advanced animations
18504 * .my-form {
18505 *   transition:0.5s linear all;
18506 *   background: white;
18507 * }
18508 * .my-form.ng-invalid {
18509 *   background: red;
18510 *   color:white;
18511 * }
18512 * </pre>
18513 *
18514 * @example
18515    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
18516      <file name="index.html">
18517       <script>
18518         angular.module('formExample', [])
18519           .controller('FormController', ['$scope', function($scope) {
18520             $scope.userType = 'guest';
18521           }]);
18522       </script>
18523       <style>
18524        .my-form {
18525          -webkit-transition:all linear 0.5s;
18526          transition:all linear 0.5s;
18527          background: transparent;
18528        }
18529        .my-form.ng-invalid {
18530          background: red;
18531        }
18532       </style>
18533       <form name="myForm" ng-controller="FormController" class="my-form">
18534         userType: <input name="input" ng-model="userType" required>
18535         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
18536         <tt>userType = {{userType}}</tt><br>
18537         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
18538         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
18539         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
18540         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
18541        </form>
18542      </file>
18543      <file name="protractor.js" type="protractor">
18544        it('should initialize to model', function() {
18545          var userType = element(by.binding('userType'));
18546          var valid = element(by.binding('myForm.input.$valid'));
18547
18548          expect(userType.getText()).toContain('guest');
18549          expect(valid.getText()).toContain('true');
18550        });
18551
18552        it('should be invalid if empty', function() {
18553          var userType = element(by.binding('userType'));
18554          var valid = element(by.binding('myForm.input.$valid'));
18555          var userInput = element(by.model('userType'));
18556
18557          userInput.clear();
18558          userInput.sendKeys('');
18559
18560          expect(userType.getText()).toEqual('userType =');
18561          expect(valid.getText()).toContain('false');
18562        });
18563      </file>
18564    </example>
18565 *
18566 * @param {string=} name Name of the form. If specified, the form controller will be published into
18567 *                       related scope, under this name.
18568 */
18569var formDirectiveFactory = function(isNgForm) {
18570  return ['$timeout', function($timeout) {
18571    var formDirective = {
18572      name: 'form',
18573      restrict: isNgForm ? 'EAC' : 'E',
18574      controller: FormController,
18575      compile: function ngFormCompile(formElement) {
18576        // Setup initial state of the control
18577        formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
18578
18579        return {
18580          pre: function ngFormPreLink(scope, formElement, attr, controller) {
18581            // if `action` attr is not present on the form, prevent the default action (submission)
18582            if (!('action' in attr)) {
18583              // we can't use jq events because if a form is destroyed during submission the default
18584              // action is not prevented. see #1238
18585              //
18586              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
18587              // page reload if the form was destroyed by submission of the form via a click handler
18588              // on a button in the form. Looks like an IE9 specific bug.
18589              var handleFormSubmission = function(event) {
18590                scope.$apply(function() {
18591                  controller.$commitViewValue();
18592                  controller.$setSubmitted();
18593                });
18594
18595                event.preventDefault();
18596              };
18597
18598              addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18599
18600              // unregister the preventDefault listener so that we don't not leak memory but in a
18601              // way that will achieve the prevention of the default action.
18602              formElement.on('$destroy', function() {
18603                $timeout(function() {
18604                  removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
18605                }, 0, false);
18606              });
18607            }
18608
18609            var parentFormCtrl = controller.$$parentForm,
18610                alias = controller.$name;
18611
18612            if (alias) {
18613              setter(scope, null, alias, controller, alias);
18614              attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) {
18615                if (alias === newValue) return;
18616                setter(scope, null, alias, undefined, alias);
18617                alias = newValue;
18618                setter(scope, null, alias, controller, alias);
18619                parentFormCtrl.$$renameControl(controller, alias);
18620              });
18621            }
18622            formElement.on('$destroy', function() {
18623              parentFormCtrl.$removeControl(controller);
18624              if (alias) {
18625                setter(scope, null, alias, undefined, alias);
18626              }
18627              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
18628            });
18629          }
18630        };
18631      }
18632    };
18633
18634    return formDirective;
18635  }];
18636};
18637
18638var formDirective = formDirectiveFactory();
18639var ngFormDirective = formDirectiveFactory(true);
18640
18641/* global VALID_CLASS: false,
18642  INVALID_CLASS: false,
18643  PRISTINE_CLASS: false,
18644  DIRTY_CLASS: false,
18645  UNTOUCHED_CLASS: false,
18646  TOUCHED_CLASS: false,
18647  $ngModelMinErr: false,
18648*/
18649
18650// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
18651var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
18652var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
18653var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
18654var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
18655var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
18656var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18657var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
18658var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
18659var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
18660
18661var inputType = {
18662
18663  /**
18664   * @ngdoc input
18665   * @name input[text]
18666   *
18667   * @description
18668   * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
18669   *
18670   *
18671   * @param {string} ngModel Assignable angular expression to data-bind to.
18672   * @param {string=} name Property name of the form under which the control is published.
18673   * @param {string=} required Adds `required` validation error key if the value is not entered.
18674   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18675   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18676   *    `required` when you want to data-bind to the `required` attribute.
18677   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
18678   *    minlength.
18679   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
18680   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
18681   *    any length.
18682   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
18683   *    that contains the regular expression body that will be converted to a regular expression
18684   *    as in the ngPattern directive.
18685   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
18686   *    a RegExp found by evaluating the Angular expression given in the attribute value.
18687   *    If the expression evaluates to a RegExp object then this is used directly.
18688   *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
18689   *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
18690   * @param {string=} ngChange Angular expression to be executed when input changes due to user
18691   *    interaction with the input element.
18692   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
18693   *    This parameter is ignored for input[type=password] controls, which will never trim the
18694   *    input.
18695   *
18696   * @example
18697      <example name="text-input-directive" module="textInputExample">
18698        <file name="index.html">
18699         <script>
18700           angular.module('textInputExample', [])
18701             .controller('ExampleController', ['$scope', function($scope) {
18702               $scope.example = {
18703                 text: 'guest',
18704                 word: /^\s*\w*\s*$/
18705               };
18706             }]);
18707         </script>
18708         <form name="myForm" ng-controller="ExampleController">
18709           Single word: <input type="text" name="input" ng-model="example.text"
18710                               ng-pattern="example.word" required ng-trim="false">
18711           <span class="error" ng-show="myForm.input.$error.required">
18712             Required!</span>
18713           <span class="error" ng-show="myForm.input.$error.pattern">
18714             Single word only!</span>
18715
18716           <tt>text = {{example.text}}</tt><br/>
18717           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18718           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18719           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18720           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18721          </form>
18722        </file>
18723        <file name="protractor.js" type="protractor">
18724          var text = element(by.binding('example.text'));
18725          var valid = element(by.binding('myForm.input.$valid'));
18726          var input = element(by.model('example.text'));
18727
18728          it('should initialize to model', function() {
18729            expect(text.getText()).toContain('guest');
18730            expect(valid.getText()).toContain('true');
18731          });
18732
18733          it('should be invalid if empty', function() {
18734            input.clear();
18735            input.sendKeys('');
18736
18737            expect(text.getText()).toEqual('text =');
18738            expect(valid.getText()).toContain('false');
18739          });
18740
18741          it('should be invalid if multi word', function() {
18742            input.clear();
18743            input.sendKeys('hello world');
18744
18745            expect(valid.getText()).toContain('false');
18746          });
18747        </file>
18748      </example>
18749   */
18750  'text': textInputType,
18751
18752    /**
18753     * @ngdoc input
18754     * @name input[date]
18755     *
18756     * @description
18757     * Input with date validation and transformation. In browsers that do not yet support
18758     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
18759     * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
18760     * modern browsers do not yet support this input type, it is important to provide cues to users on the
18761     * expected input format via a placeholder or label.
18762     *
18763     * The model must always be a Date object, otherwise Angular will throw an error.
18764     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
18765     *
18766     * The timezone to be used to read/write the `Date` instance in the model can be defined using
18767     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
18768     *
18769     * @param {string} ngModel Assignable angular expression to data-bind to.
18770     * @param {string=} name Property name of the form under which the control is published.
18771     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
18772     * valid ISO date string (yyyy-MM-dd).
18773     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
18774     * a valid ISO date string (yyyy-MM-dd).
18775     * @param {string=} required Sets `required` validation error key if the value is not entered.
18776     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18777     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18778     *    `required` when you want to data-bind to the `required` attribute.
18779     * @param {string=} ngChange Angular expression to be executed when input changes due to user
18780     *    interaction with the input element.
18781     *
18782     * @example
18783     <example name="date-input-directive" module="dateInputExample">
18784     <file name="index.html">
18785       <script>
18786          angular.module('dateInputExample', [])
18787            .controller('DateController', ['$scope', function($scope) {
18788              $scope.example = {
18789                value: new Date(2013, 9, 22)
18790              };
18791            }]);
18792       </script>
18793       <form name="myForm" ng-controller="DateController as dateCtrl">
18794          Pick a date in 2013:
18795          <input type="date" id="exampleInput" name="input" ng-model="example.value"
18796              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
18797          <span class="error" ng-show="myForm.input.$error.required">
18798              Required!</span>
18799          <span class="error" ng-show="myForm.input.$error.date">
18800              Not a valid date!</span>
18801           <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
18802           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18803           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18804           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18805           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18806       </form>
18807     </file>
18808     <file name="protractor.js" type="protractor">
18809        var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
18810        var valid = element(by.binding('myForm.input.$valid'));
18811        var input = element(by.model('example.value'));
18812
18813        // currently protractor/webdriver does not support
18814        // sending keys to all known HTML5 input controls
18815        // for various browsers (see https://github.com/angular/protractor/issues/562).
18816        function setInput(val) {
18817          // set the value of the element and force validation.
18818          var scr = "var ipt = document.getElementById('exampleInput'); " +
18819          "ipt.value = '" + val + "';" +
18820          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
18821          browser.executeScript(scr);
18822        }
18823
18824        it('should initialize to model', function() {
18825          expect(value.getText()).toContain('2013-10-22');
18826          expect(valid.getText()).toContain('myForm.input.$valid = true');
18827        });
18828
18829        it('should be invalid if empty', function() {
18830          setInput('');
18831          expect(value.getText()).toEqual('value =');
18832          expect(valid.getText()).toContain('myForm.input.$valid = false');
18833        });
18834
18835        it('should be invalid if over max', function() {
18836          setInput('2015-01-01');
18837          expect(value.getText()).toContain('');
18838          expect(valid.getText()).toContain('myForm.input.$valid = false');
18839        });
18840     </file>
18841     </example>
18842     */
18843  'date': createDateInputType('date', DATE_REGEXP,
18844         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
18845         'yyyy-MM-dd'),
18846
18847   /**
18848    * @ngdoc input
18849    * @name input[datetime-local]
18850    *
18851    * @description
18852    * Input with datetime validation and transformation. In browsers that do not yet support
18853    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
18854    * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
18855    *
18856    * The model must always be a Date object, otherwise Angular will throw an error.
18857    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
18858    *
18859    * The timezone to be used to read/write the `Date` instance in the model can be defined using
18860    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
18861    *
18862    * @param {string} ngModel Assignable angular expression to data-bind to.
18863    * @param {string=} name Property name of the form under which the control is published.
18864    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
18865    * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
18866    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
18867    * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
18868    * @param {string=} required Sets `required` validation error key if the value is not entered.
18869    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18870    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18871    *    `required` when you want to data-bind to the `required` attribute.
18872    * @param {string=} ngChange Angular expression to be executed when input changes due to user
18873    *    interaction with the input element.
18874    *
18875    * @example
18876    <example name="datetimelocal-input-directive" module="dateExample">
18877    <file name="index.html">
18878      <script>
18879        angular.module('dateExample', [])
18880          .controller('DateController', ['$scope', function($scope) {
18881            $scope.example = {
18882              value: new Date(2010, 11, 28, 14, 57)
18883            };
18884          }]);
18885      </script>
18886      <form name="myForm" ng-controller="DateController as dateCtrl">
18887        Pick a date between in 2013:
18888        <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
18889            placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
18890        <span class="error" ng-show="myForm.input.$error.required">
18891            Required!</span>
18892        <span class="error" ng-show="myForm.input.$error.datetimelocal">
18893            Not a valid date!</span>
18894        <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
18895        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18896        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18897        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18898        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18899      </form>
18900    </file>
18901    <file name="protractor.js" type="protractor">
18902      var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
18903      var valid = element(by.binding('myForm.input.$valid'));
18904      var input = element(by.model('example.value'));
18905
18906      // currently protractor/webdriver does not support
18907      // sending keys to all known HTML5 input controls
18908      // for various browsers (https://github.com/angular/protractor/issues/562).
18909      function setInput(val) {
18910        // set the value of the element and force validation.
18911        var scr = "var ipt = document.getElementById('exampleInput'); " +
18912        "ipt.value = '" + val + "';" +
18913        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
18914        browser.executeScript(scr);
18915      }
18916
18917      it('should initialize to model', function() {
18918        expect(value.getText()).toContain('2010-12-28T14:57:00');
18919        expect(valid.getText()).toContain('myForm.input.$valid = true');
18920      });
18921
18922      it('should be invalid if empty', function() {
18923        setInput('');
18924        expect(value.getText()).toEqual('value =');
18925        expect(valid.getText()).toContain('myForm.input.$valid = false');
18926      });
18927
18928      it('should be invalid if over max', function() {
18929        setInput('2015-01-01T23:59:00');
18930        expect(value.getText()).toContain('');
18931        expect(valid.getText()).toContain('myForm.input.$valid = false');
18932      });
18933    </file>
18934    </example>
18935    */
18936  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
18937      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
18938      'yyyy-MM-ddTHH:mm:ss.sss'),
18939
18940  /**
18941   * @ngdoc input
18942   * @name input[time]
18943   *
18944   * @description
18945   * Input with time validation and transformation. In browsers that do not yet support
18946   * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
18947   * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
18948   * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
18949   *
18950   * The model must always be a Date object, otherwise Angular will throw an error.
18951   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
18952   *
18953   * The timezone to be used to read/write the `Date` instance in the model can be defined using
18954   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
18955   *
18956   * @param {string} ngModel Assignable angular expression to data-bind to.
18957   * @param {string=} name Property name of the form under which the control is published.
18958   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
18959   * valid ISO time format (HH:mm:ss).
18960   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
18961   * valid ISO time format (HH:mm:ss).
18962   * @param {string=} required Sets `required` validation error key if the value is not entered.
18963   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
18964   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
18965   *    `required` when you want to data-bind to the `required` attribute.
18966   * @param {string=} ngChange Angular expression to be executed when input changes due to user
18967   *    interaction with the input element.
18968   *
18969   * @example
18970   <example name="time-input-directive" module="timeExample">
18971   <file name="index.html">
18972     <script>
18973      angular.module('timeExample', [])
18974        .controller('DateController', ['$scope', function($scope) {
18975          $scope.example = {
18976            value: new Date(1970, 0, 1, 14, 57, 0)
18977          };
18978        }]);
18979     </script>
18980     <form name="myForm" ng-controller="DateController as dateCtrl">
18981        Pick a between 8am and 5pm:
18982        <input type="time" id="exampleInput" name="input" ng-model="example.value"
18983            placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
18984        <span class="error" ng-show="myForm.input.$error.required">
18985            Required!</span>
18986        <span class="error" ng-show="myForm.input.$error.time">
18987            Not a valid date!</span>
18988        <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
18989        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
18990        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
18991        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
18992        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
18993     </form>
18994   </file>
18995   <file name="protractor.js" type="protractor">
18996      var value = element(by.binding('example.value | date: "HH:mm:ss"'));
18997      var valid = element(by.binding('myForm.input.$valid'));
18998      var input = element(by.model('example.value'));
18999
19000      // currently protractor/webdriver does not support
19001      // sending keys to all known HTML5 input controls
19002      // for various browsers (https://github.com/angular/protractor/issues/562).
19003      function setInput(val) {
19004        // set the value of the element and force validation.
19005        var scr = "var ipt = document.getElementById('exampleInput'); " +
19006        "ipt.value = '" + val + "';" +
19007        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19008        browser.executeScript(scr);
19009      }
19010
19011      it('should initialize to model', function() {
19012        expect(value.getText()).toContain('14:57:00');
19013        expect(valid.getText()).toContain('myForm.input.$valid = true');
19014      });
19015
19016      it('should be invalid if empty', function() {
19017        setInput('');
19018        expect(value.getText()).toEqual('value =');
19019        expect(valid.getText()).toContain('myForm.input.$valid = false');
19020      });
19021
19022      it('should be invalid if over max', function() {
19023        setInput('23:59:00');
19024        expect(value.getText()).toContain('');
19025        expect(valid.getText()).toContain('myForm.input.$valid = false');
19026      });
19027   </file>
19028   </example>
19029   */
19030  'time': createDateInputType('time', TIME_REGEXP,
19031      createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
19032     'HH:mm:ss.sss'),
19033
19034   /**
19035    * @ngdoc input
19036    * @name input[week]
19037    *
19038    * @description
19039    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
19040    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19041    * week format (yyyy-W##), for example: `2013-W02`.
19042    *
19043    * The model must always be a Date object, otherwise Angular will throw an error.
19044    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19045    *
19046    * The timezone to be used to read/write the `Date` instance in the model can be defined using
19047    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19048    *
19049    * @param {string} ngModel Assignable angular expression to data-bind to.
19050    * @param {string=} name Property name of the form under which the control is published.
19051    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
19052    * valid ISO week format (yyyy-W##).
19053    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
19054    * a valid ISO week format (yyyy-W##).
19055    * @param {string=} required Sets `required` validation error key if the value is not entered.
19056    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19057    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19058    *    `required` when you want to data-bind to the `required` attribute.
19059    * @param {string=} ngChange Angular expression to be executed when input changes due to user
19060    *    interaction with the input element.
19061    *
19062    * @example
19063    <example name="week-input-directive" module="weekExample">
19064    <file name="index.html">
19065      <script>
19066      angular.module('weekExample', [])
19067        .controller('DateController', ['$scope', function($scope) {
19068          $scope.example = {
19069            value: new Date(2013, 0, 3)
19070          };
19071        }]);
19072      </script>
19073      <form name="myForm" ng-controller="DateController as dateCtrl">
19074        Pick a date between in 2013:
19075        <input id="exampleInput" type="week" name="input" ng-model="example.value"
19076            placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
19077        <span class="error" ng-show="myForm.input.$error.required">
19078            Required!</span>
19079        <span class="error" ng-show="myForm.input.$error.week">
19080            Not a valid date!</span>
19081        <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
19082        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19083        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19084        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19085        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19086      </form>
19087    </file>
19088    <file name="protractor.js" type="protractor">
19089      var value = element(by.binding('example.value | date: "yyyy-Www"'));
19090      var valid = element(by.binding('myForm.input.$valid'));
19091      var input = element(by.model('example.value'));
19092
19093      // currently protractor/webdriver does not support
19094      // sending keys to all known HTML5 input controls
19095      // for various browsers (https://github.com/angular/protractor/issues/562).
19096      function setInput(val) {
19097        // set the value of the element and force validation.
19098        var scr = "var ipt = document.getElementById('exampleInput'); " +
19099        "ipt.value = '" + val + "';" +
19100        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19101        browser.executeScript(scr);
19102      }
19103
19104      it('should initialize to model', function() {
19105        expect(value.getText()).toContain('2013-W01');
19106        expect(valid.getText()).toContain('myForm.input.$valid = true');
19107      });
19108
19109      it('should be invalid if empty', function() {
19110        setInput('');
19111        expect(value.getText()).toEqual('value =');
19112        expect(valid.getText()).toContain('myForm.input.$valid = false');
19113      });
19114
19115      it('should be invalid if over max', function() {
19116        setInput('2015-W01');
19117        expect(value.getText()).toContain('');
19118        expect(valid.getText()).toContain('myForm.input.$valid = false');
19119      });
19120    </file>
19121    </example>
19122    */
19123  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
19124
19125  /**
19126   * @ngdoc input
19127   * @name input[month]
19128   *
19129   * @description
19130   * Input with month validation and transformation. In browsers that do not yet support
19131   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
19132   * month format (yyyy-MM), for example: `2009-01`.
19133   *
19134   * The model must always be a Date object, otherwise Angular will throw an error.
19135   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
19136   * If the model is not set to the first of the month, the next view to model update will set it
19137   * to the first of the month.
19138   *
19139   * The timezone to be used to read/write the `Date` instance in the model can be defined using
19140   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
19141   *
19142   * @param {string} ngModel Assignable angular expression to data-bind to.
19143   * @param {string=} name Property name of the form under which the control is published.
19144   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
19145   * a valid ISO month format (yyyy-MM).
19146   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
19147   * be a valid ISO month format (yyyy-MM).
19148   * @param {string=} required Sets `required` validation error key if the value is not entered.
19149   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19150   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19151   *    `required` when you want to data-bind to the `required` attribute.
19152   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19153   *    interaction with the input element.
19154   *
19155   * @example
19156   <example name="month-input-directive" module="monthExample">
19157   <file name="index.html">
19158     <script>
19159      angular.module('monthExample', [])
19160        .controller('DateController', ['$scope', function($scope) {
19161          $scope.example = {
19162            value: new Date(2013, 9, 1)
19163          };
19164        }]);
19165     </script>
19166     <form name="myForm" ng-controller="DateController as dateCtrl">
19167       Pick a month in 2013:
19168       <input id="exampleInput" type="month" name="input" ng-model="example.value"
19169          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
19170       <span class="error" ng-show="myForm.input.$error.required">
19171          Required!</span>
19172       <span class="error" ng-show="myForm.input.$error.month">
19173          Not a valid month!</span>
19174       <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
19175       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19176       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19177       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19178       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19179     </form>
19180   </file>
19181   <file name="protractor.js" type="protractor">
19182      var value = element(by.binding('example.value | date: "yyyy-MM"'));
19183      var valid = element(by.binding('myForm.input.$valid'));
19184      var input = element(by.model('example.value'));
19185
19186      // currently protractor/webdriver does not support
19187      // sending keys to all known HTML5 input controls
19188      // for various browsers (https://github.com/angular/protractor/issues/562).
19189      function setInput(val) {
19190        // set the value of the element and force validation.
19191        var scr = "var ipt = document.getElementById('exampleInput'); " +
19192        "ipt.value = '" + val + "';" +
19193        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
19194        browser.executeScript(scr);
19195      }
19196
19197      it('should initialize to model', function() {
19198        expect(value.getText()).toContain('2013-10');
19199        expect(valid.getText()).toContain('myForm.input.$valid = true');
19200      });
19201
19202      it('should be invalid if empty', function() {
19203        setInput('');
19204        expect(value.getText()).toEqual('value =');
19205        expect(valid.getText()).toContain('myForm.input.$valid = false');
19206      });
19207
19208      it('should be invalid if over max', function() {
19209        setInput('2015-01');
19210        expect(value.getText()).toContain('');
19211        expect(valid.getText()).toContain('myForm.input.$valid = false');
19212      });
19213   </file>
19214   </example>
19215   */
19216  'month': createDateInputType('month', MONTH_REGEXP,
19217     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
19218     'yyyy-MM'),
19219
19220  /**
19221   * @ngdoc input
19222   * @name input[number]
19223   *
19224   * @description
19225   * Text input with number validation and transformation. Sets the `number` validation
19226   * error if not a valid number.
19227   *
19228   * The model must always be a number, otherwise Angular will throw an error.
19229   *
19230   * @param {string} ngModel Assignable angular expression to data-bind to.
19231   * @param {string=} name Property name of the form under which the control is published.
19232   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
19233   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
19234   * @param {string=} required Sets `required` validation error key if the value is not entered.
19235   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19236   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19237   *    `required` when you want to data-bind to the `required` attribute.
19238   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19239   *    minlength.
19240   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19241   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19242   *    any length.
19243   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19244   *    that contains the regular expression body that will be converted to a regular expression
19245   *    as in the ngPattern directive.
19246   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19247   *    a RegExp found by evaluating the Angular expression given in the attribute value.
19248   *    If the expression evaluates to a RegExp object then this is used directly.
19249   *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19250   *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19251   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19252   *    interaction with the input element.
19253   *
19254   * @example
19255      <example name="number-input-directive" module="numberExample">
19256        <file name="index.html">
19257         <script>
19258           angular.module('numberExample', [])
19259             .controller('ExampleController', ['$scope', function($scope) {
19260               $scope.example = {
19261                 value: 12
19262               };
19263             }]);
19264         </script>
19265         <form name="myForm" ng-controller="ExampleController">
19266           Number: <input type="number" name="input" ng-model="example.value"
19267                          min="0" max="99" required>
19268           <span class="error" ng-show="myForm.input.$error.required">
19269             Required!</span>
19270           <span class="error" ng-show="myForm.input.$error.number">
19271             Not valid number!</span>
19272           <tt>value = {{example.value}}</tt><br/>
19273           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19274           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19275           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19276           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19277          </form>
19278        </file>
19279        <file name="protractor.js" type="protractor">
19280          var value = element(by.binding('example.value'));
19281          var valid = element(by.binding('myForm.input.$valid'));
19282          var input = element(by.model('example.value'));
19283
19284          it('should initialize to model', function() {
19285            expect(value.getText()).toContain('12');
19286            expect(valid.getText()).toContain('true');
19287          });
19288
19289          it('should be invalid if empty', function() {
19290            input.clear();
19291            input.sendKeys('');
19292            expect(value.getText()).toEqual('value =');
19293            expect(valid.getText()).toContain('false');
19294          });
19295
19296          it('should be invalid if over max', function() {
19297            input.clear();
19298            input.sendKeys('123');
19299            expect(value.getText()).toEqual('value =');
19300            expect(valid.getText()).toContain('false');
19301          });
19302        </file>
19303      </example>
19304   */
19305  'number': numberInputType,
19306
19307
19308  /**
19309   * @ngdoc input
19310   * @name input[url]
19311   *
19312   * @description
19313   * Text input with URL validation. Sets the `url` validation error key if the content is not a
19314   * valid URL.
19315   *
19316   * <div class="alert alert-warning">
19317   * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
19318   * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
19319   * the built-in validators (see the {@link guide/forms Forms guide})
19320   * </div>
19321   *
19322   * @param {string} ngModel Assignable angular expression to data-bind to.
19323   * @param {string=} name Property name of the form under which the control is published.
19324   * @param {string=} required Sets `required` validation error key if the value is not entered.
19325   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19326   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19327   *    `required` when you want to data-bind to the `required` attribute.
19328   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19329   *    minlength.
19330   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19331   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19332   *    any length.
19333   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19334   *    that contains the regular expression body that will be converted to a regular expression
19335   *    as in the ngPattern directive.
19336   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19337   *    a RegExp found by evaluating the Angular expression given in the attribute value.
19338   *    If the expression evaluates to a RegExp object then this is used directly.
19339   *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19340   *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19341   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19342   *    interaction with the input element.
19343   *
19344   * @example
19345      <example name="url-input-directive" module="urlExample">
19346        <file name="index.html">
19347         <script>
19348           angular.module('urlExample', [])
19349             .controller('ExampleController', ['$scope', function($scope) {
19350               $scope.url = {
19351                 text: 'http://google.com'
19352               };
19353             }]);
19354         </script>
19355         <form name="myForm" ng-controller="ExampleController">
19356           URL: <input type="url" name="input" ng-model="url.text" required>
19357           <span class="error" ng-show="myForm.input.$error.required">
19358             Required!</span>
19359           <span class="error" ng-show="myForm.input.$error.url">
19360             Not valid url!</span>
19361           <tt>text = {{url.text}}</tt><br/>
19362           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19363           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19364           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19365           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19366           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
19367          </form>
19368        </file>
19369        <file name="protractor.js" type="protractor">
19370          var text = element(by.binding('url.text'));
19371          var valid = element(by.binding('myForm.input.$valid'));
19372          var input = element(by.model('url.text'));
19373
19374          it('should initialize to model', function() {
19375            expect(text.getText()).toContain('http://google.com');
19376            expect(valid.getText()).toContain('true');
19377          });
19378
19379          it('should be invalid if empty', function() {
19380            input.clear();
19381            input.sendKeys('');
19382
19383            expect(text.getText()).toEqual('text =');
19384            expect(valid.getText()).toContain('false');
19385          });
19386
19387          it('should be invalid if not url', function() {
19388            input.clear();
19389            input.sendKeys('box');
19390
19391            expect(valid.getText()).toContain('false');
19392          });
19393        </file>
19394      </example>
19395   */
19396  'url': urlInputType,
19397
19398
19399  /**
19400   * @ngdoc input
19401   * @name input[email]
19402   *
19403   * @description
19404   * Text input with email validation. Sets the `email` validation error key if not a valid email
19405   * address.
19406   *
19407   * <div class="alert alert-warning">
19408   * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
19409   * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
19410   * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
19411   * </div>
19412   *
19413   * @param {string} ngModel Assignable angular expression to data-bind to.
19414   * @param {string=} name Property name of the form under which the control is published.
19415   * @param {string=} required Sets `required` validation error key if the value is not entered.
19416   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
19417   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
19418   *    `required` when you want to data-bind to the `required` attribute.
19419   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19420   *    minlength.
19421   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19422   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19423   *    any length.
19424   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19425   *    that contains the regular expression body that will be converted to a regular expression
19426   *    as in the ngPattern directive.
19427   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19428   *    a RegExp found by evaluating the Angular expression given in the attribute value.
19429   *    If the expression evaluates to a RegExp object then this is used directly.
19430   *    If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19431   *    characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19432   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19433   *    interaction with the input element.
19434   *
19435   * @example
19436      <example name="email-input-directive" module="emailExample">
19437        <file name="index.html">
19438         <script>
19439           angular.module('emailExample', [])
19440             .controller('ExampleController', ['$scope', function($scope) {
19441               $scope.email = {
19442                 text: '[email protected]'
19443               };
19444             }]);
19445         </script>
19446           <form name="myForm" ng-controller="ExampleController">
19447             Email: <input type="email" name="input" ng-model="email.text" required>
19448             <span class="error" ng-show="myForm.input.$error.required">
19449               Required!</span>
19450             <span class="error" ng-show="myForm.input.$error.email">
19451               Not valid email!</span>
19452             <tt>text = {{email.text}}</tt><br/>
19453             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
19454             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
19455             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
19456             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
19457             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
19458           </form>
19459         </file>
19460        <file name="protractor.js" type="protractor">
19461          var text = element(by.binding('email.text'));
19462          var valid = element(by.binding('myForm.input.$valid'));
19463          var input = element(by.model('email.text'));
19464
19465          it('should initialize to model', function() {
19466            expect(text.getText()).toContain('[email protected]');
19467            expect(valid.getText()).toContain('true');
19468          });
19469
19470          it('should be invalid if empty', function() {
19471            input.clear();
19472            input.sendKeys('');
19473            expect(text.getText()).toEqual('text =');
19474            expect(valid.getText()).toContain('false');
19475          });
19476
19477          it('should be invalid if not email', function() {
19478            input.clear();
19479            input.sendKeys('xxx');
19480
19481            expect(valid.getText()).toContain('false');
19482          });
19483        </file>
19484      </example>
19485   */
19486  'email': emailInputType,
19487
19488
19489  /**
19490   * @ngdoc input
19491   * @name input[radio]
19492   *
19493   * @description
19494   * HTML radio button.
19495   *
19496   * @param {string} ngModel Assignable angular expression to data-bind to.
19497   * @param {string} value The value to which the expression should be set when selected.
19498   * @param {string=} name Property name of the form under which the control is published.
19499   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19500   *    interaction with the input element.
19501   * @param {string} ngValue Angular expression which sets the value to which the expression should
19502   *    be set when selected.
19503   *
19504   * @example
19505      <example name="radio-input-directive" module="radioExample">
19506        <file name="index.html">
19507         <script>
19508           angular.module('radioExample', [])
19509             .controller('ExampleController', ['$scope', function($scope) {
19510               $scope.color = {
19511                 name: 'blue'
19512               };
19513               $scope.specialValue = {
19514                 "id": "12345",
19515                 "value": "green"
19516               };
19517             }]);
19518         </script>
19519         <form name="myForm" ng-controller="ExampleController">
19520           <input type="radio" ng-model="color.name" value="red">  Red <br/>
19521           <input type="radio" ng-model="color.name" ng-value="specialValue"> Green <br/>
19522           <input type="radio" ng-model="color.name" value="blue"> Blue <br/>
19523           <tt>color = {{color.name | json}}</tt><br/>
19524          </form>
19525          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
19526        </file>
19527        <file name="protractor.js" type="protractor">
19528          it('should change state', function() {
19529            var color = element(by.binding('color.name'));
19530
19531            expect(color.getText()).toContain('blue');
19532
19533            element.all(by.model('color.name')).get(0).click();
19534
19535            expect(color.getText()).toContain('red');
19536          });
19537        </file>
19538      </example>
19539   */
19540  'radio': radioInputType,
19541
19542
19543  /**
19544   * @ngdoc input
19545   * @name input[checkbox]
19546   *
19547   * @description
19548   * HTML checkbox.
19549   *
19550   * @param {string} ngModel Assignable angular expression to data-bind to.
19551   * @param {string=} name Property name of the form under which the control is published.
19552   * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
19553   * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
19554   * @param {string=} ngChange Angular expression to be executed when input changes due to user
19555   *    interaction with the input element.
19556   *
19557   * @example
19558      <example name="checkbox-input-directive" module="checkboxExample">
19559        <file name="index.html">
19560         <script>
19561           angular.module('checkboxExample', [])
19562             .controller('ExampleController', ['$scope', function($scope) {
19563               $scope.checkboxModel = {
19564                value1 : true,
19565                value2 : 'YES'
19566              };
19567             }]);
19568         </script>
19569         <form name="myForm" ng-controller="ExampleController">
19570           Value1: <input type="checkbox" ng-model="checkboxModel.value1"> <br/>
19571           Value2: <input type="checkbox" ng-model="checkboxModel.value2"
19572                          ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
19573           <tt>value1 = {{checkboxModel.value1}}</tt><br/>
19574           <tt>value2 = {{checkboxModel.value2}}</tt><br/>
19575          </form>
19576        </file>
19577        <file name="protractor.js" type="protractor">
19578          it('should change state', function() {
19579            var value1 = element(by.binding('checkboxModel.value1'));
19580            var value2 = element(by.binding('checkboxModel.value2'));
19581
19582            expect(value1.getText()).toContain('true');
19583            expect(value2.getText()).toContain('YES');
19584
19585            element(by.model('checkboxModel.value1')).click();
19586            element(by.model('checkboxModel.value2')).click();
19587
19588            expect(value1.getText()).toContain('false');
19589            expect(value2.getText()).toContain('NO');
19590          });
19591        </file>
19592      </example>
19593   */
19594  'checkbox': checkboxInputType,
19595
19596  'hidden': noop,
19597  'button': noop,
19598  'submit': noop,
19599  'reset': noop,
19600  'file': noop
19601};
19602
19603function stringBasedInputType(ctrl) {
19604  ctrl.$formatters.push(function(value) {
19605    return ctrl.$isEmpty(value) ? value : value.toString();
19606  });
19607}
19608
19609function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19610  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19611  stringBasedInputType(ctrl);
19612}
19613
19614function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19615  var type = lowercase(element[0].type);
19616
19617  // In composition mode, users are still inputing intermediate text buffer,
19618  // hold the listener until composition is done.
19619  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
19620  if (!$sniffer.android) {
19621    var composing = false;
19622
19623    element.on('compositionstart', function(data) {
19624      composing = true;
19625    });
19626
19627    element.on('compositionend', function() {
19628      composing = false;
19629      listener();
19630    });
19631  }
19632
19633  var listener = function(ev) {
19634    if (timeout) {
19635      $browser.defer.cancel(timeout);
19636      timeout = null;
19637    }
19638    if (composing) return;
19639    var value = element.val(),
19640        event = ev && ev.type;
19641
19642    // By default we will trim the value
19643    // If the attribute ng-trim exists we will avoid trimming
19644    // If input type is 'password', the value is never trimmed
19645    if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
19646      value = trim(value);
19647    }
19648
19649    // If a control is suffering from bad input (due to native validators), browsers discard its
19650    // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
19651    // control's value is the same empty value twice in a row.
19652    if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
19653      ctrl.$setViewValue(value, event);
19654    }
19655  };
19656
19657  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
19658  // input event on backspace, delete or cut
19659  if ($sniffer.hasEvent('input')) {
19660    element.on('input', listener);
19661  } else {
19662    var timeout;
19663
19664    var deferListener = function(ev, input, origValue) {
19665      if (!timeout) {
19666        timeout = $browser.defer(function() {
19667          timeout = null;
19668          if (!input || input.value !== origValue) {
19669            listener(ev);
19670          }
19671        });
19672      }
19673    };
19674
19675    element.on('keydown', function(event) {
19676      var key = event.keyCode;
19677
19678      // ignore
19679      //    command            modifiers                   arrows
19680      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
19681
19682      deferListener(event, this, this.value);
19683    });
19684
19685    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
19686    if ($sniffer.hasEvent('paste')) {
19687      element.on('paste cut', deferListener);
19688    }
19689  }
19690
19691  // if user paste into input using mouse on older browser
19692  // or form autocomplete on newer browser, we need "change" event to catch it
19693  element.on('change', listener);
19694
19695  ctrl.$render = function() {
19696    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
19697  };
19698}
19699
19700function weekParser(isoWeek, existingDate) {
19701  if (isDate(isoWeek)) {
19702    return isoWeek;
19703  }
19704
19705  if (isString(isoWeek)) {
19706    WEEK_REGEXP.lastIndex = 0;
19707    var parts = WEEK_REGEXP.exec(isoWeek);
19708    if (parts) {
19709      var year = +parts[1],
19710          week = +parts[2],
19711          hours = 0,
19712          minutes = 0,
19713          seconds = 0,
19714          milliseconds = 0,
19715          firstThurs = getFirstThursdayOfYear(year),
19716          addDays = (week - 1) * 7;
19717
19718      if (existingDate) {
19719        hours = existingDate.getHours();
19720        minutes = existingDate.getMinutes();
19721        seconds = existingDate.getSeconds();
19722        milliseconds = existingDate.getMilliseconds();
19723      }
19724
19725      return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
19726    }
19727  }
19728
19729  return NaN;
19730}
19731
19732function createDateParser(regexp, mapping) {
19733  return function(iso, date) {
19734    var parts, map;
19735
19736    if (isDate(iso)) {
19737      return iso;
19738    }
19739
19740    if (isString(iso)) {
19741      // When a date is JSON'ified to wraps itself inside of an extra
19742      // set of double quotes. This makes the date parsing code unable
19743      // to match the date string and parse it as a date.
19744      if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
19745        iso = iso.substring(1, iso.length - 1);
19746      }
19747      if (ISO_DATE_REGEXP.test(iso)) {
19748        return new Date(iso);
19749      }
19750      regexp.lastIndex = 0;
19751      parts = regexp.exec(iso);
19752
19753      if (parts) {
19754        parts.shift();
19755        if (date) {
19756          map = {
19757            yyyy: date.getFullYear(),
19758            MM: date.getMonth() + 1,
19759            dd: date.getDate(),
19760            HH: date.getHours(),
19761            mm: date.getMinutes(),
19762            ss: date.getSeconds(),
19763            sss: date.getMilliseconds() / 1000
19764          };
19765        } else {
19766          map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
19767        }
19768
19769        forEach(parts, function(part, index) {
19770          if (index < mapping.length) {
19771            map[mapping[index]] = +part;
19772          }
19773        });
19774        return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
19775      }
19776    }
19777
19778    return NaN;
19779  };
19780}
19781
19782function createDateInputType(type, regexp, parseDate, format) {
19783  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
19784    badInputChecker(scope, element, attr, ctrl);
19785    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19786    var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
19787    var previousDate;
19788
19789    ctrl.$$parserName = type;
19790    ctrl.$parsers.push(function(value) {
19791      if (ctrl.$isEmpty(value)) return null;
19792      if (regexp.test(value)) {
19793        // Note: We cannot read ctrl.$modelValue, as there might be a different
19794        // parser/formatter in the processing chain so that the model
19795        // contains some different data format!
19796        var parsedDate = parseDate(value, previousDate);
19797        if (timezone === 'UTC') {
19798          parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
19799        }
19800        return parsedDate;
19801      }
19802      return undefined;
19803    });
19804
19805    ctrl.$formatters.push(function(value) {
19806      if (value && !isDate(value)) {
19807        throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19808      }
19809      if (isValidDate(value)) {
19810        previousDate = value;
19811        if (previousDate && timezone === 'UTC') {
19812          var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
19813          previousDate = new Date(previousDate.getTime() + timezoneOffset);
19814        }
19815        return $filter('date')(value, format, timezone);
19816      } else {
19817        previousDate = null;
19818        return '';
19819      }
19820    });
19821
19822    if (isDefined(attr.min) || attr.ngMin) {
19823      var minVal;
19824      ctrl.$validators.min = function(value) {
19825        return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19826      };
19827      attr.$observe('min', function(val) {
19828        minVal = parseObservedDateValue(val);
19829        ctrl.$validate();
19830      });
19831    }
19832
19833    if (isDefined(attr.max) || attr.ngMax) {
19834      var maxVal;
19835      ctrl.$validators.max = function(value) {
19836        return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19837      };
19838      attr.$observe('max', function(val) {
19839        maxVal = parseObservedDateValue(val);
19840        ctrl.$validate();
19841      });
19842    }
19843
19844    function isValidDate(value) {
19845      // Invalid Date: getTime() returns NaN
19846      return value && !(value.getTime && value.getTime() !== value.getTime());
19847    }
19848
19849    function parseObservedDateValue(val) {
19850      return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
19851    }
19852  };
19853}
19854
19855function badInputChecker(scope, element, attr, ctrl) {
19856  var node = element[0];
19857  var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
19858  if (nativeValidation) {
19859    ctrl.$parsers.push(function(value) {
19860      var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
19861      // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
19862      // - also sets validity.badInput (should only be validity.typeMismatch).
19863      // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
19864      // - can ignore this case as we can still read out the erroneous email...
19865      return validity.badInput && !validity.typeMismatch ? undefined : value;
19866    });
19867  }
19868}
19869
19870function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19871  badInputChecker(scope, element, attr, ctrl);
19872  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19873
19874  ctrl.$$parserName = 'number';
19875  ctrl.$parsers.push(function(value) {
19876    if (ctrl.$isEmpty(value))      return null;
19877    if (NUMBER_REGEXP.test(value)) return parseFloat(value);
19878    return undefined;
19879  });
19880
19881  ctrl.$formatters.push(function(value) {
19882    if (!ctrl.$isEmpty(value)) {
19883      if (!isNumber(value)) {
19884        throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
19885      }
19886      value = value.toString();
19887    }
19888    return value;
19889  });
19890
19891  if (attr.min || attr.ngMin) {
19892    var minVal;
19893    ctrl.$validators.min = function(value) {
19894      return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
19895    };
19896
19897    attr.$observe('min', function(val) {
19898      if (isDefined(val) && !isNumber(val)) {
19899        val = parseFloat(val, 10);
19900      }
19901      minVal = isNumber(val) && !isNaN(val) ? val : undefined;
19902      // TODO(matsko): implement validateLater to reduce number of validations
19903      ctrl.$validate();
19904    });
19905  }
19906
19907  if (attr.max || attr.ngMax) {
19908    var maxVal;
19909    ctrl.$validators.max = function(value) {
19910      return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
19911    };
19912
19913    attr.$observe('max', function(val) {
19914      if (isDefined(val) && !isNumber(val)) {
19915        val = parseFloat(val, 10);
19916      }
19917      maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
19918      // TODO(matsko): implement validateLater to reduce number of validations
19919      ctrl.$validate();
19920    });
19921  }
19922}
19923
19924function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19925  // Note: no badInputChecker here by purpose as `url` is only a validation
19926  // in browsers, i.e. we can always read out input.value even if it is not val
19926id!
19927  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19928  stringBasedInputType(ctrl);
19929
19930  ctrl.$$parserName = 'url';
19931  ctrl.$validators.url = function(modelValue, viewValue) {
19932    var value = modelValue || viewValue;
19933    return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
19934  };
19935}
19936
19937function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19938  // Note: no badInputChecker here by purpose as `url` is only a validation
19939  // in browsers, i.e. we can always read out input.value even if it is not valid!
19940  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
19941  stringBasedInputType(ctrl);
19942
19943  ctrl.$$parserName = 'email';
19944  ctrl.$validators.email = function(modelValue, viewValue) {
19945    var value = modelValue || viewValue;
19946    return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
19947  };
19948}
19949
19950function radioInputType(scope, element, attr, ctrl) {
19951  // make the name unique, if not defined
19952  if (isUndefined(attr.name)) {
19953    element.attr('name', nextUid());
19954  }
19955
19956  var listener = function(ev) {
19957    if (element[0].checked) {
19958      ctrl.$setViewValue(attr.value, ev && ev.type);
19959    }
19960  };
19961
19962  element.on('click', listener);
19963
19964  ctrl.$render = function() {
19965    var value = attr.value;
19966    element[0].checked = (value == ctrl.$viewValue);
19967  };
19968
19969  attr.$observe('value', ctrl.$render);
19970}
19971
19972function parseConstantExpr($parse, context, name, expression, fallback) {
19973  var parseFn;
19974  if (isDefined(expression)) {
19975    parseFn = $parse(expression);
19976    if (!parseFn.constant) {
19977      throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
19978                                   '`{1}`.', name, expression);
19979    }
19980    return parseFn(context);
19981  }
19982  return fallback;
19983}
19984
19985function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
19986  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
19987  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
19988
19989  var listener = function(ev) {
19990    ctrl.$setViewValue(element[0].checked, ev && ev.type);
19991  };
19992
19993  element.on('click', listener);
19994
19995  ctrl.$render = function() {
19996    element[0].checked = ctrl.$viewValue;
19997  };
19998
19999  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
20000  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
20001  // it to a boolean.
20002  ctrl.$isEmpty = function(value) {
20003    return value === false;
20004  };
20005
20006  ctrl.$formatters.push(function(value) {
20007    return equals(value, trueValue);
20008  });
20009
20010  ctrl.$parsers.push(function(value) {
20011    return value ? trueValue : falseValue;
20012  });
20013}
20014
20015
20016/**
20017 * @ngdoc directive
20018 * @name textarea
20019 * @restrict E
20020 *
20021 * @description
20022 * HTML textarea element control with angular data-binding. The data-binding and validation
20023 * properties of this element are exactly the same as those of the
20024 * {@link ng.directive:input input element}.
20025 *
20026 * @param {string} ngModel Assignable angular expression to data-bind to.
20027 * @param {string=} name Property name of the form under which the control is published.
20028 * @param {string=} required Sets `required` validation error key if the value is not entered.
20029 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20030 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20031 *    `required` when you want to data-bind to the `required` attribute.
20032 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20033 *    minlength.
20034 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20035 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20036 *    length.
20037 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20038 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20039 *    patterns defined as scope expressions.
20040 * @param {string=} ngChange Angular expression to be executed when input changes due to user
20041 *    interaction with the input element.
20042 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20043 */
20044
20045
20046/**
20047 * @ngdoc directive
20048 * @name input
20049 * @restrict E
20050 *
20051 * @description
20052 * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
20053 * input state control, and validation.
20054 * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
20055 *
20056 * <div class="alert alert-warning">
20057 * **Note:** Not every feature offered is available for all input types.
20058 * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
20059 * </div>
20060 *
20061 * @param {string} ngModel Assignable angular expression to data-bind to.
20062 * @param {string=} name Property name of the form under which the control is published.
20063 * @param {string=} required Sets `required` validation error key if the value is not entered.
20064 * @param {boolean=} ngRequired Sets `required` attribute if set to true
20065 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20066 *    minlength.
20067 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20068 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
20069 *    length.
20070 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
20071 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
20072 *    patterns defined as scope expressions.
20073 * @param {string=} ngChange Angular expression to be executed when input changes due to user
20074 *    interaction with the input element.
20075 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20076 *    This parameter is ignored for input[type=password] controls, which will never trim the
20077 *    input.
20078 *
20079 * @example
20080    <example name="input-directive" module="inputExample">
20081      <file name="index.html">
20082       <script>
20083          angular.module('inputExample', [])
20084            .controller('ExampleController', ['$scope', function($scope) {
20085              $scope.user = {name: 'guest', last: 'visitor'};
20086            }]);
20087       </script>
20088       <div ng-controller="ExampleController">
20089         <form name="myForm">
20090           User name: <input type="text" name="userName" ng-model="user.name" required>
20091           <span class="error" ng-show="myForm.userName.$error.required">
20092             Required!</span><br>
20093           Last name: <input type="text" name="lastName" ng-model="user.last"
20094             ng-minlength="3" ng-maxlength="10">
20095           <span class="error" ng-show="myForm.lastName.$error.minlength">
20096             Too short!</span>
20097           <span class="error" ng-show="myForm.lastName.$error.maxlength">
20098             Too long!</span><br>
20099         </form>
20100         <hr>
20101         <tt>user = {{user}}</tt><br/>
20102         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
20103         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
20104         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
20105         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
20106         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
20107         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
20108         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
20109         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br
vendor: 2,872 bytes, lines 20109-20183
20109>
20110       </div>
20111      </file>
20112      <file name="protractor.js" type="protractor">
20113        var user = element(by.exactBinding('user'));
20114        var userNameValid = element(by.binding('myForm.userName.$valid'));
20115        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
20116        var lastNameError = element(by.binding('myForm.lastName.$error'));
20117        var formValid = element(by.binding('myForm.$valid'));
20118        var userNameInput = element(by.model('user.name'));
20119        var userLastInput = element(by.model('user.last'));
20120
20121        it('should initialize to model', function() {
20122          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
20123          expect(userNameValid.getText()).toContain('true');
20124          expect(formValid.getText()).toContain('true');
20125        });
20126
20127        it('should be invalid if empty when required', function() {
20128          userNameInput.clear();
20129          userNameInput.sendKeys('');
20130
20131          expect(user.getText()).toContain('{"last":"visitor"}');
20132          expect(userNameValid.getText()).toContain('false');
20133          expect(formValid.getText()).toContain('false');
20134        });
20135
20136        it('should be valid if empty when min length is set', function() {
20137          userLastInput.clear();
20138          userLastInput.sendKeys('');
20139
20140          expect(user.getText()).toContain('{"name":"guest","last":""}');
20141          expect(lastNameValid.getText()).toContain('true');
20142          expect(formValid.getText()).toContain('true');
20143        });
20144
20145        it('should be invalid if less than required min length', function() {
20146          userLastInput.clear();
20147          userLastInput.sendKeys('xx');
20148
20149          expect(user.getText()).toContain('{"name":"guest"}');
20150          expect(lastNameValid.getText()).toContain('false');
20151          expect(lastNameError.getText()).toContain('minlength');
20152          expect(formValid.getText()).toContain('false');
20153        });
20154
20155        it('should be invalid if longer than max length', function() {
20156          userLastInput.clear();
20157          userLastInput.sendKeys('some ridiculously long name');
20158
20159          expect(user.getText()).toContain('{"name":"guest"}');
20160          expect(lastNameValid.getText()).toContain('false');
20161          expect(lastNameError.getText()).toContain('maxlength');
20162          expect(formValid.getText()).toContain('false');
20163        });
20164      </file>
20165    </example>
20166 */
20167var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
20168    function($browser, $sniffer, $filter, $parse) {
20169  return {
20170    restrict: 'E',
20171    require: ['?ngModel'],
20172    link: {
20173      pre: function(scope, element, attr, ctrls) {
20174        if (ctrls[0]) {
20175          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
20176                                                              $browser, $filter, $parse);
20177        }
20178      }
20179    }
20180  };
20181}];
20182
20183
20184
20185var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
20186/**
20187 * @ngdoc directive
20188 * @name ngValue
20189 *
20190 * @description
20191 * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
20192 * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
20193 * the bound value.
20194 *
20195 * `ngValue` is useful when dynamically generating lists of radio buttons using
20196 * {@link ngRepeat `ngRepeat`}, as shown below.
20197 *
20198 * Likewise, `ngValue` can be used to generate `<option>` elements for
20199 * the {@link select `select`} element. In that case however, only strings are supported
20200 * for the `value `attribute, so the resulting `ngModel` will always be a string.
20201 * Support for `select` models with non-string values is available via `ngOptions`.
20202 *
20203 * @element input
20204 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
20205 *   of the `input` element
20206 *
20207 * @example
20208    <example name="ngValue-directive" module="valueExample">
20209      <file name="index.html">
20210       <script>
20211          angular.module('valueExample', [])
20212            .controller('ExampleController', ['$scope', function($scope) {
20213              $scope.names = ['pizza', 'unicorns', 'robots'];
20214              $scope.my = { favorite: 'unicorns' };
20215            }]);
20216       </script>
20217        <form ng-controller="ExampleController">
20218          <h2>Which is your favorite?</h2>
20219            <label ng-repeat="name in names" for="{{name}}">
20220              {{name}}
20221              <input type="radio"
20222                     ng-model="my.favorite"
20223                     ng-value="name"
20224                     id="{{name}}"
20225                     name="favorite">
20226            </label>
20227          <div>You chose {{my.favorite}}</div>
20228        </form>
20229      </file>
20230      <file name="protractor.js" type="protractor">
20231        var favorite = element(by.binding('my.favorite'));
20232
20233        it('should initialize to model', function() {
20234          expect(favorite.getText()).toContain('unicorns');
20235        });
20236        it('should bind the values to the inputs', function() {
20237          element.all(by.model('my.favorite')).get(0).click();
20238          expect(favorite.getText()).toContain('pizza');
20239        });
20240      </file>
20241    </example>
20242 */
20243var ngValueDirective = function() {
20244  return {
20245    restrict: 'A',
20246    priority: 100,
20247    compile: function(tpl, tplAttr) {
20248      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
20249        return function ngValueConstantLink(scope, elm, attr) {
20250          attr.$set('value', scope.$eval(attr.ngValue));
20251        };
20252      } else {
20253        return function ngValueLink(scope, elm, attr) {
20254          scope.$watch(attr.ngValue, function valueWatchAction(value) {
20255            attr.$set('value', value);
20256          });
20257        };
20258      }
20259    }
20260  };
20261};
20262
20263/**
20264 * @ngdoc directive
20265 * @name ngBind
20266 * @restrict AC
20267 *
20268 * @description
20269 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
20270 * with the value of a given expression, and to update the text content when the value of that
20271 * expression changes.
20272 *
20273 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
20274 * `{{ expression }}` which is similar but less verbose.
20275 *
20276 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
20277 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
20278 * element attribute, it makes the bindings invisible to the user while the page is loading.
20279 *
20280 * An alternative solution to this problem would be using the
20281 * {@link ng.directive:ngCloak ngCloak} directive.
20282 *
20283 *
20284 * @element ANY
20285 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
20286 *
20287 * @example
20288 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
20289   <example module="bindExample">
20290     <file name="index.html">
20291       <script>
20292         angular.module('bindExample', [])
20293           .controller('ExampleController', ['$scope', function($scope) {
20294             $scope.name = 'Whirled';
20295           }]);
20296       </script>
20297       <div ng-controller="ExampleController">
20298         Enter name: <input type="text" ng-model="name"><br>
20299         Hello <span ng-bind="name"></span>!
20300       </div>
20301     </file>
20302     <file name="protractor.js" type="protractor">
20303       it('should check ng-bind', function() {
20304         var nameInput = element(by.model('name'));
20305
20306         expect(element(by.binding('name')).getText()).toBe('Whirled');
20307         nameInput.clear();
20308         nameInput.sendKeys('world');
20309         expect(element(by.binding('name')).getText()).toBe('world');
20310       });
20311     </file>
20312   </example>
20313 */
20314var ngBindDirective = ['$compile', function($compile) {
20315  return {
20316    restrict: 'AC',
20317    compile: function ngBindCompile(templateElement) {
20318      $compile.$$addBindingClass(templateElement);
20319      return function ngBindLink(scope, element, attr) {
20320        $compile.$$addBindingInfo(element, attr.ngBind);
20321        element = element[0];
20322        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
20323          element.textContent = value === undefined ? '' : value;
20324        });
20325      };
20326    }
20327  };
20328}];
20329
20330
20331/**
20332 * @ngdoc directive
20333 * @name ngBindTemplate
20334 *
20335 * @description
20336 * The `ngBindTemplate` directive specifies that the element
20337 * text content should be replaced with the interpolation of the template
20338 * in the `ngBindTemplate` attribute.
20339 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
20340 * expressions. This directive is needed since some HTML elements
20341 * (such as TITLE and OPTION) cannot contain SPAN elements.
20342 *
20343 * @element ANY
20344 * @param {string} ngBindTemplate template of form
20345 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
20346 *
20347 * @example
20348 * Try it here: enter text in text box and watch the greeting change.
20349   <example module="bindExample">
20350     <file name="index.html">
20351       <script>
20352         angular.module('bindExample', [])
20353           .controller('ExampleController', ['$scope', function($scope) {
20354             $scope.salutation = 'Hello';
20355             $scope.name = 'World';
20356           }]);
20357       </script>
20358       <div ng-controller="ExampleController">
20359        Salutation: <input type="text" ng-model="salutation"><br>
20360        Name: <input type="text" ng-model="name"><br>
20361        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
20362       </div>
20363     </file>
20364     <file name="protractor.js" type="protractor">
20365       it('should check ng-bind', function() {
20366         var salutationElem = element(by.binding('salutation'));
20367         var salutationInput = element(by.model('salutation'));
20368         var nameInput = element(by.model('name'));
20369
20370         expect(salutationElem.getText()).toBe('Hello World!');
20371
20372         salutationInput.clear();
20373         salutationInput.sendKeys('Greetings');
20374         nameInput.clear();
20375         nameInput.sendKeys('user');
20376
20377         expect(salutationElem.getText()).toBe('Greetings user!');
20378       });
20379     </file>
20380   </example>
20381 */
20382var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
20383  return {
20384    compile: function ngBindTemplateCompile(templateElement) {
20385      $compile.$$addBindingClass(templateElement);
20386      return function ngBindTemplateLink(scope, element, attr) {
20387        var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
20388        $compile.$$addBindingInfo(element, interpolateFn.expressions);
20389        element = element[0];
20390        attr.$observe('ngBindTemplate', function(value) {
20391          element.textContent = value === undefined ? '' : value;
20392        });
20393      };
20394    }
20395  };
20396}];
20397
20398
20399/**
20400 * @ngdoc directive
20401 * @name ngBindHtml
20402 *
20403 * @description
20404 * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
20405 * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
20406 * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
20407 * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
20408 * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
20409 *
20410 * You may also bypass sanitization for values you know are safe. To do so, bind to
20411 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
20412 * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
20413 *
20414 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
20415 * will have an exception (instead of an exploit.)
20416 *
20417 * @element ANY
20418 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
20419 *
20420 * @example
20421
20422   <example module="bindHtmlExample" deps="angular-sanitize.js">
20423     <file name="index.html">
20424       <div ng-controller="ExampleController">
20425        <p ng-bind-html="myHTML"></p>
20426       </div>
20427     </file>
20428
20429     <file name="script.js">
20430       angular.module('bindHtmlExample', ['ngSanitize'])
20431         .controller('ExampleController', ['$scope', function($scope) {
20432           $scope.myHTML =
20433              'I am an <code>HTML</code>string with ' +
20434              '<a href="#">links!</a> and other <em>stuff</em>';
20435         }]);
20436     </file>
20437
20438     <file name="protractor.js" type="protractor">
20439       it('should check ng-bind-html', function() {
20440         expect(element(by.binding('myHTML')).getText()).toBe(
20441             'I am an HTMLstring with links! and other stuff');
20442       });
20443     </file>
20444   </example>
20445 */
20446var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
20447  return {
20448    restrict: 'A',
20449    compile: function ngBindHtmlCompile(tElement, tAttrs) {
20450      var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
20451      var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
20452        return (value || '').toString();
20453      });
20454      $compile.$$addBindingClass(tElement);
20455
20456      return function ngBindHtmlLink(scope, element, attr) {
20457        $compile.$$addBindingInfo(element, attr.ngBindHtml);
20458
20459        scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
20460          // we re-evaluate the expr because we want a TrustedValueHolderType
20461          // for $sce, not a string
20462          element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
20463        });
20464      };
20465    }
20466  };
20467}];
20468
20469/**
20470 * @ngdoc directive
20471 * @name ngChange
20472 *
20473 * @description
20474 * Evaluate the given expression when the user changes the input.
20475 * The expression is evaluated immediately, unlike the JavaScript onchange event
20476 * which only triggers at the end of a change (usually, when the user leaves the
20477 * form element or presses the return key).
20478 *
20479 * The `ngChange` expression is only evaluated when a change in the input value causes
20480 * a new value to be committed to the model.
20481 *
20482 * It will not be evaluated:
20483 * * if the value returned from the `$parsers` transformation pipeline has not changed
20484 * * if the input has continued to be invalid since the model will stay `null`
20485 * * if the model is changed programmatically and not by a change to the input value
20486 *
20487 *
20488 * Note, this directive requires `ngModel` to be present.
20489 *
20490 * @element input
20491 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
20492 * in input value.
20493 *
20494 * @example
20495 * <example name="ngChange-directive" module="changeExample">
20496 *   <file name="index.html">
20497 *     <script>
20498 *       angular.module('changeExample', [])
20499 *         .controller('ExampleController', ['$scope', function($scope) {
20500 *           $scope.counter = 0;
20501 *           $scope.change = function() {
20502 *             $scope.counter++;
20503 *           };
20504 *         }]);
20505 *     </script>
20506 *     <div ng-controller="ExampleController">
20507 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
20508 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
20509 *       <label for="ng-change-example2">Confirmed</label><br />
20510 *       <tt>debug = {{confirmed}}</tt><br/>
20511 *       <tt>counter = {{counter}}</tt><br/>
20512 *     </div>
20513 *   </file>
20514 *   <file name="protractor.js" type="protractor">
20515 *     var counter = element(by.binding('counter'));
20516 *     var debug = element(by.binding('confirmed'));
20517 *
20518 *     it('should evaluate the expression if changing from view', function() {
20519 *       expect(counter.getText()).toContain('0');
20520 *
20521 *       element(by.id('ng-change-example1')).click();
20522 *
20523 *       expect(counter.getText()).toContain('1');
20524 *       expect(debug.getText()).toContain('true');
20525 *     });
20526 *
20527 *     it('should not evaluate the expression if changing from model', function() {
20528 *       element(by.id('ng-change-example2')).click();
20529
20530 *       expect(counter.getText()).toContain('0');
20531 *       expect(debug.getText()).toContain('true');
20532 *     });
20533 *   </file>
20534 * </example>
20535 */
20536var ngChangeDirective = valueFn({
20537  restrict: 'A',
20538  require: 'ngModel',
20539  link: function(scope, element, attr, ctrl) {
20540    ctrl.$viewChangeListeners.push(function() {
20541      scope.$eval(attr.ngChange);
20542    });
20543  }
20544});
20545
20546function classDirective(name, selector) {
20547  name = 'ngClass' + name;
20548  return ['$animate', function($animate) {
20549    return {
20550      restrict: 'AC',
20551      link: function(scope, element, attr) {
20552        var oldVal;
20553
20554        scope.$watch(attr[name], ngClassWatchAction, true);
20555
20556        attr.$observe('class', function(value) {
20557          ngClassWatchAction(scope.$eval(attr[name]));
20558        });
20559
20560
20561        if (name !== 'ngClass') {
20562          scope.$watch('$index', function($index, old$index) {
20563            // jshint bitwise: false
20564            var mod = $index & 1;
20565            if (mod !== (old$index & 1)) {
20566              var classes = arrayClasses(scope.$eval(attr[name]));
20567              mod === selector ?
20568                addClasses(classes) :
20569                removeClasses(classes);
20570            }
20571          });
20572        }
20573
20574        function addClasses(classes) {
20575          var newClasses = digestClassCounts(classes, 1);
20576          attr.$addClass(newClasses);
20577        }
20578
20579        function removeClasses(classes) {
20580          var newClasses = digestClassCounts(classes, -1);
20581          attr.$removeClass(newClasses);
20582        }
20583
20584        function digestClassCounts(classes, count) {
20585          var classCounts = element.data('$classCounts') || {};
20586          var classesToUpdate = [];
20587          forEach(classes, function(className) {
20588            if (count > 0 || classCounts[className]) {
20589              classCounts[className] = (classCounts[className] || 0) + count;
20590              if (classCounts[className] === +(count > 0)) {
20591                classesToUpdate.push(className);
20592              }
20593            }
20594          });
20595          element.data('$classCounts', classCounts);
20596          return classesToUpdate.join(' ');
20597        }
20598
20599        function updateClasses(oldClasses, newClasses) {
20600          var toAdd = arrayDifference(newClasses, oldClasses);
20601          var toRemove = arrayDifference(oldClasses, newClasses);
20602          toAdd = digestClassCounts(toAdd, 1);
20603          toRemove = digestClassCounts(toRemove, -1);
20604          if (toAdd && toAdd.length) {
20605            $animate.addClass(element, toAdd);
20606          }
20607          if (toRemove && toRemove.length) {
20608            $animate.removeClass(element, toRemove);
20609          }
20610        }
20611
20612        function ngClassWatchAction(newVal) {
20613          if (selector === true || scope.$index % 2 === selector) {
20614            var newClasses = arrayClasses(newVal || []);
20615            if (!oldVal) {
20616              addClasses(newClasses);
20617            } else if (!equals(newVal,oldVal)) {
20618              var oldClasses = arrayClasses(oldVal);
20619              updateClasses(oldClasses, newClasses);
20620            }
20621          }
20622          oldVal = shallowCopy(newVal);
20623        }
20624      }
20625    };
20626
20627    function arrayDifference(tokens1, tokens2) {
20628      var values = [];
20629
20630      outer:
20631      for (var i = 0; i < tokens1.length; i++) {
20632        var token = tokens1[i];
20633        for (var j = 0; j < tokens2.length; j++) {
20634          if (token == tokens2[j]) continue outer;
20635        }
20636        values.push(token);
20637      }
20638      return values;
20639    }
20640
20641    function arrayClasses(classVal) {
20642      if (isArray(classVal)) {
20643        return classVal;
20644      } else if (isString(classVal)) {
20645        return classVal.split(' ');
20646      } else if (isObject(classVal)) {
20647        var classes = [];
20648        forEach(classVal, function(v, k) {
20649          if (v) {
20650            classes = classes.concat(k.split(' '));
20651          }
20652        });
20653        return classes;
20654      }
20655      return classVal;
20656    }
20657  }];
20658}
20659
20660/**
20661 * @ngdoc directive
20662 * @name ngClass
20663 * @restrict AC
20664 *
20665 * @description
20666 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
20667 * an expression that represents all classes to be added.
20668 *
20669 * The directive operates in three different ways, depending on which of three types the expression
20670 * evaluates to:
20671 *
20672 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
20673 * names.
20674 *
20675 * 2. If the expression evaluates to an array, each element of the array should be a string that is
20676 * one or more space-delimited class names.
20677 *
20678 * 3. If the expression evaluates to an object, then for each key-value pair of the
20679 * object with a truthy value the corresponding key is used as a class name.
20680 *
20681 * The directive won't add duplicate classes if a particular class was already set.
20682 *
20683 * When the expression changes, the previously added classes are removed and only then the
20684 * new classes are added.
20685 *
20686 * @animations
20687 * **add** - happens just before the class is applied to the elements
20688 *
20689 * **remove** - happens just before the class is removed from the element
20690 *
20691 * @element ANY
20692 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
20693 *   of the evaluation can be a string representing space delimited class
20694 *   names, an array, or a map of class names to boolean values. In the case of a map, the
20695 *   names of the properties whose values are truthy will be added as css classes to the
20696 *   element.
20697 *
20698 * @example Example that demonstrates basic bindings via ngClass directive.
20699   <example>
20700     <file name="index.html">
20701       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
20702       <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
20703       <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
20704       <input type="checkbox" ng-model="error"> error (apply "red" class)
20705       <hr>
20706       <p ng-class="style">Using String Syntax</p>
20707       <input type="text" ng-model="style" placeholder="Type: bold strike red">
20708       <hr>
20709       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
20710       <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
20711       <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
20712       <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
20713     </file>
20714     <file name="style.css">
20715       .strike {
20716         text-decoration: line-through;
20717       }
20718       .bold {
20719           font-weight: bold;
20720       }
20721       .red {
20722           color: red;
20723       }
20724     </file>
20725     <file name="protractor.js" type="protractor">
20726       var ps = element.all(by.css('p'));
20727
20728       it('should let you toggle the class', function() {
20729
20730         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
20731         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
20732
20733         element(by.model('important')).click();
20734         expect(ps.first().getAttribute('class')).toMatch(/bold/);
20735
20736         element(by.model('error')).click();
20737         expect(ps.first().getAttribute('class')).toMatch(/red/);
20738       });
20739
20740       it('should let you toggle string example', function() {
20741         expect(ps.get(1).getAttribute('class')).toBe('');
20742         element(by.model('style')).clear();
20743         element(by.model('style')).sendKeys('red');
20744         expect(ps.get(1).getAttribute('class')).toBe('red');
20745       });
20746
20747       it('array example should have 3 classes', function() {
20748         expect(ps.last().getAttribute('class')).toBe('');
20749         element(by.model('style1')).sendKeys('bold');
20750         element(by.model('style2')).sendKeys('strike');
20751         element(by.model('style3')).sendKeys('red');
20752         expect(ps.last().getAttribute('class')).toBe('bold strike red');
20753       });
20754     </file>
20755   </example>
20756
20757   ## Animations
20758
20759   The example below demonstrates how to perform animations using ngClass.
20760
20761   <example module="ngAnimate" deps="angular-animate.js" animations="true">
20762     <file name="index.html">
20763      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
20764      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
20765      <br>
20766      <span class="base-class" ng-class="myVar">Sample Text</span>
20767     </file>
20768     <file name="style.css">
20769       .base-class {
20770         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20771         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20772       }
20773
20774       .base-class.my-class {
20775         color: red;
20776         font-size:3em;
20777       }
20778     </file>
20779     <file name="protractor.js" type="protractor">
20780       it('should check ng-class', function() {
20781         expect(element(by.css('.base-class')).getAttribute('class')).not.
20782           toMatch(/my-class/);
20783
20784         element(by.id('setbtn')).click();
20785
20786         expect(element(by.css('.base-class')).getAttribute('class')).
20787           toMatch(/my-class/);
20788
20789         element(by.id('clearbtn')).click();
20790
20791         expect(element(by.css('.base-class')).getAttribute('class')).not.
20792           toMatch(/my-class/);
20793       });
20794     </file>
20795   </example>
20796
20797
20798   ## ngClass and pre-existing CSS3 Transitions/Animations
20799   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
20800   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
20801   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
20802   to view the step by step details of {@link ng.$animate#addClass $animate.addClass} and
20803   {@link ng.$animate#removeClass $animate.removeClass}.
20804 */
20805var ngClassDirective = classDirective('', true);
20806
20807/**
20808 * @ngdoc directive
20809 * @name ngClassOdd
20810 * @restrict AC
20811 *
20812 * @description
20813 * The `ngClassOdd` and `ngClassEven` directives work exactly as
20814 * {@link ng.directive:ngClass ngClass}, except they work in
20815 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
20816 *
20817 * This directive can be applied only within the scope of an
20818 * {@link ng.directive:ngRepeat ngRepeat}.
20819 *
20820 * @element ANY
20821 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
20822 *   of the evaluation can be a string representing space delimited class names or an array.
20823 *
20824 * @example
20825   <example>
20826     <file name="index.html">
20827        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
20828          <li ng-repeat="name in names">
20829           <span ng-class-odd="'odd'" ng-class-even="'even'">
20830             {{name}}
20831           </span>
20832          </li>
20833        </ol>
20834     </file>
20835     <file name="style.css">
20836       .odd {
20837         color: red;
20838       }
20839       .even {
20840         color: blue;
20841       }
20842     </file>
20843     <file name="protractor.js" type="protractor">
20844       it('should check ng-class-odd and ng-class-even', function() {
20845         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
20846           toMatch(/odd/);
20847         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
20848           toMatch(/even/);
20849       });
20850     </file>
20851   </example>
20852 */
20853var ngClassOddDirective = classDirective('Odd', 0);
20854
20855/**
20856 * @ngdoc directive
20857 * @name ngClassEven
20858 * @restrict AC
20859 *
20860 * @description
20861 * The `ngClassOdd` and `ngClassEven` directives work exactly as
20862 * {@link ng.directive:ngClass ngClass}, except they work in
20863 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
20864 *
20865 * This directive can be applied only within the scope of an
20866 * {@link ng.directive:ngRepeat ngRepeat}.
20867 *
20868 * @element ANY
20869 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
20870 *   result of the evaluation can be a string representing space delimited class names or an array.
20871 *
20872 * @example
20873   <example>
20874     <file name="index.html">
20875        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
20876          <li ng-repeat="name in names">
20877           <span ng-class-odd="'odd'" ng-class-even="'even'">
20878             {{name}} &nbsp; &nbsp; &nbsp;
20879           </span>
20880          </li>
20881        </ol>
20882     </file>
20883     <file name="style.css">
20884       .odd {
20885         color: red;
20886       }
20887       .even {
20888         color: blue;
20889       }
20890     </file>
20891     <file name="protractor.js" type="protractor">
20892       it('should check ng-class-odd and ng-class-even', function() {
20893         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
20894           toMatch(/odd/);
20895         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
20896           toMatch(/even/);
20897       });
20898     </file>
20899   </example>
20900 */
20901var ngClassEvenDirective = classDirective('Even', 1);
20902
20903/**
20904 * @ngdoc directive
20905 * @name ngCloak
20906 * @restrict AC
20907 *
20908 * @description
20909 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
20910 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
20911 * directive to avoid the undesirable flicker effect caused by the html template display.
20912 *
20913 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
20914 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
20915 * of the browser view.
20916 *
20917 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
20918 * `angular.min.js`.
20919 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20920 *
20921 * ```css
20922 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
20923 *   display: none !important;
20924 * }
20925 * ```
20926 *
20927 * When this css rule is loaded by the browser, all html elements (including their children) that
20928 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
20929 * during the compilation of the template it deletes the `ngCloak` element attribute, making
20930 * the compiled element visible.
20931 *
20932 * For the best result, the `angular.js` script must be loaded in the head section of the html
20933 * document; alternatively, the css rule above must be included in the external stylesheet of the
20934 * application.
20935 *
20936 * Legacy browsers, like IE7, do not provide attribute selector support (a
20936dded in CSS 2.1) so they
20937 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
20938 * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
20939 *
20940 * @element ANY
20941 *
20942 * @example
20943   <example>
20944     <file name="index.html">
20945        <div id="template1" ng-cloak>{{ 'hello' }}</div>
20946        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
20947     </file>
20948     <file name="protractor.js" type="protractor">
20949       it('should remove the template directive and css class', function() {
20950         expect($('#template1').getAttribute('ng-cloak')).
20951           toBeNull();
20952         expect($('#template2').getAttribute('ng-cloak')).
20953           toBeNull();
20954       });
20955     </file>
20956   </example>
20957 *
20958 */
20959var ngCloakDirective = ngDirective({
20960  compile: function(element, attr) {
20961    attr.$set('ngCloak', undefined);
20962    element.removeClass('ng-cloak');
20963  }
20964});
20965
20966/**
20967 * @ngdoc directive
20968 * @name ngController
20969 *
20970 * @description
20971 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
20972 * supports the principles behind the Model-View-Controller design pattern.
20973 *
20974 * MVC components in angular:
20975 *
20976 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
20977 *   are accessed through bindings.
20978 * * View — The template (HTML with data bindings) that is rendered into the View.
20979 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
20980 *   logic behind the application to decorate the scope with functions and values
20981 *
20982 * Note that you can also attach controllers to the DOM by declaring it in a route definition
20983 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
20984 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
20985 * and executed twice.
20986 *
20987 * @element ANY
20988 * @scope
20989 * @priority 500
20990 * @param {expression} ngController Name of a constructor function registered with the current
20991 * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
20992 * that on the current scope evaluates to a constructor function.
20993 *
20994 * The controller instance can be published into a scope property by specifying
20995 * `ng-controller="as propertyName"`.
20996 *
20997 * If the current `$controllerProvider` is configured to use globals (via
20998 * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
20999 * also be the name of a globally accessible constructor function (not recommended).
21000 *
21001 * @example
21002 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
21003 * greeting are methods declared on the controller (see source tab). These methods can
21004 * easily be called from the angular markup. Any changes to the data are automatically reflected
21005 * in the View without the need for a manual update.
21006 *
21007 * Two different declaration styles are included below:
21008 *
21009 * * one binds methods and properties directly onto the controller using `this`:
21010 * `ng-controller="SettingsController1 as settings"`
21011 * * one injects `$scope` into the controller:
21012 * `ng-controller="SettingsController2"`
21013 *
21014 * The second option is more common in the Angular community, and is generally used in boilerplates
21015 * and in this guide. However, there are advantages to binding properties directly to the controller
21016 * and avoiding scope.
21017 *
21018 * * Using `controller as` makes it obvious which controller you are accessing in the template when
21019 * multiple controllers apply to an element.
21020 * * If you are writing your controllers as classes you have easier access to the properties and
21021 * methods, which will appear on the scope, from inside the controller code.
21022 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
21023 * inheritance masking primitives.
21024 *
21025 * This example demonstrates the `controller as` syntax.
21026 *
21027 * <example name="ngControllerAs" module="controllerAsExample">
21028 *   <file name="index.html">
21029 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
21030 *      Name: <input type="text" ng-model="settings.name"/>
21031 *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
21032 *      Contact:
21033 *      <ul>
21034 *        <li ng-repeat="contact in settings.contacts">
21035 *          <select ng-model="contact.type">
21036 *             <option>phone</option>
21037 *             <option>email</option>
21038 *          </select>
21039 *          <input type="text" ng-model="contact.value"/>
21040 *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
21041 *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
21042 *        </li>
21043 *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
21044 *     </ul>
21045 *    </div>
21046 *   </file>
21047 *   <file name="app.js">
21048 *    angular.module('controllerAsExample', [])
21049 *      .controller('SettingsController1', SettingsController1);
21050 *
21051 *    function SettingsController1() {
21052 *      this.name = "John Smith";
21053 *      this.contacts = [
21054 *        {type: 'phone', value: '408 555 1212'},
21055 *        {type: 'email', value: '[email protected]'} ];
21056 *    }
21057 *
21058 *    SettingsController1.prototype.greet = function() {
21059 *      alert(this.name);
21060 *    };
21061 *
21062 *    SettingsController1.prototype.addContact = function() {
21063 *      this.contacts.push({type: 'email', value: '[email protected]'});
21064 *    };
21065 *
21066 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
21067 *     var index = this.contacts.indexOf(contactToRemove);
21068 *      this.contacts.splice(index, 1);
21069 *    };
21070 *
21071 *    SettingsController1.prototype.clearContact = function(contact) {
21072 *      contact.type = 'phone';
21073 *      contact.value = '';
21074 *    };
21075 *   </file>
21076 *   <file name="protractor.js" type="protractor">
21077 *     it('should check controller as', function() {
21078 *       var container = element(by.id('ctrl-as-exmpl'));
21079 *         expect(container.element(by.model('settings.name'))
21080 *           .getAttribute('value')).toBe('John Smith');
21081 *
21082 *       var firstRepeat =
21083 *           container.element(by.repeater('contact in settings.contacts').row(0));
21084 *       var secondRepeat =
21085 *           container.element(by.repeater('contact in settings.contacts').row(1));
21086 *
21087 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21088 *           .toBe('408 555 1212');
21089 *
21090 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21091 *           .toBe('[email protected]');
21092 *
21093 *       firstRepeat.element(by.linkText('clear')).click();
21094 *
21095 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21096 *           .toBe('');
21097 *
21098 *       container.element(by.linkText('add')).click();
21099 *
21100 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
21101 *           .element(by.model('contact.value'))
21102 *           .getAttribute('value'))
21103 *           .toBe('[email protected]');
21104 *     });
21105 *   </file>
21106 * </example>
21107 *
21108 * This example demonstrates the "attach to `$scope`" style of controller.
21109 *
21110 * <example name="ngController" module="controllerExample">
21111 *  <file name="index.html">
21112 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
21113 *     Name: <input type="text" ng-model="name"/>
21114 *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
21115 *     Contact:
21116 *     <ul>
21117 *       <li ng-repeat="contact in contacts">
21118 *         <select ng-model="contact.type">
21119 *            <option>phone</option>
21120 *            <option>email</option>
21121 *         </select>
21122 *         <input type="text" ng-model="contact.value"/>
21123 *         [ <a href="" ng-click="clearContact(contact)">clear</a>
21124 *         | <a href="" ng-click="removeContact(contact)">X</a> ]
21125 *       </li>
21126 *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
21127 *    </ul>
21128 *   </div>
21129 *  </file>
21130 *  <file name="app.js">
21131 *   angular.module('controllerExample', [])
21132 *     .controller('SettingsController2', ['$scope', SettingsController2]);
21133 *
21134 *   function SettingsController2($scope) {
21135 *     $scope.name = "John Smith";
21136 *     $scope.contacts = [
21137 *       {type:'phone', value:'408 555 1212'},
21138 *       {type:'email', value:'[email protected]'} ];
21139 *
21140 *     $scope.greet = function() {
21141 *       alert($scope.name);
21142 *     };
21143 *
21144 *     $scope.addContact = function() {
21145 *       $scope.contacts.push({type:'email', value:'[email protected]'});
21146 *     };
21147 *
21148 *     $scope.removeContact = function(contactToRemove) {
21149 *       var index = $scope.contacts.indexOf(contactToRemove);
21150 *       $scope.contacts.splice(index, 1);
21151 *     };
21152 *
21153 *     $scope.clearContact = function(contact) {
21154 *       contact.type = 'phone';
21155 *       contact.value = '';
21156 *     };
21157 *   }
21158 *  </file>
21159 *  <file name="protractor.js" type="protractor">
21160 *    it('should check controller', function() {
21161 *      var container = element(by.id('ctrl-exmpl'));
21162 *
21163 *      expect(container.element(by.model('name'))
21164 *          .getAttribute('value')).toBe('John Smith');
21165 *
21166 *      var firstRepeat =
21167 *          container.element(by.repeater('contact in contacts').row(0));
21168 *      var secondRepeat =
21169 *          container.element(by.repeater('contact in contacts').row(1));
21170 *
21171 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21172 *          .toBe('408 555 1212');
21173 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
21174 *          .toBe('[email protected]');
21175 *
21176 *      firstRepeat.element(by.linkText('clear')).click();
21177 *
21178 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
21179 *          .toBe('');
21180 *
21181 *      container.element(by.linkText('add')).click();
21182 *
21183 *      expect(container.element(by.repeater('contact in contacts').row(2))
21184 *          .element(by.model('contact.value'))
21185 *          .getAttribute('value'))
21186 *          .toBe('[email protected]');
21187 *    });
21188 *  </file>
21189 *</example>
21190
21191 */
21192var ngControllerDirective = [function() {
21193  return {
21194    restrict: 'A',
21195    scope: true,
21196    controller: '@',
21197    priority: 500
21198  };
21199}];
21200
21201/**
21202 * @ngdoc directive
21203 * @name ngCsp
21204 *
21205 * @element html
21206 * @description
21207 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
21208 *
21209 * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
21210 *
21211 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
21212 * For Angular to be CSP compatible there are only two things that we need to do differently:
21213 *
21214 * - don't use `Function` constructor to generate optimized value getters
21215 * - don't inject custom stylesheet into the document
21216 *
21217 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
21218 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
21219 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
21220 * be raised.
21221 *
21222 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
21223 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
21224 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
21225 *
21226 * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
21227 * autodetection however triggers a CSP error to be logged in the console:
21228 *
21229 * ```
21230 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
21231 * script in the following Content Security Policy directive: "default-src 'self'". Note that
21232 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
21233 * ```
21234 *
21235 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
21236 * directive on the root element of the application or on the `angular.js` script tag, whichever
21237 * appears first in the html document.
21238 *
21239 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
21240 *
21241 * @example
21242 * This example shows how to apply the `ngCsp` directive to the `html` tag.
21243   ```html
21244     <!doctype html>
21245     <html ng-app ng-csp>
21246     ...
21247     ...
21248     </html>
21249   ```
21250  * @example
21251      // Note: the suffix `.csp` in the example name triggers
21252      // csp mode in our http server!
21253      <example name="example.csp" module="cspExample" ng-csp="true">
21254        <file name="index.html">
21255          <div ng-controller="MainController as ctrl">
21256            <div>
21257              <button ng-click="ctrl.inc()" id="inc">Increment</button>
21258              <span id="counter">
21259                {{ctrl.counter}}
21260              </span>
21261            </div>
21262
21263            <div>
21264              <button ng-click="ctrl.evil()" id="evil">Evil</button>
21265              <span id="evilError">
21266                {{ctrl.evilError}}
21267              </span>
21268            </div>
21269          </div>
21270        </file>
21271        <file name="script.js">
21272           angular.module('cspExample', [])
21273             .controller('MainController', function() {
21274                this.counter = 0;
21275                this.inc = function() {
21276                  this.counter++;
21277                };
21278                this.evil = function() {
21279                  // jshint evil:true
21280                  try {
21281                    eval('1+2');
21282                  } catch (e) {
21283                    this.evilError = e.message;
21284                  }
21285                };
21286              });
21287        </file>
21288        <file name="protractor.js" type="protractor">
21289          var util, webdriver;
21290
21291          var incBtn = element(by.id('inc'));
21292          var counter = element(by.id('counter'));
21293          var evilBtn = element(by.id('evil'));
21294          var evilError = element(by.id('evilError'));
21295
21296          function getAndClearSevereErrors() {
21297            return browser.manage().logs().get('browser').then(function(browserLog) {
21298              return browserLog.filter(function(logEntry) {
21299                return logEntry.level.value > webdriver.logging.Level.WARNING.value;
21300              });
21301            });
21302          }
21303
21304          function clearErrors() {
21305            getAndClearSevereErrors();
21306          }
21307
21308          function expectNoErrors() {
21309            getAndClearSevereErrors().then(function(filteredLog) {
21310              expect(filteredLog.length).toEqual(0);
21311              if (filteredLog.length) {
21312                console.log('browser console errors: ' + util.inspect(filteredLog));
21313              }
21314            });
21315          }
21316
21317          function expectError(regex) {
21318            getAndClearSevereErrors().then(function(filteredLog) {
21319              var found = false;
21320              filteredLog.forEach(function(log) {
21321                if (log.message.match(regex)) {
21322                  found = true;
21323                }
21324              });
21325              if (!found) {
21326                throw new Error('expected an error that matches ' + regex);
21327              }
21328            });
21329          }
21330
21331          beforeEach(function() {
21332            util = require('util');
21333            webdriver = require('protractor/node_modules/selenium-webdriver');
21334          });
21335
21336          // For now, we only test on Chrome,
21337          // as Safari does not load the page with Protractor's injected scripts,
21338          // and Firefox webdriver always disables content security policy (#6358)
21339          if (browser.params.browser !== 'chrome') {
21340            return;
21341          }
21342
21343          it('should not report errors when the page is loaded', function() {
21344            // clear errors so we are not dependent on previous tests
21345            clearErrors();
21346            // Need to reload the page as the page is already loaded when
21347            // we come here
21348            browser.driver.getCurrentUrl().then(function(url) {
21349              browser.get(url);
21350            });
21351            expectNoErrors();
21352          });
21353
21354          it('should evaluate expressions', function() {
21355            expect(counter.getText()).toEqual('0');
21356            incBtn.click();
21357            expect(counter.getText()).toEqual('1');
21358            expectNoErrors();
21359          });
21360
21361          it('should throw and report an error when using "eval"', function() {
21362            evilBtn.click();
21363            expect(evilError.getText()).toMatch(/Content Security Policy/);
21364            expectError(/Content Security Policy/);
21365          });
21366        </file>
21367      </example>
21368  */
21369
21370// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
21371// bootstrap the system (before $parse is instantiated), for this reason we just have
21372// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
21373
21374/**
21375 * @ngdoc directive
21376 * @name ngClick
21377 *
21378 * @description
21379 * The ngClick directive allows you to specify custom behavior when
21380 * an element is clicked.
21381 *
21382 * @element ANY
21383 * @priority 0
21384 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
21385 * click. ({@link guide/expression#-event- Event object is available as `$event`})
21386 *
21387 * @example
21388   <example>
21389     <file name="index.html">
21390      <button ng-click="count = count + 1" ng-init="count=0">
21391        Increment
21392      </button>
21393      <span>
21394        count: {{count}}
21395      </span>
21396     </file>
21397     <file name="protractor.js" type="protractor">
21398       it('should check ng-click', function() {
21399         expect(element(by.binding('count')).getText()).toMatch('0');
21400         element(by.css('button')).click();
21401         expect(element(by.binding('count')).getText()).toMatch('1');
21402       });
21403     </file>
21404   </example>
21405 */
21406/*
21407 * A collection of directives that allows creation of custom event handlers that are defined as
21408 * angular expressions and are compiled and executed within the current scope.
21409 */
21410var ngEventDirectives = {};
21411
21412// For events that might fire synchronously during DOM manipulation
21413// we need to execute their event handlers asynchronously using $evalAsync,
21414// so that they are not executed in an inconsistent state.
21415var forceAsyncEvents = {
21416  'blur': true,
21417  'focus': true
21418};
21419forEach(
21420  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
21421  function(eventName) {
21422    var directiveName = directiveNormalize('ng-' + eventName);
21423    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
21424      return {
21425        restrict: 'A',
21426        compile: function($element, attr) {
21427          // We expose the powerful $event object on the scope that provides access to the Window,
21428          // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
21429          // checks at the cost of speed since event handler expressions are not executed as
21430          // frequently as regular change detection.
21431          var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
21432          return function ngEventHandler(scope, element) {
21433            element.on(eventName, function(event) {
21434              var callback = function() {
21435                fn(scope, {$event:event});
21436              };
21437              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
21438                scope.$evalAsync(callback);
21439              } else {
21440                scope.$apply(callback);
21441              }
21442            });
21443          };
21444        }
21445      };
21446    }];
21447  }
21448);
21449
21450/**
21451 * @ngdoc directive
21452 * @name ngDblclick
21453 *
21454 * @description
21455 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
21456 *
21457 * @element ANY
21458 * @priority 0
21459 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
21460 * a dblclick. (The Event object is available as `$event`)
21461 *
21462 * @example
21463   <example>
21464     <file name="index.html">
21465      <button ng-dblclick="count = count + 1" ng-init="count=0">
21466        Increment (on double click)
21467      </button>
21468      count: {{count}}
21469     </file>
21470   </example>
21471 */
21472
21473
21474/**
21475 * @ngdoc directive
21476 * @name ngMousedown
21477 *
21478 * @description
21479 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
21480 *
21481 * @element ANY
21482 * @priority 0
21483 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
21484 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
21485 *
21486 * @example
21487   <example>
21488     <file name="index.html">
21489      <button ng-mousedown="count = count + 1" ng-init="count=0">
21490        Increment (on mouse down)
21491      </button>
21492      count: {{count}}
21493     </file>
21494   </example>
21495 */
21496
21497
21498/**
21499 * @ngdoc directive
21500 * @name ngMouseup
21501 *
21502 * @description
21503 * Specify custom behavior on mouseup event.
21504 *
21505 * @element ANY
21506 * @priority 0
21507 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
21508 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
21509 *
21510 * @example
21511   <example>
21512     <file name="index.html">
21513      <button ng-mouseup="count = count + 1" ng-init="count=0">
21514        Increment (on mouse up)
21515      </button>
21516      count: {{count}}
21517     </file>
21518   </example>
21519 */
21520
21521/**
21522 * @ngdoc directive
21523 * @name ngMouseover
21524 *
21525 * @description
21526 * Specify custom behavior on mouseover event.
21527 *
21528 * @element ANY
21529 * @priority 0
21530 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
21531 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
21532 *
21533 * @example
21534   <example>
21535     <file name="index.html">
21536      <button ng-mouseover="count = count + 1" ng-init="count=0">
21537        Increment (when mouse is over)
21538      </button>
21539      count: {{count}}
21540     </file>
21541   </example>
21542 */
21543
21544
21545/**
21546 * @ngdoc directive
21547 * @name ngMouseenter
21548 *
21549 * @description
21550 * Specify custom behavior on mouseenter event.
21551 *
21552 * @element ANY
21553 * @priority 0
21554 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
21555 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
21556 *
21557 * @example
21558   <example>
21559     <file name="index.html">
21560      <button ng-mouseenter="count = count + 1" ng-init="count=0">
21561        Increment (when mouse enters)
21562      </button>
21563      count: {{count}}
21564     </file>
21565   </example>
21566 */
21567
21568
21569/**
21570 * @ngdoc directive
21571 * @name ngMouseleave
21572 *
21573 * @description
21574 * Specify custom behavior on mouseleave event.
21575 *
21576 * @element ANY
21577 * @priority 0
21578 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
21579 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
21580 *
21581 * @example
21582   <example>
21583     <file name="index.html">
21584      <button ng-mouseleave="count = count + 1" ng-init="count=0">
21585        Increment (when mouse leaves)
21586      </button>
21587      count: {{count}}
21588     </file>
21589   </example>
21590 */
21591
21592
21593/**
21594 * @ngdoc directive
21595 * @name ngMousemove
21596 *
21597 * @description
21598 * Specify custom behavior on mousemove event.
21599 *
21600 * @element ANY
21601 * @priority 0
21602 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
21603 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
21604 *
21605 * @example
21606   <example>
21607     <file name="index.html">
21608      <button ng-mousemove="count = count + 1" ng-init="count=0">
21609        Increment (when mouse moves)
21610      </button>
21611      count: {{count}}
21612     </file>
21613   </example>
21614 */
21615
21616
21617/**
21618 * @ngdoc directive
21619 * @name ngKeydown
21620 *
21621 * @description
21622 * Specify custom behavior on keydown event.
21623 *
21624 * @element ANY
21625 * @priority 0
21626 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
21627 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21628 *
21629 * @example
21630   <example>
21631     <file name="index.html">
21632      <input ng-keydown="count = count + 1" ng-init="count=0">
21633      key down count: {{count}}
21634     </file>
21635   </example>
21636 */
21637
21638
21639/**
21640 * @ngdoc directive
21641 * @name ngKeyup
21642 *
21643 * @description
21644 * Specify custom behavior on keyup event.
21645 *
21646 * @element ANY
21647 * @priority 0
21648 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
21649 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
21650 *
21651 * @example
21652   <example>
21653     <file name="index.html">
21654       <p>Typing in the input box below updates the key count</p>
21655       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
21656
21657       <p>Typing in the input box below updates the keycode</p>
21658       <input ng-keyup="event=$event">
21659       <p>event keyCode: {{ event.keyCode }}</p>
21660       <p>event altKey: {{ event.altKey }}</p>
21661     </file>
21662   </example>
21663 */
21664
21665
21666/**
21667 * @ngdoc directive
21668 * @name ngKeypress
21669 *
21670 * @description
21671 * Specify custom behavior on keypress event.
21672 *
21673 * @element ANY
21674 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
21675 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
21676 * and can be interrogated for keyCode, altKey, etc.)
21677 *
21678 * @example
21679   <example>
21680     <file name="index.html">
21681      <input ng-keypress="count = count + 1" ng-init="count=0">
21682      key press count: {{count}}
21683     </file>
21684   </example>
21685 */
21686
21687
21688/**
21689 * @ngdoc directive
21690 * @name ngSubmit
21691 *
21692 * @description
21693 * Enables binding angular expressions to onsubmit events.
21694 *
21695 * Additionally it prevents the default action (which for form means 
21695sending the request to the
21696 * server and reloading the current page), but only if the form does not contain `action`,
21697 * `data-action`, or `x-action` attributes.
21698 *
21699 * <div class="alert alert-warning">
21700 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
21701 * `ngSubmit` handlers together. See the
21702 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
21703 * for a detailed discussion of when `ngSubmit` may be triggered.
21704 * </div>
21705 *
21706 * @element form
21707 * @priority 0
21708 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
21709 * ({@link guide/expression#-event- Event object is available as `$event`})
21710 *
21711 * @example
21712   <example module="submitExample">
21713     <file name="index.html">
21714      <script>
21715        angular.module('submitExample', [])
21716          .controller('ExampleController', ['$scope', function($scope) {
21717            $scope.list = [];
21718            $scope.text = 'hello';
21719            $scope.submit = function() {
21720              if ($scope.text) {
21721                $scope.list.push(this.text);
21722                $scope.text = '';
21723              }
21724            };
21725          }]);
21726      </script>
21727      <form ng-submit="submit()" ng-controller="ExampleController">
21728        Enter text and hit enter:
21729        <input type="text" ng-model="text" name="text" />
21730        <input type="submit" id="submit" value="Submit" />
21731        <pre>list={{list}}</pre>
21732      </form>
21733     </file>
21734     <file name="protractor.js" type="protractor">
21735       it('should check ng-submit', function() {
21736         expect(element(by.binding('list')).getText()).toBe('list=[]');
21737         element(by.css('#submit')).click();
21738         expect(element(by.binding('list')).getText()).toContain('hello');
21739         expect(element(by.model('text')).getAttribute('value')).toBe('');
21740       });
21741       it('should ignore empty strings', function() {
21742         expect(element(by.binding('list')).getText()).toBe('list=[]');
21743         element(by.css('#submit')).click();
21744         element(by.css('#submit')).click();
21745         expect(element(by.binding('list')).getText()).toContain('hello');
21746        });
21747     </file>
21748   </example>
21749 */
21750
21751/**
21752 * @ngdoc directive
21753 * @name ngFocus
21754 *
21755 * @description
21756 * Specify custom behavior on focus event.
21757 *
21758 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
21759 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
21760 * during an `$apply` to ensure a consistent state.
21761 *
21762 * @element window, input, select, textarea, a
21763 * @priority 0
21764 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
21765 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
21766 *
21767 * @example
21768 * See {@link ng.directive:ngClick ngClick}
21769 */
21770
21771/**
21772 * @ngdoc directive
21773 * @name ngBlur
21774 *
21775 * @description
21776 * Specify custom behavior on blur event.
21777 *
21778 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
21779 * an element has lost focus.
21780 *
21781 * Note: As the `blur` event is executed synchronously also during DOM manipulations
21782 * (e.g. removing a focussed input),
21783 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
21784 * during an `$apply` to ensure a consistent state.
21785 *
21786 * @element window, input, select, textarea, a
21787 * @priority 0
21788 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
21789 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
21790 *
21791 * @example
21792 * See {@link ng.directive:ngClick ngClick}
21793 */
21794
21795/**
21796 * @ngdoc directive
21797 * @name ngCopy
21798 *
21799 * @description
21800 * Specify custom behavior on copy event.
21801 *
21802 * @element window, input, select, textarea, a
21803 * @priority 0
21804 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
21805 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
21806 *
21807 * @example
21808   <example>
21809     <file name="index.html">
21810      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
21811      copied: {{copied}}
21812     </file>
21813   </example>
21814 */
21815
21816/**
21817 * @ngdoc directive
21818 * @name ngCut
21819 *
21820 * @description
21821 * Specify custom behavior on cut event.
21822 *
21823 * @element window, input, select, textarea, a
21824 * @priority 0
21825 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
21826 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
21827 *
21828 * @example
21829   <example>
21830     <file name="index.html">
21831      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
21832      cut: {{cut}}
21833     </file>
21834   </example>
21835 */
21836
21837/**
21838 * @ngdoc directive
21839 * @name ngPaste
21840 *
21841 * @description
21842 * Specify custom behavior on paste event.
21843 *
21844 * @element window, input, select, textarea, a
21845 * @priority 0
21846 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
21847 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
21848 *
21849 * @example
21850   <example>
21851     <file name="index.html">
21852      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
21853      pasted: {{paste}}
21854     </file>
21855   </example>
21856 */
21857
21858/**
21859 * @ngdoc directive
21860 * @name ngIf
21861 * @restrict A
21862 *
21863 * @description
21864 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
21865 * {expression}. If the expression assigned to `ngIf` evaluates to a false
21866 * value then the element is removed from the DOM, otherwise a clone of the
21867 * element is reinserted into the DOM.
21868 *
21869 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
21870 * element in the DOM rather than changing its visibility via the `display` css property.  A common
21871 * case when this difference is significant is when using css selectors that rely on an element's
21872 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
21872s.
21873 *
21874 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
21875 * is created when the element is restored.  The scope created within `ngIf` inherits from
21876 * its parent scope using
21877 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
21878 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
21879 * a javascript primitive defined in the parent scope. In this case any modifications made to the
21880 * variable within the child scope will override (hide) the value in the parent scope.
21881 *
21882 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
21883 * is if an element's class attribute is directly modified after it's compiled, using something like
21884 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
21885 * the added class will be lost because the original compiled state is used to regenerate the element.
21886 *
21887 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
21888 * and `leave` effects.
21889 *
21890 * @animations
21891 * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
21892 * leave - happens just before the `ngIf` contents are removed from the DOM
21893 *
21894 * @element ANY
21895 * @scope
21896 * @priority 600
21897 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
21898 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
21899 *     element is added to the DOM tree.
21900 *
21901 * @example
21902  <example module="ngAnimate" deps="angular-animate.js" animations="true">
21903    <file name="index.html">
21904      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
21905      Show when checked:
21906      <span ng-if="checked" class="animate-if">
21907        This is removed when the checkbox is unchecked.
21908      </span>
21909    </file>
21910    <file name="animations.css">
21911      .animate-if {
21912        background:white;
21913        border:1px solid black;
21914        padding:10px;
21915      }
21916
21917      .animate-if.ng-enter, .animate-if.ng-leave {
21918        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21919        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
21920      }
21921
21922      .animate-if.ng-enter,
21923      .animate-if.ng-leave.ng-leave-active {
21924        opacity:0;
21925      }
21926
21927      .animate-if.ng-leave,
21928      .animate-if.ng-enter.ng-enter-active {
21929        opacity:1;
21930      }
21931    </file>
21932  </example>
21933 */
21934var ngIfDirective = ['$animate', function($animate) {
21935  return {
21936    multiElement: true,
21937    transclude: 'element',
21938    priority: 600,
21939    terminal: true,
21940    restrict: 'A',
21941    $$tlb: true,
21942    link: function($scope, $element, $attr, ctrl, $transclude) {
21943        var block, childScope, previousElements;
21944        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
21945
21946          if (value) {
21947            if (!childScope) {
21948              $transclude(function(clone, newScope) {
21949                childScope = newScope;
21950                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
21951                // Note: We only need the first/last node of the cloned nodes.
21952                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
21953                // by a directive with templateUrl when its template arrives.
21954                block = {
21955                  clone: clone
21956                };
21957                $animate.enter(clone, $element.parent(), $element);
21958              });
21959            }
21960          } else {
21961            if (previousElements) {
21962              previousElements.remove();
21963              previousElements = null;
21964            }
21965            if (childScope) {
21966              childScope.$destroy();
21967              childScope = null;
21968            }
21969            if (block) {
21970              previousElements = getBlockNodes(block.clone);
21971              $animate.leave(previousElements).then(function() {
21972                previousElements = null;
21973              });
21974              block = null;
21975            }
21976          }
21977        });
21978    }
21979  };
21980}];
21981
21982/**
21983 * @ngdoc directive
21984 * @name ngInclude
21985 * @restrict ECA
21986 *
21987 * @description
21988 * Fetches, compiles and includes an external HTML fragment.
21989 *
21990 * By default, the template URL is restricted to the same domain and protocol as the
21991 * application document. This is done by calling {@link $sce#getTrustedResourceUrl
21992 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
21993 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
21994 * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
21995 * ng.$sce Strict Contextual Escaping}.
21996 *
21997 * In addition, the browser's
21998 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
21999 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
22000 * policy may further restrict whether the template is successfully loaded.
22001 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
22002 * access on some browsers.
22003 *
22004 * @animations
22005 * enter - animation is used to bring new content into the browser.
22006 * leave - animation is used to animate existing content away.
22007 *
22008 * The enter and leave animation occur concurrently.
22009 *
22010 * @scope
22011 * @priority 400
22012 *
22013 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
22014 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
22015 * @param {string=} onload Expression to evaluate when a new partial is loaded.
22016 *
22017 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
22018 *                  $anchorScroll} to scroll the viewport after the content is loaded.
22019 *
22020 *                  - If the attribute is not set, disable scrolling.
22021 *                  - If the attribute is set without value, enable scrolling.
22022 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
22023 *
22024 * @example
22025  <example module="includeExample" deps="angular-animate.js" animations="true">
22026    <file name="index.html">
22027     <div ng-controller="ExampleController">
22028       <select ng-model="template" ng-options="t.name for t in templates">
22029        <option value="">(blank)</option>
22030       </select>
22031       url of the template: <code>{{template.url}}</code>
22032       <hr/>
22033       <div class="slide-animate-container">
22034         <div class="slide-animate" ng-include="template.url"></div>
22035       </div>
22036     </div>
22037    </file>
22038    <file name="script.js">
22039      angular.module('includeExample', ['ngAnimate'])
22040        .controller('ExampleController', ['$scope', function($scope) {
22041          $scope.templates =
22042            [ { name: 'template1.html', url: 'template1.html'},
22043              { name: 'template2.html', url: 'template2.html'} ];
22044          $scope.template = $scope.templates[0];
22045        }]);
22046     </file>
22047    <file name="template1.html">
22048      Content of template1.html
22049    </file>
22050    <file name="template2.html">
22051      Content of template2.html
22052    </file>
22053    <file name="animations.css">
22054      .slide-animate-container {
22055        position:relative;
22056        background:white;
22057        border:1px solid black;
22058        height:40px;
22059        overflow:hidden;
22060      }
22061
22062      .slide-animate {
22063        padding:10px;
22064      }
22065
22066      .slide-animate.ng-enter, .slide-animate.ng-leave {
22067        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22068        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22069
22070        position:absolute;
22071        top:0;
22072        left:0;
22073        right:0;
22074        bottom:0;
22075        display:block;
22076        padding:10px;
22077      }
22078
22079      .slide-animate.ng-enter {
22080        top:-50px;
22081      }
22082      .slide-animate.ng-enter.ng-enter-active {
22083        top:0;
22084      }
22085
22086      .slide-animate.ng-leave {
22087        top:0;
22088      }
22089      .slide-animate.ng-leave.ng-leave-active {
22090        top:50px;
22091      }
22092    </file>
22093    <file name="protractor.js" type="protractor">
22094      var templateSelect = element(by.model('template'));
22095      var includeElem = element(by.css('[ng-include]'));
22096
22097      it('should load template1.html', function() {
22098        expect(includeElem.getText()).toMatch(/Content of template1.html/);
22099      });
22100
22101      it('should load template2.html', function() {
22102        if (browser.params.browser == 'firefox') {
22103          // Firefox can't handle using selects
22104          // See https://github.com/angular/protractor/issues/480
22105          return;
22106        }
22107        templateSelect.click();
22108        templateSelect.all(by.css('option')).get(2).click();
22109        expect(includeElem.getText()).toMatch(/Content of template2.html/);
22110      });
22111
22112      it('should change to blank', function() {
22113        if (browser.params.browser == 'firefox') {
22114          // Firefox can't handle using selects
22115          return;
22116        }
22117        templateSelect.click();
22118        templateSelect.all(by.css('option')).get(0).click();
22119        expect(includeElem.isPresent()).toBe(false);
22120      });
22121    </file>
22122  </example>
22123 */
22124
22125
22126/**
22127 * @ngdoc event
22128 * @name ngInclude#$includeContentRequested
22129 * @eventType emit on the scope ngInclude was declared in
22130 * @description
22131 * Emitted every time the ngInclude content is requested.
22132 *
22133 * @param {Object} angularEvent Synthetic event object.
22134 * @param {String} src URL of content to load.
22135 */
22136
22137
22138/**
22139 * @ngdoc event
22140 * @name ngInclude#$includeContentLoaded
22141 * @eventType emit on the current ngInclude scope
22142 * @description
22143 * Emitted every time the ngInclude content is reloaded.
22144 *
22145 * @param {Object} angularEvent Synthetic event object.
22146 * @param {String} src URL of content to load.
22147 */
22148
22149
22150/**
22151 * @ngdoc event
22152 * @name ngInclude#$includeContentError
22153 * @eventType emit on the scope ngInclude was declared in
22154 * @description
22155 * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
22156 *
22157 * @param {Object} angularEvent Synthetic event object.
22158 * @param {String} src URL of content to load.
22159 */
22160var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
22161                  function($templateRequest,   $anchorScroll,   $animate,   $sce) {
22162  return {
22163    restrict: 'ECA',
22164    priority: 400,
22165    terminal: true,
22166    transclude: 'element',
22167    controller: angular.noop,
22168    compile: function(element, attr) {
22169      var srcExp = attr.ngInclude || attr.src,
22170          onloadExp = attr.onload || '',
22171          autoScrollExp = attr.autoscroll;
22172
22173      return function(scope, $element, $attr, ctrl, $transclude) {
22174        var changeCounter = 0,
22175            currentScope,
22176            previousElement,
22177            currentElement;
22178
22179        var cleanupLastIncludeContent = function() {
22180          if (previousElement) {
22181            previousElement.remove();
22182            previousElement = null;
22183          }
22184          if (currentScope) {
22185            currentScope.$destroy();
22186            currentScope = null;
22187          }
22188          if (currentElement) {
22189            $animate.leave(currentElement).then(function() {
22190              previousElement = null;
22191            });
22192            previousElement = currentElement;
22193            currentElement = null;
22194          }
22195        };
22196
22197        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
22198          var afterAnimation = function() {
22199            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
22200              $anchorScroll();
22201            }
22202          };
22203          var thisChangeId = ++changeCounter;
22204
22205          if (src) {
22206            //set the 2nd param to true to ignore the template request error so that the inner
22207            //contents and scope can be cleaned up.
22208            $templateRequest(src, true).then(function(response) {
22209              if (thisChangeId !== changeCounter) return;
22210              var newScope = scope.$new();
22211              ctrl.template = response;
22212
22213              // Note: This will also link all children of ng-include that were contained in the original
22214              // html. If that content contains controllers, ... they could pollute/change the scope.
22215              // However, using ng-include on an element with additional content does not make sense...
22216              // Note: We can't remove them in the cloneAttchFn of $transclude as that
22217              // function is called before linking the content, which would apply child
22218              // directives to non existing elements.
22219              var clone = $transclude(newScope, function(clone) {
22220                cleanupLastIncludeContent();
22221                $animate.enter(clone, null, $element).then(afterAnimation);
22222              });
22223
22224              currentScope = newScope;
22225              currentElement = clone;
22226
22227              currentScope.$emit('$includeContentLoaded', src);
22228              scope.$eval(onloadExp);
22229            }, function() {
22230              if (thisChangeId === changeCounter) {
22231                cleanupLastIncludeContent();
vendor: 2,650 bytes, lines 22232-22312
22232                scope.$emit('$includeContentError', src);
22233              }
22234            });
22235            scope.$emit('$includeContentRequested', src);
22236          } else {
22237            cleanupLastIncludeContent();
22238            ctrl.template = null;
22239          }
22240        });
22241      };
22242    }
22243  };
22244}];
22245
22246// This directive is called during the $transclude call of the first `ngInclude` directive.
22247// It will replace and compile the content of the element with the loaded template.
22248// We need this directive so that the element content is already filled when
22249// the link function of another directive on the same element as ngInclude
22250// is called.
22251var ngIncludeFillContentDirective = ['$compile',
22252  function($compile) {
22253    return {
22254      restrict: 'ECA',
22255      priority: -400,
22256      require: 'ngInclude',
22257      link: function(scope, $element, $attr, ctrl) {
22258        if (/SVG/.test($element[0].toString())) {
22259          // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
22260          // support innerHTML, so detect this here and try to generate the contents
22261          // specially.
22262          $element.empty();
22263          $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
22264              function namespaceAdaptedClone(clone) {
22265            $element.append(clone);
22266          }, {futureParentElement: $element});
22267          return;
22268        }
22269
22270        $element.html(ctrl.template);
22271        $compile($element.contents())(scope);
22272      }
22273    };
22274  }];
22275
22276/**
22277 * @ngdoc directive
22278 * @name ngInit
22279 * @restrict AC
22280 *
22281 * @description
22282 * The `ngInit` directive allows you to evaluate an expression in the
22283 * current scope.
22284 *
22285 * <div class="alert alert-error">
22286 * The only appropriate use of `ngInit` is for aliasing special properties of
22287 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
22288 * should use {@link guide/controller controllers} rather than `ngInit`
22289 * to initialize values on a scope.
22290 * </div>
22291 * <div class="alert alert-warning">
22292 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
22293 * sure you have parenthesis for correct precedence:
22294 * <pre class="prettyprint">
22295 * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
22296 * </pre>
22297 * </div>
22298 *
22299 * @priority 450
22300 *
22301 * @element ANY
22302 * @param {expression} ngInit {@link guide/expression Expression} to eval.
22303 *
22304 * @example
22305   <example module="initExample">
22306     <file name="index.html">
22307   <script>
22308     angular.module('initExample', [])
22309       .controller('ExampleController', ['$scope', function($scope) {
22310         $scope.list = [['a', 'b'], ['c', 'd']];
22311       }]);
22312   </script>
22313   <div ng-controller="ExampleController">
22314     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
22315       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
22316          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
22317       </div>
22318     </div>
22319   </div>
22320     </file>
22321     <file name="protractor.js" type="protractor">
22322       it('should alias index positions', function() {
22323         var elements = element.all(by.css('.example-init'));
22324         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
22325         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
22326         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
22327         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
22328       });
22329     </file>
22330   </example>
22331 */
22332var ngInitDirective = ngDirective({
22333  priority: 450,
22334  compile: function() {
22335    return {
22336      pre: function(scope, element, attrs) {
22337        scope.$eval(attrs.ngInit);
22338      }
22339    };
22340  }
22341});
22342
22343/**
22344 * @ngdoc directive
22345 * @name ngList
22346 *
22347 * @description
22348 * Text input that converts between a delimited string and an array of strings. The default
22349 * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
22350 * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
22351 *
22352 * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
22353 * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
22354 *   list item is respected. This implies that the user of the directive is responsible for
22355 *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
22356 *   tab or newline character.
22357 * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
22358 *   when joining the list items back together) and whitespace around each list item is stripped
22359 *   before it is added to the model.
22360 *
22361 * ### Example with Validation
22362 *
22363 * <example name="ngList-directive" module="listExample">
22364 *   <file name="app.js">
22365 *      angular.module('listExample', [])
22366 *        .controller('ExampleController', ['$scope', function($scope) {
22367 *          $scope.names = ['morpheus', 'neo', 'trinity'];
22368 *        }]);
22369 *   </file>
22370 *   <file name="index.html">
22371 *    <form name="myForm" ng-controller="ExampleController">
22372 *      List: <input name="namesInput" ng-model="names" ng-list required>
22373 *      <span class="error" ng-show="myForm.namesInput.$error.required">
22374 *        Required!</span>
22375 *      <br>
22376 *      <tt>names = {{names}}</tt><br/>
22377 *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
22378 *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
22379 *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
22380 *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
22381 *     </form>
22382 *   </file>
22383 *   <file name="protractor.js" type="protractor">
22384 *     var listInput = element(by.model('names'));
22385 *     var names = element(by.exactBinding('names'));
22386 *     var valid = element(by.binding('myForm.namesInput.$valid'));
22387 *     var error = element(by.css('span.error'));
22388 *
22389 *     it('should initialize to model', function() {
22390 *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
22391 *       expect(valid.getText()).toContain('true');
22392 *       expect(error.getCssValue('display')).toBe('none');
22393 *     });
22394 *
22395 *     it('should be invalid if empty', function() {
22396 *       listInput.clear();
22397 *       listInput.sendKeys('');
22398 *
22399 *       expect(names.getText()).toContain('');
22400 *       expect(valid.getText()).toContain('false');
22401 *       expect(error.getCssValue('display')).not.toBe('none');
22402 *     });
22403 *   </file>
22404 * </example>
22405 *
22406 * ### Example - splitting on whitespace
22407 * <example name="ngList-directive-newlines">
22408 *   <file name="index.html">
22409 *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
22410 *    <pre>{{ list | json }}</pre>
22411 *   </file>
22412 *   <file name="protractor.js" type="protractor">
22413 *     it("should split the text by newlines", function() {
22414 *       var listInput = element(by.model('list'));
22415 *       var output = element(by.binding('list | json'));
22416 *       listInput.sendKeys('abc\ndef\nghi');
22417 *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
22418 *     });
22419 *   </file>
22420 * </example>
22421 *
22422 * @element input
22423 * @param {string=} ngList optional delimiter that should be used to split the value.
22424 */
22425var ngListDirective = function() {
22426  return {
22427    restrict: 'A',
22428    priority: 100,
22429    require: 'ngModel',
22430    link: function(scope, element, attr, ctrl) {
22431      // We want to control whitespace trimming so we use this convoluted approach
22432      // to access the ngList attribute, which doesn't pre-trim the attribute
22433      var ngList = element.attr(attr.$attr.ngList) || ', ';
22434      var trimValues = attr.ngTrim !== 'false';
22435      var separator = trimValues ? trim(ngList) : ngList;
22436
22437      var parse = function(viewValue) {
22438        // If the viewValue is invalid (say required but empty) it will be `undefined`
22439        if (isUndefined(viewValue)) return;
22440
22441        var list = [];
22442
22443        if (viewValue) {
22444          forEach(viewValue.split(separator), function(value) {
22445            if (value) list.push(trimValues ? trim(value) : value);
22446          });
22447        }
22448
22449        return list;
22450      };
22451
22452      ctrl.$parsers.push(parse);
22453      ctrl.$formatters.push(function(value) {
22454        if (isArray(value)) {
22455          return value.join(ngList);
22456        }
22457
22458        return undefined;
22459      });
22460
22461      // Override the standard $isEmpty because an empty array means the input is empty.
22462      ctrl.$isEmpty = function(value) {
22463        return !value || !value.length;
22464      };
22465    }
22466  };
22467};
22468
22469/* global VALID_CLASS: true,
22470  INVALID_CLASS: true,
22471  PRISTINE_CLASS: true,
22472  DIRTY_CLASS: true,
22473  UNTOUCHED_CLASS: true,
22474  TOUCHED_CLASS: true,
22475*/
22476
22477var VALID_CLASS = 'ng-valid',
22478    INVALID_CLASS = 'ng-invalid',
22479    PRISTINE_CLASS = 'ng-pristine',
22480    DIRTY_CLASS = 'ng-dirty',
22481    UNTOUCHED_CLASS = 'ng-untouched',
22482    TOUCHED_CLASS = 'ng-touched',
22483    PENDING_CLASS = 'ng-pending';
22484
22485
22486var $ngModelMinErr = new minErr('ngModel');
22487
22488/**
22489 * @ngdoc type
22490 * @name ngModel.NgModelController
22491 *
22492 * @property {string} $viewValue Actual string value in the view.
22493 * @property {*} $modelValue The value in the model that the control is bound to.
22494 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
22495       the control reads value from the DOM. The functions are called in array order, each passing
22496       its return value through to the next. The last return value is forwarded to the
22497       {@link ngModel.NgModelController#$validators `$validators`} collection.
22498
22499Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
22500`$viewValue`}.
22501
22502Returning `undefined` from a parser means a parse error occurred. In that case,
22503no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
22504will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
22505is set to `true`. The parse error is stored in `ngModel.$error.parse`.
22506
22507 *
22508 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
22509       the model value changes. The functions are called in reverse array order, each passing the value through to the
22510       next. The last return value is used as the actual DOM value.
22511       Used to format / convert values for display in the control.
22512 * ```js
22513 * function formatter(value) {
22514 *   if (value) {
22515 *     return value.toUpperCase();
22516 *   }
22517 * }
22518 * ngModel.$formatters.push(formatter);
22519 * ```
22520 *
22521 * @property {Object.<string, function>} $validators A collection of validators that are applied
22522 *      whenever the model value changes. The key value within the object refers to the name of the
22523 *      validator while the function refers to the validation operation. The validation operation is
22524 *      provided with the model value as an argument and must return a true or false value depending
22525 *      on the response of that validation.
22526 *
22527 * ```js
22528 * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
22529 *   var value = modelValue || viewValue;
22530 *   return /[0-9]+/.test(value) &&
22531 *          /[a-z]+/.test(value) &&
22532 *          /[A-Z]+/.test(value) &&
22533 *          /\W+/.test(value);
22534 * };
22535 * ```
22536 *
22537 * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
22538 *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
22539 *      is expected to return a promise when it is run during the model validation process. Once the promise
22540 *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
22541 *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
22542 *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
22543 *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
22544 *      will only run once all synchronous validators have passed.
22545 *
22546 * Please note that if $http is used then it is important that the server returns a success HTTP response code
22547 * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
22548 *
22549 * ```js
22550 * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
22551 *   var value = modelValue || viewValue;
22552 *
22553 *   // Lookup user by username
22554 *   return $http.get('/api/users/' + value).
22555 *      then(function resolved() {
22556 *        //username exists, this means validation fails
22557 *        return $q.reject('exists');
22558 *      }, function rejected() {
22559 *        //username does not exist, therefore this validation passes
22560 *        return true;
22561 *      });
22562 * };
22563 * ```
22564 *
22565 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
22566 *     view value has changed. It is called with no arguments, and its return value is ignored.
22567 *     This can be used in place of additional $watches against the model value.
22568 *
22569 * @property {Object} $error An object hash with all failing validator ids as keys.
22570 * @property {Object} $pending An object hash with all pending validator ids as keys.
22571 *
22572 * @property {boolean} $untouched True if control has not lost focus yet.
22573 * @property {boolean} $touched True if control has lost focus.
22574 * @property {boolean} $pristine True if user has not interacted with the control yet.
22575 * @property {boolean} $dirty True if user has already interacted with the control.
22576 * @property {boolean} $valid True if there is no error.
22577 * @property {boolean}
22577 $invalid True if at least one error on the control.
22578 * @property {string} $name The name attribute of the control.
22579 *
22580 * @description
22581 *
22582 * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
22583 * The controller contains services for data-binding, validation, CSS updates, and value formatting
22584 * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
22585 * listening to DOM events.
22586 * Such DOM related logic should be provided by other directives which make use of
22587 * `NgModelController` for data-binding to control elements.
22588 * Angular provides this DOM logic for most {@link input `input`} elements.
22589 * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
22590 * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
22591 *
22592 * @example
22593 * ### Custom Control Example
22594 * This example shows how to use `NgModelController` with a custom control to achieve
22595 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
22596 * collaborate together to achieve the desired result.
22597 *
22598 * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
22599 * contents be edited in place by the user.  This will not work on older browsers.
22600 *
22601 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
22602 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
22603 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
22604 * that content using the `$sce` service.
22605 *
22606 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
22607    <file name="style.css">
22608      [contenteditable] {
22609        border: 1px solid black;
22610        background-color: white;
22611        min-height: 20px;
22612      }
22613
22614      .ng-invalid {
22615        border: 1px solid red;
22616      }
22617
22618    </file>
22619    <file name="script.js">
22620      angular.module('customControl', ['ngSanitize']).
22621        directive('contenteditable', ['$sce', function($sce) {
22622          return {
22623            restrict: 'A', // only activate on element attribute
22624            require: '?ngModel', // get a hold of NgModelController
22625            link: function(scope, element, attrs, ngModel) {
22626              if (!ngModel) return; // do nothing if no ng-model
22627
22628              // Specify how UI should be updated
22629              ngModel.$render = function() {
22630                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
22631              };
22632
22633              // Listen for change events to enable binding
22634              element.on('blur keyup change', function() {
22635                scope.$evalAsync(read);
22636              });
22637              read(); // initialize
22638
22639              // Write data to the model
22640              function read() {
22641                var html = element.html();
22642                // When we clear the content editable the browser leaves a <br> behind
22643                // If strip-br attribute is provided then we strip this out
22644                if ( attrs.stripBr && html == '<br>' ) {
22645                  html = '';
22646                }
22647                ngModel.$setViewValue(html);
22648              }
22649            }
22650          };
22651        }]);
22652    </file>
22653    <file name="index.html">
22654      <form name="myForm">
22655       <div contenteditable
22656            name="myWidget" ng-model="userContent"
22657            strip-br="true"
22658            required>Change me!</div>
22659        <span ng-show="myForm.myWidget.$error.required">Required!</span>
22660       <hr>
22661       <textarea ng-model="userContent"></textarea>
22662      </form>
22663    </file>
22664    <file name="protractor.js" type="protractor">
22665    it('should data-bind and become invalid', function() {
22666      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
22667        // SafariDriver can't handle contenteditable
22668        // and Firefox driver can't clear contenteditables very well
22669        return;
22670      }
22671      var contentEditable = element(by.css('[contenteditable]'));
22672      var content = 'Change me!';
22673
22674      expect(contentEditable.getText()).toEqual(content);
22675
22676      contentEditable.clear();
22677      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
22678      expect(contentEditable.getText()).toEqual('');
22679      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
22680    });
22681    </file>
22682 * </example>
22683 *
22684 *
22685 */
22686var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
22687    function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
22688  this.$viewValue = Number.NaN;
22689  this.$modelValue = Number.NaN;
22690  this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
22691  this.$validators = {};
22692  this.$asyncValidators = {};
22693  this.$parsers = [];
22694  this.$formatters = [];
22695  this.$viewChangeListeners = [];
22696  this.$untouched = true;
22697  this.$touched = false;
22698  this.$pristine = true;
22699  this.$dirty = false;
22700  this.$valid = true;
22701  this.$invalid = false;
22702  this.$error = {}; // keep invalid keys here
22703  this.$$success = {}; // keep valid keys here
22704  this.$pending = undefined; // keep pending keys here
22705  this.$name = $interpolate($attr.name || '', false)($scope);
22706
22707
22708  var parsedNgModel = $parse($attr.ngModel),
22709      parsedNgModelAssign = parsedNgModel.assign,
22710      ngModelGet = parsedNgModel,
22711      ngModelSet = parsedNgModelAssign,
22712      pendingDebounce = null,
22713      ctrl = this;
22714
22715  this.$$setOptions = function(options) {
22716    ctrl.$options = options;
22717    if (options && options.getterSetter) {
22718      var invokeModelGetter = $parse($attr.ngModel + '()'),
22719          invokeModelSetter = $parse($attr.ngModel + '($$$p)');
22720
22721      ngModelGet = function($scope) {
22722        var modelValue = parsedNgModel($scope);
22723        if (isFunction(modelValue)) {
22724          modelValue = invokeModelGetter($scope);
22725        }
22726        return modelValue;
22727      };
22728      ngModelSet = function($scope, newValue) {
22729        if (isFunction(parsedNgModel($scope))) {
22730          invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
22731        } else {
22732          parsedNgModelAssign($scope, ctrl.$modelValue);
22733        }
22734      };
22735    } else if (!parsedNgModel.assign) {
22736      throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
22737          $attr.ngModel, startingTag($element));
22738    }
22739  };
22740
22741  /**
22742   * @ngdoc method
22743   * @name ngModel.NgModelController#$render
22744   *
22745   * @description
22746   * Called when the view needs to be updated. It is expected that the user of the ng-model
22747   * directive will implement this method.
22748   *
22749   * The `$render()` method is invoked in the following situations:
22750   *
22751   * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
22752   *   committed value then `$render()` is called to update the input control.
22753   * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
22754   *   the `$viewValue` are different to last time.
22755   *
22756   * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
22757   * `$modelValue` and `$viewValue` are actually different to their previous value. If `$modelValue`
22758   * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
22759   * invoked if you only change a property on the objects.
22760   */
22761  this.$render = noop;
22762
22763  /**
22764   * @ngdoc method
22765   * @name ngModel.NgModelController#$isEmpty
22766   *
22767   * @description
22768   * This is called when we need to determine if the value of an input is empty.
22769   *
22770   * For instance, the required directive does this to work out if the input has data or not.
22771   *
22772   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
22773   *
22774   * You can override this for input directives whose concept of being empty is different to the
22775   * default. The `checkboxInputType` directive does this because in its case a value of `false`
22776   * implies empty.
22777   *
22778   * @param {*} value The value of the input to check for emptiness.
22779   * @returns {boolean} True if `value` is "empty".
22780   */
22781  this.$isEmpty = function(value) {
22782    return isUndefined(value) || value === '' || value === null || value !== value;
22783  };
22784
22785  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
22786      currentValidationRunId = 0;
22787
22788  /**
22789   * @ngdoc method
22790   * @name ngModel.NgModelController#$setValidity
22791   *
22792   * @description
22793   * Change the validity state, and notify the form.
22794   *
22795   * This method can be called within $parsers/$formatters or a custom validation implementation.
22796   * However, in most cases it should be sufficient to use the `ngModel.$validators` and
22797   * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
22798   *
22799   * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
22800   *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
22801   *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
22802   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
22803   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
22804   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
22805   * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
22806   *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
22807   *                          Skipped is used by Angular when validators do not run because of parse errors and
22808   *                          when `$asyncValidators` do not run because any of the `$validators` failed.
22809   */
22810  addSetValidityMethod({
22811    ctrl: this,
22812    $element: $element,
22813    set: function(object, property) {
22814      object[property] = true;
22815    },
22816    unset: function(object, property) {
22817      delete object[property];
22818    },
22819    parentForm: parentForm,
22820    $animate: $animate
22821  });
22822
22823  /**
22824   * @ngdoc method
22825   * @name ngModel.NgModelController#$setPristine
22826   *
22827   * @description
22828   * Sets the control to its pristine state.
22829   *
22830   * This method can be called to remove the `ng-dirty` class and set the control to its pristine
22831   * state (`ng-pristine` class). A model is considered to be pristine when the control
22832   * has not been changed from when first compiled.
22833   */
22834  this.$setPristine = function() {
22835    ctrl.$dirty = false;
22836    ctrl.$pristine = true;
22837    $animate.removeClass($element, DIRTY_CLASS);
22838    $animate.addClass($element, PRISTINE_CLASS);
22839  };
22840
22841  /**
22842   * @ngdoc method
22843   * @name ngModel.NgModelController#$setDirty
22844   *
22845   * @description
22846   * Sets the control to its dirty state.
22847   *
22848   * This method can be called to remove the `ng-pristine` class and set the control to its dirty
22849   * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
22850   * from when first compiled.
22851   */
22852  this.$setDirty = function() {
22853    ctrl.$dirty = true;
22854    ctrl.$pristine = false;
22855    $animate.removeClass($element, PRISTINE_CLASS);
22856    $animate.addClass($element, DIRTY_CLASS);
22857    parentForm.$setDirty();
22858  };
22859
22860  /**
22861   * @ngdoc method
22862   * @name ngModel.NgModelController#$setUntouched
22863   *
22864   * @description
22865   * Sets the control to its untouched state.
22866   *
22867   * This method can be called to remove the `ng-touched` class and set the control to its
22868   * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
22869   * by default, however this function can be used to restore that state if the model has
22870   * already been touched by the user.
22871   */
22872  this.$setUntouched = function() {
22873    ctrl.$touched = false;
22874    ctrl.$untouched = true;
22875    $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
22876  };
22877
22878  /**
22879   * @ngdoc method
22880   * @name ngModel.NgModelController#$setTouched
22881   *
22882   * @description
22883   * Sets the control to its touched state.
22884   *
22885   * This method can be called to remove the `ng-untouched` class and set the control to its
22886   * touched state (`ng-touched` class). A model is considered to be touched when the user has
22887   * first focused the control element and then shifted focus away from the control (blur event).
22888   */
22889  this.$setTouched = function() {
22890    ctrl.$touched = true;
22891    ctrl.$untouched = false;
22892    $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
22893  };
22894
22895  /**
22896   * @ngdoc method
22897   * @name ngModel.NgModelController#$rollbackViewValue
22898   *
22899   * @description
22900   * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
22901   * which may be caused by a pending debounced event or because the input is waiting for a some
22902   * future event.
22903   *
22904   * If you have an input that uses `ng-model-options` to set up debounced events or events such
22905   * as blur you can have a situation where there is a period when the `$viewValue`
22906   * is out of synch with the ngModel's `$modelValue`.
22907   *
22908   * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
22909   * programmatically before these debounced/future events have resolved/occurred, because Angular's
22910   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
22911   *
22912   * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
22913   * input which may have such events pending. This is important in order to make sure that the
22914   * input field will be updated with the new model value and any pending operations are cancelled.
22915   *
22916   * <example name="ng-model-cancel-update" module="cancel-update-example">
22917   *   <file name="app.js">
22918   *     angular.module('cancel-update-example', [])
22919   *
22920   *     .controller('CancelUpdateController', ['$scope', function($scope) {
22921   *       $scope.resetWithCancel = function(e) {
22922   *         if (e.keyCode == 27) {
22923   *           $scope.myForm.myInput1.$rollbackViewValue();
22924   *           $scope.myValue = '';
22925   *         }
22926   *       };
22927   *       $scope.resetWithoutCancel = function(e) {
22928   *         if (e.keyCode == 27) {
22929   *           $scope.myValue = '';
22930   *         }
22931   *       };
22932   *     }]);
22933   *   </file>
22934   *   <file name="index.html">
22935   *     <div ng-controller="CancelUpdateController">
22936   *       <p>Try typing something in each input.  See that the model only updates when you
22937   *          blur off the input.
22938   *        </p>
22939   *        <p>Now see what happens if you start typing then press the Escape key</p>
22940   *
22941   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
22942   *         <p>With $rollbackViewValue()</p>
22943   *         <input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)"><br/>
22944   *         myValue: "{{ myValue }}"
22945   *
22946   *         <p>Without $rollbackViewValue()</p>
22947   *         <input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)"><br/>
22948   *         myValue: "{{ myValue }}"
22949   *       </form>
22950   *     </div>
22951   *   </file>
22952   * </example>
22953   */
22954  this.$rollbackViewValue = function() {
22955    $timeout.cancel(pendingDebounce);
22956    ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
22957    ctrl.$render();
22958  };
22959
22960  /**
22961   * @ngdoc method
22962   * @name ngModel.NgModelController#$validate
22963   *
22964   * @description
22965   * Runs each of the registered validators (first synchronous validators and then
22966   * asynchronous validators).
22967   * If the validity changes to invalid, the model will be set to `undefined`,
22968   * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
22969   * If the validity changes to valid, it will set the model to the last available valid
22970   * modelValue, i.e. either the last parsed value or the last value set from the scope.
22971   */
22972  this.$validate = function() {
22973    // ignore $validate before model is initialized
22974    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
22975      return;
22976    }
22977
22978    var viewValue = ctrl.$$lastCommittedViewValue;
22979    // Note: we use the $$rawModelValue as $modelValue might have been
22980    // set to undefined during a view -> model update that found validation
22981    // errors. We can't parse the view here, since that could change
22982    // the model although neither viewValue nor the model on the scope changed
22983    var modelValue = ctrl.$$rawModelValue;
22984
22985    // Check if the there's a parse error, so we don't unset it accidentially
22986    var parserName = ctrl.$$parserName || 'parse';
22987    var parserValid = ctrl.$error[parserName] ? false : undefined;
22988
22989    var prevValid = ctrl.$valid;
22990    var prevModelValue = ctrl.$modelValue;
22991
22992    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
22993
22994    ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
22995      // If there was no change in validity, don't update the model
22996      // This prevents changing an invalid modelValue to undefined
22997      if (!allowInvalid && prevValid !== allValid) {
22998        // Note: Don't check ctrl.$valid here, as we could have
22999        // external validators (e.g. calculated on the server),
23000        // that just call $setValidity and need the model value
23001        // to calculate their validity.
23002        ctrl.$modelValue = allValid ? modelValue : undefined;
23003
23004        if (ctrl.$modelValue !== prevModelValue) {
23005          ctrl.$$writeModelToScope();
23006        }
23007      }
23008    });
23009
23010  };
23011
23012  this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
23013    currentValidationRunId++;
23014    var localValidationRunId = currentValidationRunId;
23015
23016    // check parser error
23017    if (!processParseErrors(parseValid)) {
23018      validationDone(false);
23019      return;
23020    }
23021    if (!processSyncValidators()) {
23022      validationDone(false);
23023      return;
23024    }
23025    processAsyncValidators();
23026
23027    function processParseErrors(parseValid) {
23028      var errorKey = ctrl.$$parserName || 'parse';
23029      if (parseValid === undefined) {
23030        setValidity(errorKey, null);
23031      } else {
23032        setValidity(errorKey, parseValid);
23033        if (!parseValid) {
23034          forEach(ctrl.$validators, function(v, name) {
23035            setValidity(name, null);
23036          });
23037          forEach(ctrl.$asyncValidators, function(v, name) {
23038            setValidity(name, null);
23039          });
23040          return false;
23041        }
23042      }
23043      return true;
23044    }
23045
23046    function processSyncValidators() {
23047      var syncValidatorsValid = true;
23048      forEach(ctrl.$validators, function(validator, name) {
23049        var result = validator(modelValue, viewValue);
23050        syncValidatorsValid = syncValidatorsValid && result;
23051        setValidity(name, result);
23052      });
23053      if (!syncValidatorsValid) {
23054        forEach(ctrl.$asyncValidators, function(v, name) {
23055          setValidity(name, null);
23056        });
23057        return false;
23058      }
23059      return true;
23060    }
23061
23062    function processAsyncValidators() {
23063      var validatorPromises = [];
23064      var allValid = true;
23065      forEach(ctrl.$asyncValidators, function(validator, name) {
23066        var promise = validator(modelValue, viewValue);
23067        if (!isPromiseLike(promise)) {
23068          throw $ngModelMinErr("$asyncValidators",
23069            "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
23070        }
23071        setValidity(name, undefined);
23072        validatorPromises.push(promise.then(function() {
23073          setValidity(name, true);
23074        }, function(error) {
23075          allValid = false;
23076          setValidity(name, false);
23077        }));
23078      });
23079      if (!validatorPromises.length) {
23080        validationDone(true);
23081      } else {
23082        $q.all(validatorPromises).then(function() {
23083          validationDone(allValid);
23084        }, noop);
23085      }
23086    }
23087
23088    function setValidity(name, isValid) {
23089      if (localValidationRunId === currentValidationRunId) {
23090        ctrl.$setValidity(name, isValid);
23091      }
23092    }
23093
23094    function validationDone(allValid) {
23095      if (localValidationRunId === currentValidationRunId) {
23096
23097        doneCallback(allValid);
23098      }
23099    }
23100  };
23101
23102  /**
23103   * @ngdoc method
23104   * @name ngModel.NgModelController#$commitViewValue
23105   *
23106   * @description
23107   * Commit a pending update to the `$modelValue`.
23108   *
23109   * Updates may be pending by a debounced event or because the input is waiting for a some future
23110   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
23111   * usually handles calling this in response to input events.
23112   */
23113  this.$commitViewValue = function() {
23114    var viewValue = ctrl.$viewValue;
23115
23116    $timeout.cancel(pendingDebounce);
23117
23118    // If the view value has not changed then we should just exit, except in the case where there is
23119    // a native validator on the element. In this case the validation state may have changed even though
23120    // the viewValue has stayed empty.
23121    if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
23122      return;
23123    }
23124    ctrl.$$lastCommittedViewValue = viewValue;
23125
23126    // change to dirty
23127    if (ctrl.$pristine) {
23128      this.$setDirty();
23129    }
23130    this.$$parseAndValidate();
23131  };
23132
23133  this.$$parseAndValidate = function() {
23134    var viewValue = ctrl.$$lastCommittedViewValue;
23135    var modelValue = viewValue;
23136    var parserValid = isUndefined(modelValue) ? undefined : true;
23137
23138    if (parserValid) {
23139      for (var i = 0; i < ctrl.$parsers.length; i++) {
23140        modelValue = ctrl.$parsers[i](modelValue);
23141        if (isUndefined(modelValue)) {
23142          parserValid = false;
23143          break;
23144        }
23145      }
23146    }
23147    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
23148      // ctrl.$modelValue has not been touched yet...
23149      ctrl.$modelValue = ngModelGet($scope);
23150    }
23151    var prevModelValue = ctrl.$modelValue;
23152    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
23153    ctrl.$$rawModelValue = modelValue;
23154
23155    if (allowInvalid) {
23156      ctrl.$modelValue = modelValue;
23157      writeToModelIfNeeded();
23158    }
23159
23160    // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
23161    // This can happen if e.g. $setViewValue is called from inside a parser
23162    ctrl.$$runValidators(parserValid, modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
23163      if (!allowInvalid) {
23164        // Note: Don't check ctrl.$valid here, as we could have
23165        // external validators (e.g. calculated on the server),
23166        // that just call $setValidity and need the model value
23167        // to calculate their validity.
23168        ctrl.$modelValue = allValid ? modelValue : undefined;
23169        writeToModelIfNeeded();
23170      }
23171    });
23172
23173    function writeToModelIfNeeded() {
23174      if (ctrl.$modelValue !== prevModelValue) {
23175        ctrl.$$writeModelToScope();
23176      }
23177    }
23178  };
23179
23180  this.$$writeModelToScope = function() {
23181    ngModelSet($scope, ctrl.$modelValue);
23182    forEach(ctrl.$viewChangeListeners, function(listener) {
23183      try {
23184        listener();
23185      } catch (e) {
23186        $exceptionHandler(e);
23187      }
23188    });
23189  };
23190
23191  /**
23192   * @ngdoc method
23193   * @name ngModel.NgModelController#$setViewValue
23194   *
23195   * @description
23196   * Update the view value.
23197   *
23198   * This method should be called when an input directive want to change the view value; typically,
23199   * this is done from within a DOM event handler.
23200   *
23201   * For example {@link ng.directive:input input} calls it when the value of the input changes and
23202   * {@link ng.directive:select select} calls it when an option is selected.
23203   *
23204   * If the new `value` is an object (rather than a string or a number), we should make a copy of the
23205   * object before passing it to `$setViewValue`.  This is because `ngModel` does not perform a deep
23206   * watch of objects, it only looks for a change of identity. If you only change the property of
23207   * the object then ngModel will not realise that the object has changed and will not invoke the
23208   * `$parsers` and `$validators` pipelines.
23209   *
23210   * For this reason, you should not change properties of the copy once it has been passed to
23211   * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
23212   *
23213   * When this method is called, the new `value` will be staged for committing through the `$parsers`
23214   * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
23215   * value sent directly for processing, finally to be applied to `$modelValue` and then the
23216   * **expression** specified in the `ng-model` attribute.
23217   *
23218   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
23219   *
23220   * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
23221   * and the `default` trigger is not listed, all those actions will remain pending until one of the
23222   * `updateOn` events is triggered on the DOM element.
23223   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
23224   * directive is used with a custom debounce for this particular event.
23225   *
23226   * Note that calling this function does not trigger a `$digest`.
23227   *
23228   * @param {string} value Value from the view.
23229   * @param {string} trigger Event that triggered the update.
23230   */
23231  this.$setViewValue = function(value, trigger) {
23232    ctrl.$viewValue = value;
23233    if (!ctrl.$options || ctrl.$options.updateOnDefault) {
23234      ctrl.$$debounceViewValueCommit(trigger);
23235    }
23236  };
23237
23238  this.$$debounceViewValueCommit = function(trigger) {
23239    var debounceDelay = 0,
23240        options = ctrl.$options,
23241        debounce;
23242
23243    if (options && isDefined(options.debounce)) {
23244      debounce = options.debounce;
23245      if (isNumber(debounce)) {
23246        debounceDelay = debounce;
23247      } else if (isNumber(debounce[trigger])) {
23248        debounceDelay = debounce[trigger];
23249      } else if (isNumber(debounce['default'])) {
23250        debounceDelay = debounce['default'];
23251      }
23252    }
23253
23254    $timeout.cancel(pendingDebounce);
23255    if (debounceDelay) {
23256      pendingDebounce = $timeout(function() {
23257        ctrl.$commitViewValue();
23258      }, debounceDelay);
23259    } else if ($rootScope.$$phase) {
23260      ctrl.$commitViewValue();
23261    } else {
23262      $scope.$apply(function() {
23263        ctrl.$commitViewValue();
23264      });
23265    }
23266  };
23267
23268  // model -> value
23269  // Note: we cannot use a normal scope.$watch as we want to detect the following:
23270  // 1. scope value is 'a'
23271  // 2. user enters 'b'
23272  // 3. ng-change kicks in and reverts scope value to 'a'
23273  //    -> scope value did not change since the last digest as
23274  //       ng-change executes in apply phase
23275  // 4. view should be changed back to 'a'
23276  $scope.$watch(function ngModelWatch() {
23277    var modelValue = ngModelGet($scope);
23278
23279    // if scope model value and ngModel value are out of sync
23280    // TODO(perf): why not move this to the action fn?
23281    if (modelValue !== ctrl.$modelValue) {
23282      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
23283
23284      var formatters = ctrl.$formatters,
23285          idx = formatters.length;
23286
23287      var viewValue = modelValue;
23288      while (idx--) {
23289        viewValue = formatters[idx](viewValue);
23290      }
23291      if (ctrl.$viewValue !== viewValue) {
23292        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
23293        ctrl.$render();
23294
23295        ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
23296      }
23297    }
23298
23299    return modelValue;
23300  });
23301}];
23302
23303
23304/**
23305 * @ngdoc directive
23306 * @name ngModel
23307 *
23308 * @element input
23309 * @priority 1
23310 *
23311 * @description
23312 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
23313 * property on the scope using {@link ngModel.NgModelController NgModelController},
23314 * which is created and exposed by this directive.
23315 *
23316 * `ngModel` is responsible for:
23317 *
23318 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
23319 *   require.
23320 * - Providing validation behavior (i.e. required, number, email, url).
23321 * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
23322 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
23323 * - Registering the control with its parent {@link ng.directive:form form}.
23324 *
23325 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
23326 * current scope. If the property doesn't already exist on this scope, it will be created
23327 * implicitly and added to the scope.
23328 *
23329 * For best practices on using `ngModel`, see:
23330 *
23331 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
23332 *
23333 * For basic examples, how to use `ngModel`, see:
23334 *
23335 *  - {@link ng.directive:input input}
23336 *    - {@link input[text] text}
23337 *    - {@link input[checkbox] checkbox}
23338 *    - {@link input[radio] radio}
23339 *    - {@link input[number] number}
23340 *    - {@link input[email] email}
23341 *    - {@link input[url] url}
23342 *    - {@link input[date] date}
23343 *    - {@link input[datetime-local] datetime-local}
23344 *    - {@link input[time] time}
23345 *    - {@link input[month] month}
23346 *    - {@link input[week] week}
23347 *  - {@link ng.directive:select select}
23348 *  - {@link ng.directive:textarea textarea}
23349 *
23350 * # CSS classes
23351 * The following CSS classes are added and removed on the associated input/select/textarea element
23352 * depending on the validity of the model.
23353 *
23354 *  - `ng-valid`: the model is valid
23355 *  - `ng-invalid`: the model is invalid
23356 *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
23357 *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
23358 *  - `ng-pristine`: the control hasn't been interacted with yet
23359 *  - `ng-dirty`: the control has been interacted with
23360 *  - `ng-touched`: the control has been blurred
23361 *  - `ng-untouched`: the control hasn't been blurred
23362 *  - `ng-pending`: any `$asyncValidators` are unfulfilled
23363 *
23364 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
23365 *
23366 * ## Animation Hooks
23367 *
23368 * Animations within models are triggered when any of the associated CSS classes are added and removed
23369 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
23370 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
23371 * The animations that are triggered within ngModel are similar to how they work in ngClass and
23372 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
23373 *
23374 * The following example shows a simple way to utilize CSS transitions to style an input element
23375 * that has been rendered as invalid after it has been validated:
23376 *
23377 * <pre>
23378 * //be sure to include ngAnimate as a module to hook into more
23379 * //advanced animations
23380 * .my-input {
23381 *   transition:0.5s linear all;
23382 *   background: white;
23383 * }
23384 * .my-input.ng-invalid {
23385 *   background: red;
23386 *   color:white;
23387 * }
23388 * </pre>
23389 *
23390 * @example
23391 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
23392     <file name="index.html">
23393       <script>
23394        angular.module('inputExample', [])
23395          .controller('ExampleController', ['$scope', function($scope) {
23396            $scope.val = '1';
23397          }]);
23398       </script>
23399       <style>
23400         .my-input {
23401           -webkit-transition:all linear 0.5s;
23402           transition:all linear 0.5s;
23403           background: transparent;
23404         }
23405         .my-input.ng-invalid {
23406           color:white;
23407           background: red;
23408         }
23409       </style>
23410       Update input to see transitions when valid/invalid.
23411       Integer is a valid value.
23412       <form name="testForm" ng-controller="ExampleController">
23413         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
23414       </form>
23415     </file>
23416 * </example>
23417 *
23418 * ## Binding to a getter/setter
23419 *
23420 * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
23421 * function that returns a representation of the model when called with zero arguments, and sets
23422 * the internal state of a model when called with an argument. It's sometimes useful to use this
23423 * for models that have an internal representation that's different than what the model exposes
23424 * to the view.
23425 *
23426 * <div class="alert alert-success">
23427 * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
23428 * frequently than other parts of your code.
23429 * </div>
23430 *
23431 * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
23432 * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
23433 * a `<form>`, which will enable this behavior for all `<input>`s within it. See
23434 * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
23435 *
23436 * The following example shows how to use `ngModel` with a getter/setter:
23437 *
23438 * @example
23439 * <example name="ngModel-getter-setter" module="getterSetterExample">
23440     <file name="index.html">
23441       <div ng-controller="ExampleController">
23442         <form name="userForm">
23443           Name:
23444           <input type="text" name="userName"
23445                  ng-model="user.name"
23446                  ng-model-options="{ getterSetter: true }" />
23447         </form>
23448         <pre>user.name = <span ng-bind="user.name()"></span></pre>
23449       </div>
23450     </file>
23451     <file name="app.js">
23452       angular.module('getterSetterExample', [])
23453         .controller('ExampleController', ['$scope', function($scope) {
23454           var _name = 'Brian';
23455           $scope.user = {
23456             name: function(newName) {
23457               if (angular.isDefined(newName)) {
23458                 _name = newName;
23459               }
23460               return _name;
23461             }
23462           };
23463         }]);
23464     </file>
23465 * </example>
23466 */
23467var ngModelDirective = ['$rootScope', function($rootScope) {
23468  return {
23469    restrict: 'A',
23470    require: ['ngModel', '^?form', '^?ngModelOptions'],
23471    controller: NgModelController,
23472    // Prelink needs to run before any input directive
23473    // so that we can set the NgModelOptions in NgModelController
23474    // before anyone else uses it.
23475    priority: 1,
23476    compile: function ngModelCompile(element) {
23477      // Setup initial state of the control
23478      element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
23479
23480      return {
23481        pre: function ngModelPreLink(scope, element, attr, ctrls) {
23482          var modelCtrl = ctrls[0],
23483              formCtrl = ctrls[1] || nullFormCtrl;
23484
23485          modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
23486
23487          // notify others, especially parent forms
23488          formCtrl.$addControl(modelCtrl);
23489
23490          attr.$observe('name', function(newValue) {
23491            if (modelCtrl.$name !== newValue) {
23492              formCtrl.$$renameControl(modelCtrl, newValue);
23493            }
23494          });
23495
23496          scope.$on('$destroy', function() {
23497            formCtrl.$removeControl(modelCtrl);
23498          });
23499        },
23500        post: function ngModelPostLink(scope, element, attr, ctrls) {
23501          var modelCtrl = ctrls[0];
23502          if (modelCtrl.$options && modelCtrl.$options.updateOn) {
23503            element.on(modelCtrl.$options.updateOn, function(ev) {
23504              modelCtrl.$$debounceViewValueCommit(ev && ev.type);
23505            });
23506          }
23507
23508          element.on('blur', function(ev) {
23509            if (modelCtrl.$touched) return;
23510
23511            if ($rootScope.$$phase) {
23512              scope.$evalAsync(modelCtrl.$setTouched);
23513            } else {
23514              scope.$apply(modelCtrl.$setTouched);
23515            }
23516          });
23517        }
23518      };
23519    }
23520  };
23521}];
23522
23523var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
23524
23525/**
23526 * @ngdoc directive
23527 * @name ngModelOptions
23528 *
23529 * @description
23530 * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
23531 * events that will trigger a model update and/or a debouncing delay so that the actual update only
23532 * takes place when a timer expires; this timer will be reset after another change takes place.
23533 *
23534 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
23535 * be different than the value in the actual model. This means that if you update the model you
23536 * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
23537 * order to make sure it is synchronized with the model and that any debounced action is canceled.
23538 *
23539 * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
23540 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
23541 * important because `form` controllers are published to the related scope under the name in their
23542 * `name` attribute.
23543 *
23544 * Any pending changes will take place immediately when an enclosing form is submitted via the
23545 * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
23546 * to have access to the updated model.
23547 *
23548 * `ngModelOptions` has an effect on the element it's declared on and its descendants.
23549 *
23550 * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
23551 *   - `updateOn`: string specifying which event should the input be bound to. You can set several
23552 *     events using an space delimited list. There is a special event called `default` that
23553 *     matches the default events belonging of the control.
23554 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
23555 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
23556 *     custom value for each event. For example:
23557 *     `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
23558 *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
23559 *     not validate correctly instead of the default behavior of setting the model to undefined.
23560 *   - `getterSetter`: boolean value which determines whether or not to treat functions boun
23560d to
23561       `ngModel` as getters/setters.
23562 *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
23563 *     `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
23564 *     otherwise the default timezone of the browser will be used.
23565 *
23566 * @example
23567
23568  The following example shows how to override immediate updates. Changes on the inputs within the
23569  form will update the model only when the control loses focus (blur event). If `escape` key is
23570  pressed while the input field is focused, the value is reset to the value in the current model.
23571
23572  <example name="ngModelOptions-directive-blur" module="optionsExample">
23573    <file name="index.html">
23574      <div ng-controller="ExampleController">
23575        <form name="userForm">
23576          Name:
23577          <input type="text" name="userName"
23578                 ng-model="user.name"
23579                 ng-model-options="{ updateOn: 'blur' }"
23580                 ng-keyup="cancel($event)" /><br />
23581
23582          Other data:
23583          <input type="text" ng-model="user.data" /><br />
23584        </form>
23585        <pre>user.name = <span ng-bind="user.name"></span></pre>
23586      </div>
23587    </file>
23588    <file name="app.js">
23589      angular.module('optionsExample', [])
23590        .controller('ExampleController', ['$scope', function($scope) {
23591          $scope.user = { name: 'say', data: '' };
23592
23593          $scope.cancel = function(e) {
23594            if (e.keyCode == 27) {
23595              $scope.userForm.userName.$rollbackViewValue();
23596            }
23597          };
23598        }]);
23599    </file>
23600    <file name="protractor.js" type="protractor">
23601      var model = element(by.binding('user.name'));
23602      var input = element(by.model('user.name'));
23603      var other = element(by.model('user.data'));
23604
23605      it('should allow custom events', function() {
23606        input.sendKeys(' hello');
23607        input.click();
23608        expect(model.getText()).toEqual('say');
23609        other.click();
23610        expect(model.getText()).toEqual('say hello');
23611      });
23612
23613      it('should $rollbackViewValue when model changes', function() {
23614        input.sendKeys(' hello');
23615        expect(input.getAttribute('value')).toEqual('say hello');
23616        input.sendKeys(protractor.Key.ESCAPE);
23617        expect(input.getAttribute('value')).toEqual('say');
23618        other.click();
23619        expect(model.getText()).toEqual('say');
23620      });
23621    </file>
23622  </example>
23623
23624  This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
23625  If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
23626
23627  <example name="ngModelOptions-directive-debounce" module="optionsExample">
23628    <file name="index.html">
23629      <div ng-controller="ExampleController">
23630        <form name="userForm">
23631          Name:
23632          <input type="text" name="userName"
23633                 ng-model="user.name"
23634                 ng-model-options="{ debounce: 1000 }" />
23635          <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
23636        </form>
23637        <pre>user.name = <span ng-bind="user.name"></span></pre>
23638      </div>
23639    </file>
23640    <file name="app.js">
23641      angular.module('optionsExample', [])
23642        .controller('ExampleController', ['$scope', function($scope) {
23643          $scope.user = { name: 'say' };
23644        }]);
23645    </file>
23646  </example>
23647
23648  This one shows how to bind to getter/setters:
23649
23650  <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
23651    <file name="index.html">
23652      <div ng-controller="ExampleController">
23653        <form name="userForm">
23654          Name:
23655          <input type="text" name="userName"
23656                 ng-model="user.name"
23657                 ng-model-options="{ getterSetter: true }" />
23658        </form>
23659        <pre>user.name = <span ng-bind="user.name()"></span></pre>
23660      </div>
23661    </file>
23662    <file name="app.js">
23663      angular.module('getterSetterExample', [])
23664        .controller('ExampleController', ['$scope', function($scope) {
23665          var _name = 'Brian';
23666          $scope.user = {
23667            name: function(newName) {
23668              return angular.isDefined(newName) ? (_name = newName) : _name;
23669            }
23670          };
23671        }]);
23672    </file>
23673  </example>
23674 */
23675var ngModelOptionsDirective = function() {
23676  return {
23677    restrict: 'A',
23678    controller: ['$scope', '$attrs', function($scope, $attrs) {
23679      var that = this;
23680      this.$options = $scope.$eval($attrs.ngModelOptions);
23681      // Allow adding/overriding bound events
23682      if (this.$options.updateOn !== undefined) {
23683        this.$options.updateOnDefault = false;
23684        // extract "default" pseudo-event from list of events that can trigger a model update
23685        this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
23686          that.$options.updateOnDefault = true;
23687          return ' ';
23688        }));
23689      } else {
23690        this.$options.updateOnDefault = true;
23691      }
23692    }]
23693  };
23694};
23695
23696
23697
23698// helper methods
23699function addSetValidityMethod(context) {
23700  var ctrl = context.ctrl,
23701      $element = context.$element,
23702      classCache = {},
23703      set = context.set,
23704      unset = context.unset,
23705      parentForm = context.parentForm,
23706      $animate = context.$animate;
23707
23708  classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
23709
23710  ctrl.$setValidity = setValidity;
23711
23712  function setValidity(validationErrorKey, state, controller) {
23713    if (state === undefined) {
23714      createAndSet('$pending', validationErrorKey, controller);
23715    } else {
23716      unsetAndCleanup('$pending', validationErrorKey, controller);
23717    }
23718    if (!isBoolean(state)) {
23719      unset(ctrl.$error, validationErrorKey, controller);
23720      unset(ctrl.$$success, validationErrorKey, controller);
23721    } else {
23722      if (state) {
23723        unset(ctrl.$error, validationErrorKey, controller);
23724        set(ctrl.$$success, validationErrorKey, controller);
23725      } else {
23726        set(ctrl.$error, validationErrorKey, controller);
23727        unset(ctrl.$$success, validationErrorKey, controller);
23728      }
23729    }
23730    if (ctrl.$pending) {
23731      cachedToggleClass(PENDING_CLASS, true);
23732      ctrl.$valid = ctrl.$invalid = undefined;
23733      toggleValidationCss('', null);
23734    } else {
23735      cachedToggleClass(PENDING_CLASS, false);
23736      ctrl.$valid = isObjectEmpty(ctrl.$error);
23737      ctrl.$invalid = !ctrl.$valid;
23738      toggleValidationCss('', ctrl.$valid);
23739    }
23740
23741    // re-read the state as the set/unset methods could have
23742    // combined state in ctrl.$error[validationError] (used for forms),
23743    // where setting/unsetting only increments/decrements the value,
23744    // and does not replace it.
23745    var combinedState;
23746    if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
23747      combinedState = undefined;
23748    } else if (ctrl.$error[validationErrorKey]) {
23749      combinedState = false;
23750    } else if (ctrl.$$success[validationErrorKey]) {
23751      combinedState = true;
23752    } else {
23753      combinedState = null;
23754    }
23755
23756    toggleValidationCss(validationErrorKey, combinedState);
23757    parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
23758  }
23759
23760  function createAndSet(name, value, controller) {
23761    if (!ctrl[name]) {
23762      ctrl[name] = {};
23763    }
23764    set(ctrl[name], value, controller);
23765  }
23766
23767  function unsetAndCleanup(name, value, controller) {
23768    if (ctrl[name]) {
23769      unset(ctrl[name], value, controller);
23770    }
23771    if (isObjectEmpty(ctrl[name])) {
23772      ctrl[name] = undefined;
23773    }
23774  }
23775
23776  function cachedToggleClass(className, switchValue) {
23777    if (switchValue && !classCache[className]) {
23778      $animate.addClass($element, className);
23779      classCache[className] = true;
23780    } else if (!switchValue && classCache[className]) {
23781      $animate.removeClass($element, className);
23782      classCache[className] = false;
23783    }
23784  }
23785
23786  function toggleValidationCss(validationErrorKey, isValid) {
23787    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
23788
23789    cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
23790    cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
23791  }
23792}
23793
23794function isObjectEmpty(obj) {
23795  if (obj) {
23796    for (var prop in obj) {
23797      return false;
23798    }
23799  }
23800  return true;
23801}
23802
23803/**
23804 * @ngdoc directive
23805 * @name ngNonBindable
23806 * @restrict AC
23807 * @priority 1000
23808 *
23809 * @description
23810 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
23811 * DOM element. This is useful if the element contains what appears to be Angular directives and
23812 * bindings but which should be ignored by Angular. This could be the case if you have a site that
23813 * displays snippets of code, for instance.
23814 *
23815 * @element ANY
23816 *
23817 * @example
23818 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
23819 * but the one wrapped in `ngNonBindable` is left alone.
23820 *
23821 * @example
23822    <example>
23823      <file name="index.html">
23824        <div>Normal: {{1 + 2}}</div>
23825        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
23826      </file>
23827      <file name="protractor.js" type="protractor">
23828       it('should check ng-non-bindable', function() {
23829         expect(element(by.binding('1 + 2')).getText()).toContain('3');
23830         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
23831       });
23832      </file>
23833    </example>
23834 */
23835var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
23836
23837/**
23838 * @ngdoc directive
23839 * @name ngPluralize
23840 * @restrict EA
23841 *
23842 * @description
23843 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
23844 * These rules are bundled with angular.js, but can be overridden
23845 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
23846 * by specifying the mappings between
23847 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
23848 * and the strings to be displayed.
23849 *
23850 * # Plural categories and explicit number rules
23851 * There are two
23852 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
23853 * in Angular's default en-US locale: "one" and "other".
23854 *
23855 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
23856 * any number that is not 1), an explicit number rule can only match one number. For example, the
23857 * explicit number rule for "3" matches the number 3. There are examples of plural categories
23858 * and explicit number rules throughout the rest of this documentation.
23859 *
23860 * # Configuring ngPluralize
23861 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
23862 * You can also provide an optional attribute, `offset`.
23863 *
23864 * The value of the `count` attribute can be either a string or an {@link guide/expression
23865 * Angular expression}; these are evaluated on the current scope for its bound value.
23866 *
23867 * The `when` attribute specifies the mappings between plural categories and the actual
23868 * string to be displayed. The value of the attribute should be a JSON object.
23869 *
23870 * The following example shows how to configure ngPluralize:
23871 *
23872 * ```html
23873 * <ng-pluralize count="personCount"
23874                 when="{'0': 'Nobody is viewing.',
23875 *                      'one': '1 person is viewing.',
23876 *                      'other': '{} people are viewing.'}">
23877 * </ng-pluralize>
23878 *```
23879 *
23880 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
23881 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
23882 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
23883 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
23884 * show "a dozen people are viewing".
23885 *
23886 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
23887 * into pluralized strings. In the previous example, Angular will replace `{}` with
23888 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
23889 * for <span ng-non-bindable>{{numberExpression}}</span>.
23890 *
23891 * # Configuring ngPluralize with offset
23892 * The `offset` attribute allows further customization of pluralized text, which can result in
23893 * a better user experience. For example, instead of the message "4 people are viewing this document",
23894 * you might display "John, Kate and 2 others are viewing this document".
23895 * The offset attribute allows you to offset a number by any desired value.
23896 * Let's take a look at an example:
23897 *
23898 * ```html
23899 * <ng-pluralize count="personCount" offset=2
23900 *               when="{'0': 'Nobody is viewing.',
23901 *                      '1': '{{person1}} is viewing.',
23902 *                      '2': '{{person1}} and {{person2}} are viewing.',
23903 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
23904 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
23905 * </ng-pluralize>
23906 * ```
23907 *
23908 * Notice that we are still using two plural categories(one, other), but we added
23909 * three explicit number rules 0, 1 and 2.
23910 * When one person, perhaps John, views the document, "John is viewing" will be shown.
23911 * When three people view the document, no explicit number rule is found, so
23912 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
23913 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
23914 * is shown.
23915 *
23916 * Note that when you specify offsets, you must provide explicit number rules for
23917 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
23918 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
23919 * plural categories "one" and "other".
23920 *
23921 * @param {string|expression} count The variable to be bound to.
23922 * @param {string} when The mapping between plural category to its corresponding strings.
23923 * @param {number=} offset Offset to deduct from the total number.
23924 *
23925 * @example
23926    <example module="pluralizeExample">
23927      <file name="index.html">
23928        <script>
23929          angular.module('pluralizeExample', [])
23930            .controller('ExampleController', ['$scope', function($scope) {
23931              $scope.person1 = 'Igor';
23932              $scope.person2 = 'Misko';
23933              $scope.personCount = 1;
23934            }]);
23935        </script>
23936        <div ng-controller="ExampleController">
23937          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
23938          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
23939          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
23940
23941          <!--- Example with simple pluralization rules for en locale --->
23942          Without Offset:
23943          <ng-pluralize count="personCount"
23944                        when="{'0': 'Nobody is viewing.',
23945                               'one': '1 person is viewing.',
23946                               'other': '{} people are viewing.'}">
23947          </ng-pluralize><br>
23948
23949          <!--- Example with offset --->
23950          With Offset(2):
23951          <ng-pluralize count="personCount" offset=2
23952                        when="{'0': 'Nobody is viewing.',
23953                               '1': '{{person1}} is viewing.',
23954                               '2': '{{person1}} and {{person2}} are viewing.',
23955                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
23956                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
23957          </ng-pluralize>
23958        </div>
23959      </file>
23960      <file name="protractor.js" type="protractor">
23961        it('should show correct pluralized string', function() {
23962          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
23963          var withOffset = element.all(by.css('ng-pluralize')).get(1);
23964          var countInput = element(by.model('personCount'));
23965
23966          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
23967          expect(withOffset.getText()).toEqual('Igor is viewing.');
23968
23969          countInput.clear();
23970          countInput.sendKeys('0');
23971
23972          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
23973          expect(withOffset.getText()).toEqual('Nobody is viewing.');
23974
23975          countInput.clear();
23976          countInput.sendKeys('2');
23977
23978          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
23979          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
23980
23981          countInput.clear();
23982          countInput.sendKeys('3');
23983
23984          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
23985          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
23986
23987          countInput.clear();
23988          countInput.sendKeys('4');
23989
23990          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
23991          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
23992        });
23993        it('should show data-bound names', function() {
23994          var withOffset = element.all(by.css('ng-pluralize')).get(1);
23995          var personCount = element(by.model('personCount'));
23996          var person1 = element(by.model('person1'));
23997          var person2 = element(by.model('person2'));
23998          personCount.clear();
23999          personCount.sendKeys('4');
24000          person1.clear();
24001          person1.sendKeys('Di');
24002          person2.clear();
24003          person2.sendKeys('Vojta');
24004          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
24005        });
24006      </file>
24007    </example>
24008 */
24009var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
24010  var BRACE = /{}/g,
24011      IS_WHEN = /^when(Minus)?(.+)$/;
24012
24013  return {
24014    restrict: 'EA',
24015    link: function(scope, element, attr) {
24016      var numberExp = attr.count,
24017          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
24018          offset = attr.offset || 0,
24019          whens = scope.$eval(whenExp) || {},
24020          whensExpFns = {},
24021          startSymbol = $interpolate.startSymbol(),
24022          endSymbol = $interpolate.endSymbol(),
24023          braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
24024          watchRemover = angular.noop,
24025          lastCount;
24026
24027      forEach(attr, function(expression, attributeName) {
24028        var tmpMatch = IS_WHEN.exec(attributeName);
24029        if (tmpMatch) {
24030          var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
24031          whens[whenKey] = element.attr(attr.$attr[attributeName]);
24032        }
24033      });
vendor: 10,186 bytes, lines 24034-24265
24034      forEach(whens, function(expression, key) {
24035        whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
24036
24037      });
24038
24039      scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
24040        var count = parseFloat(newVal);
24041        var countIsNaN = isNaN(count);
24042
24043        if (!countIsNaN && !(count in whens)) {
24044          // If an explicit number rule such as 1, 2, 3... is defined, just use it.
24045          // Otherwise, check it against pluralization rules in $locale service.
24046          count = $locale.pluralCat(count - offset);
24047        }
24048
24049        // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
24050        // In JS `NaN !== NaN`, so we have to exlicitly check.
24051        if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
24052          watchRemover();
24053          watchRemover = scope.$watch(whensExpFns[count], updateElementText);
24054          lastCount = count;
24055        }
24056      });
24057
24058      function updateElementText(newText) {
24059        element.text(newText || '');
24060      }
24061    }
24062  };
24063}];
24064
24065/**
24066 * @ngdoc directive
24067 * @name ngRepeat
24068 *
24069 * @description
24070 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
24071 * instance gets its own scope, where the given loop variable is set to the current collection item,
24072 * and `$index` is set to the item index or key.
24073 *
24074 * Special properties are exposed on the local scope of each template instance, including:
24075 *
24076 * | Variable  | Type            | Details                                                                     |
24077 * |-----------|-----------------|-----------------------------------------------------------------------------|
24078 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
24079 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
24080 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
24081 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
24082 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
24083 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
24084 *
24085 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
24086 * This may be useful when, for instance, nesting ngRepeats.
24087 *
24088 * # Iterating over object properties
24089 *
24090 * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
24091 * syntax:
24092 *
24093 * ```js
24094 * <div ng-repeat="(key, value) in myObj"> ... </div>
24095 * ```
24096 *
24097 * You need to be aware that the JavaScript specification does not define what order
24098 * it will return the keys for an object. In order to have a guaranteed deterministic order
24099 * for the keys, Angular versions up to and including 1.3 **sort the keys alphabetically**.
24100 *
24101 * If this is not desired, the recommended workaround is to convert your object into an array
24102 * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
24103 * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
24104 * or implement a `$watch` on the object yourself.
24105 *
24106 * In version 1.4 we will remove the sorting, since it seems that browsers generally follow the
24107 * strategy of providing keys in the order in which they were defined, although there are exceptions
24108 * when keys are deleted and reinstated.
24109 *
24110 *
24111 * # Special repeat start and end points
24112 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
24113 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
24114 * 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)
24115 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
24116 *
24117 * The example below makes use of this feature:
24118 * ```html
24119 *   <header ng-repeat-start="item in items">
24120 *     Header {{ item }}
24121 *   </header>
24122 *   <div class="body">
24123 *     Body {{ item }}
24124 *   </div>
24125 *   <footer ng-repeat-end>
24126 *     Footer {{ item }}
24127 *   </footer>
24128 * ```
24129 *
24130 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
24131 * ```html
24132 *   <header>
24133 *     Header A
24134 *   </header>
24135 *   <div class="body">
24136 *     Body A
24137 *   </div>
24138 *   <footer>
24139 *     Footer A
24140 *   </footer>
24141 *   <header>
24142 *     Header B
24143 *   </header>
24144 *   <div class="body">
24145 *     Body B
24146 *   </div>
24147 *   <footer>
24148 *     Footer B
24149 *   </footer>
24150 * ```
24151 *
24152 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
24153 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
24154 *
24155 * @animations
24156 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
24157 *
24158 * **.leave** - when an item is removed from the list or when an item is filtered out
24159 *
24160 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
24161 *
24162 * @element ANY
24163 * @scope
24164 * @priority 1000
24165 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
24166 *   formats are currently supported:
24167 *
24168 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
24169 *     is a scope expression giving the collection to enumerate.
24170 *
24171 *     For example: `album in artist.albums`.
24172 *
24173 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
24174 *     and `expression` is the scope expression giving the collection to enumerate.
24175 *
24176 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
24177 *
24178 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
24179 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
24180 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
24181 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
24182 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
24183 *     before specifying a tracking expression.
24184 *
24185 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
24186 *     will be associated by item identity in the array.
24187 *
24188 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
24189 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
24190 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
24191 *     element in the same way in the DOM.
24192 *
24193 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
24194 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
24195 *     property is same.
24196 *
24197 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
24198 *     to items in conjunction with a tracking expression.
24199 *
24200 *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
24201 *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
24202 *     when a filter is active on the repeater, but the filtered result set is empty.
24203 *
24204 *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
24205 *     the items have been processed through the filter.
24206 *
24207 * @example
24208 * This example initializes the scope to a list of names and
24209 * then uses `ngRepeat` to display every person:
24210  <example module="ngAnimate" deps="angular-animate.js" animations="true">
24211    <file name="index.html">
24212      <div ng-init="friends = [
24213        {name:'John', age:25, gender:'boy'},
24214        {name:'Jessie', age:30, gender:'girl'},
24215        {name:'Johanna', age:28, gender:'girl'},
24216        {name:'Joy', age:15, gender:'girl'},
24217        {name:'Mary', age:28, gender:'girl'},
24218        {name:'Peter', age:95, gender:'boy'},
24219        {name:'Sebastian', age:50, gender:'boy'},
24220        {name:'Erika', age:27, gender:'girl'},
24221        {name:'Patrick', age:40, gender:'boy'},
24222        {name:'Samantha', age:60, gender:'girl'}
24223      ]">
24224        I have {{friends.length}} friends. They are:
24225        <input type="search" ng-model="q" placeholder="filter friends..." />
24226        <ul class="example-animate-container">
24227          <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
24228            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
24229          </li>
24230          <li class="animate-repeat" ng-if="results.length == 0">
24231            <strong>No results found...</strong>
24232          </li>
24233        </ul>
24234      </div>
24235    </file>
24236    <file name="animations.css">
24237      .example-animate-container {
24238        background:white;
24239        border:1px solid black;
24240        list-style:none;
24241        margin:0;
24242        padding:0 10px;
24243      }
24244
24245      .animate-repeat {
24246        line-height:40px;
24247        list-style:none;
24248        box-sizing:border-box;
24249      }
24250
24251      .animate-repeat.ng-move,
24252      .animate-repeat.ng-enter,
24253      .animate-repeat.ng-leave {
24254        -webkit-transition:all linear 0.5s;
24255        transition:all linear 0.5s;
24256      }
24257
24258      .animate-repeat.ng-leave.ng-leave-active,
24259      .animate-repeat.ng-move,
24260      .animate-repeat.ng-enter {
24261        opacity:0;
24262        max-height:0;
24263      }
24264
24265      .animate-repeat.ng-leave,
24266      .animate-repeat.ng-move.ng-move-active,
24267      .animate-repeat.ng-enter.ng-enter-active {
24268        opacity:1;
24269        max-height:40px;
24270      }
24271    </file>
24272    <file name="protractor.js" type="protractor">
24273      var friends = element.all(by.repeater('friend in friends'));
24274
24275      it('should render initial data set', function() {
24276        expect(friends.count()).toBe(10);
24277        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
24278        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
24279        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
24280        expect(element(by.binding('friends.length')).getText())
24281            .toMatch("I have 10 friends. They are:");
24282      });
24283
24284       it('should update repeater when filter predicate changes', function() {
24285         expect(friends.count()).toBe(10);
24286
24287         element(by.model('q')).sendKeys('ma');
24288
24289         expect(friends.count()).toBe(2);
24290         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
24291         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
24292       });
24293      </file>
24294    </example>
24295 */
24296var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
24297  var NG_REMOVED = '$$NG_REMOVED';
24298  var ngRepeatMinErr = minErr('ngRepeat');
24299
24300  var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
24301    // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
24302    scope[valueIdentifier] = value;
24303    if (keyIdentifier) scope[keyIdentifier] = key;
24304    scope.$index = index;
24305    scope.$first = (index === 0);
24306    scope.$last = (index === (arrayLength - 1));
24307    scope.$middle = !(scope.$first || scope.$last);
24308    // jshint bitwise: false
24309    scope.$odd = !(scope.$even = (index&1) === 0);
24310    // jshint bitwise: true
24311  };
24312
24313  var getBlockStart = function(block) {
24314    return block.clone[0];
24315  };
24316
24317  var getBlockEnd = function(block) {
24318    return block.clone[block.clone.length - 1];
24319  };
24320
24321
24322  return {
24323    restrict: 'A',
24324    multiElement: true,
24325    transclude: 'element',
24326    priority: 1000,
24327    terminal: true,
24328    $$tlb: true,
24329    compile: function ngRepeatCompile($element, $attr) {
24330      var expression = $attr.ngRepeat;
24331      var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
24332
24333      var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
24334
24335      if (!match) {
24336        throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
24337            expression);
24338      }
24339
24340      var lhs = match[1];
24341      var rhs = match[2];
24342      var aliasAs = match[3];
24343      var trackByExp = match[4];
24344
24345      match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
24346
24347      if (!match) {
24348        throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
24349            lhs);
24350      }
24351      var valueIdentifier = match[3] || match[1];
24352      var keyIdentifier = match[2];
24353
24354      if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
24355          /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
24356        throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
24357          aliasAs);
24358      }
24359
24360      var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
24361      var hashFnLocals = {$id: hashKey};
24362
24363      if (trackByExp) {
24364        trackByExpGetter = $parse(trackByExp);
24365      } else {
24366        trackByIdArrayFn = function(key, value) {
24367          return hashKey(value);
24368        };
24369        trackByIdObjFn = function(key) {
24370          return key;
24371        };
24372      }
24373
24374      return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
24375
24376        if (trackByExpGetter) {
24377          trackByIdExpFn = function(key, value, index) {
24378            // assign key, value, and $index to the locals so that they can be used in hash functions
24379            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
24380            hashFnLocals[valueIdentifier] = value;
24381            hashFnLocals.$index = index;
24382            return trackByExpGetter($scope, hashFnLocals);
24383          };
24384        }
24385
24386        // Store a list of elements from previous run. This is a hash where key is the item from the
24387        // iterator, and the value is objects with following properties.
24388        //   - scope: bound scope
24389        //   - element: previous element.
24390        //   - index: position
24391        //
24392        // We are using no-proto object so that we don't need to guard against inherited props via
24393        // hasOwnProperty.
24394        var lastBlockMap = createMap();
24395
24396        //watch props
24397        $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
24398          var index, length,
24399              previousNode = $element[0],     // node that cloned 
vendor: 5,124 bytes, lines 24399-24511
24399nodes should be inserted after
24400                                              // initialized to the comment node anchor
24401              nextNode,
24402              // Same as lastBlockMap but it has the current state. It will become the
24403              // lastBlockMap on the next iteration.
24404              nextBlockMap = createMap(),
24405              collectionLength,
24406              key, value, // key/value of iteration
24407              trackById,
24408              trackByIdFn,
24409              collectionKeys,
24410              block,       // last object information {scope, element, id}
24411              nextBlockOrder,
24412              elementsToRemove;
24413
24414          if (aliasAs) {
24415            $scope[aliasAs] = collection;
24416          }
24417
24418          if (isArrayLike(collection)) {
24419            collectionKeys = collection;
24420            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
24421          } else {
24422            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
24423            // if object, extract keys, sort them and use to determine order of iteration over obj props
24424            collectionKeys = [];
24425            for (var itemKey in collection) {
24426              if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
24427                collectionKeys.push(itemKey);
24428              }
24429            }
24430            collectionKeys.sort();
24431          }
24432
24433          collectionLength = collectionKeys.length;
24434          nextBlockOrder = new Array(collectionLength);
24435
24436          // locate existing items
24437          for (index = 0; index < collectionLength; index++) {
24438            key = (collection === collectionKeys) ? index : collectionKeys[index];
24439            value = collection[key];
24440            trackById = trackByIdFn(key, value, index);
24441            if (lastBlockMap[trackById]) {
24442              // found previously seen block
24443              block = lastBlockMap[trackById];
24444              delete lastBlockMap[trackById];
24445              nextBlockMap[trackById] = block;
24446              nextBlockOrder[index] = block;
24447            } else if (nextBlockMap[trackById]) {
24448              // if collision detected. restore lastBlockMap and throw an error
24449              forEach(nextBlockOrder, function(block) {
24450                if (block && block.scope) lastBlockMap[block.id] = block;
24451              });
24452              throw ngRepeatMinErr('dupes',
24453                  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
24454                  expression, trackById, value);
24455            } else {
24456              // new never before seen block
24457              nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
24458              nextBlockMap[trackById] = true;
24459            }
24460          }
24461
24462          // remove leftover items
24463          for (var blockKey in lastBlockMap) {
24464            block = lastBlockMap[blockKey];
24465            elementsToRemove = getBlockNodes(block.clone);
24466            $animate.leave(elementsToRemove);
24467            if (elementsToRemove[0].parentNode) {
24468              // if the element was not removed yet because of pending animation, mark it as deleted
24469              // so that we can ignore it later
24470              for (index = 0, length = elementsToRemove.length; index < length; index++) {
24471                elementsToRemove[index][NG_REMOVED] = true;
24472              }
24473            }
24474            block.scope.$destroy();
24475          }
24476
24477          // we are not using forEach for perf reasons (trying to avoid #call)
24478          for (index = 0; index < collectionLength; index++) {
24479            key = (collection === collectionKeys) ? index : collectionKeys[index];
24480            value = collection[key];
24481            block = nextBlockOrder[index];
24482
24483            if (block.scope) {
24484              // if we have already seen this object, then we need to reuse the
24485              // associated scope/element
24486
24487              nextNode = previousNode;
24488
24489              // skip nodes that are already pending removal via leave animation
24490              do {
24491                nextNode = nextNode.nextSibling;
24492              } while (nextNode && nextNode[NG_REMOVED]);
24493
24494              if (getBlockStart(block) != nextNode) {
24495                // existing item which got moved
24496                $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
24497              }
24498              previousNode = getBlockEnd(block);
24499              updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24500            } else {
24501              // new item which we don't know about
24502              $transclude(function ngRepeatTransclude(clone, scope) {
24503                block.scope = scope;
24504                // http://jsperf.com/clone-vs-createcomment
24505                var endNode = ngRepeatEndComment.cloneNode(false);
24506                clone[clone.length++] = endNode;
24507
24508                // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
24509                $animate.enter(clone, null, jqLite(previousNode));
24510                previousNode = endNode;
24511                // Note: We only need the first/last node of the cloned 
24511nodes.
24512                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
24513                // by a directive with templateUrl when its template arrives.
24514                block.clone = clone;
24515                nextBlockMap[block.id] = block;
24516                updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
24517              });
24518            }
24519          }
24520          lastBlockMap = nextBlockMap;
24521        });
24522      };
24523    }
24524  };
24525}];
24526
24527var NG_HIDE_CLASS = 'ng-hide';
24528var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24529/**
24530 * @ngdoc directive
24531 * @name ngShow
24532 *
24533 * @description
24534 * The `ngShow` directive shows or hides the given HTML element based on the expression
24535 * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
24536 * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
24537 * in AngularJS and sets the display style to none (using an !important flag).
24538 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
24539 *
24540 * ```html
24541 * <!-- when $scope.myValue is truthy (element is visible) -->
24542 * <div ng-show="myValue"></div>
24543 *
24544 * <!-- when $scope.myValue is falsy (element is hidden) -->
24545 * <div ng-show="myValue" class="ng-hide"></div>
24546 * ```
24547 *
24548 * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
24549 * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
24550 * from the element causing the element not to appear hidden.
24551 *
24552 * ## Why is !important used?
24553 *
24554 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
24555 * can be easily overridden by heavier selectors. For example, something as simple
24556 * as changing the display style on a HTML list item would make hidden elements appear visible.
24557 * This also becomes a bigger issue when dealing with CSS frameworks.
24558 *
24559 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
24560 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
24561 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
24562 *
24563 * ### Overriding `.ng-hide`
24564 *
24565 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24566 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24567 * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
24568 * with extra animation classes that can be added.
24569 *
24570 * ```css
24571 * .ng-hide:not(.ng-hide-animate) {
24572 *   /&#42; this is just another form of hiding an element &#42;/
24573 *   display: block!important;
24574 *   position: absolute;
24575 *   top: -9999px;
24576 *   left: -9999px;
24577 * }
24578 * ```
24579 *
24580 * By default you don't need to override in CSS anything and the animations will work around the display style.
24581 *
24582 * ## A note about animations with `ngShow`
24583 *
24584 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
24585 * is true and false. This system works like the animation system present with ngClass except that
24586 * you must also include the !important flag to override the display property
24587 * so that you can perform an animation when the element is hidden during the time of the animation.
24588 *
24589 * ```css
24590 * //
24591 * //a working example can be found at the bottom of this page
24592 * //
24593 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24594 *   /&#42; this is required as of 1.3x to properly
24595 *      apply all styling in a show/hide animation &#42;/
24596 *   transition: 0s linear all;
24597 * }
24598 *
24599 * .my-element.ng-hide-add-active,
24600 * .my-element.ng-hide-remove-active {
24601 *   /&#42; the transition is defined in the active class &#42;/
24602 *   transition: 1s linear all;
24603 * }
24604 *
24605 * .my-element.ng-hide-add { ... }
24606 * .my-element.ng-hide-add.ng-hide-add-active { ... }
24607 * .my-element.ng-hide-remove { ... }
24608 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
24609 * ```
24610 *
24611 * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
24612 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
24613 *
24614 * @animations
24615 * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
24616 * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
24617 *
24618 * @element ANY
24619 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
24620 *     then the element is shown or hidden respectively.
24621 *
24622 * @example
24623  <example module="ngAnimate" deps="angular-animate.js" animations="true">
24624    <file name="index.html">
24625      Click me: <input type="checkbox" ng-model="checked"><br/>
24626      <div>
24627        Show:
24628        <div class="check-element animate-show" ng-show="checked">
24629          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
24630        </div>
24631      </div>
24632      <div>
24633        Hide:
24634        <div class="check-element animate-show" ng-hide="checked">
24635          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
24636        </div>
24637      </div>
24638    </file>
24639    <file name="glyphicons.css">
24640      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
24641    </file>
24642    <file name="animations.css">
24643      .animate-show {
24644        line-height: 20px;
24645        opacity: 1;
24646        padding: 10px;
24647        border: 1px solid black;
24648        background: white;
24649      }
24650
24651      .animate-show.ng-hide-add.ng-hide-add-active,
24652      .animate-show.ng-hide-remove.ng-hide-remove-active {
24653        -webkit-transition: all linear 0.5s;
24654        transition: all linear 0.5s;
24655      }
24656
24657      .animate-show.ng-hide {
24658        line-height: 0;
24659        opacity: 0;
24660        padding: 0 10px;
24661      }
24662
24663      .check-element {
24664        padding: 10px;
24665        border: 1px solid black;
24666        background: white;
24667      }
24668    </file>
24669    <file name="protractor.js" type="protractor">
24670      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
24671      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
24672
24673      it('should check ng-show / ng-hide', function() {
24674        expect(thumbsUp.isDisplayed()).toBeFalsy();
24675        expect(thumbsDown.isDisplayed()).toBeTruthy();
24676
24677        element(by.model('checked')).click();
24678
24679        expect(thumbsUp.isDisplayed()).toBeTruthy();
24680        expect(thumbsDown.isDisplayed()).toBeFalsy();
24681      });
24682    </file>
24683  </example>
24684 */
24685var ngShowDirective = ['$animate', function($animate) {
24686  return {
24687    restrict: 'A',
24688    multiElement: true,
24689    link: function(scope, element, attr) {
24690      scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
24691        // we're adding a temporary, animation-specific class for ng-hide since this way
24692        // we can control when the element is actually displayed on screen without having
24693        // to have a global/greedy CSS selector that breaks when other animations are run.
24694        // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
24695        $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
24696          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
24697        });
24698      });
24699    }
24700  };
24701}];
24702
24703
24704/**
24705 * @ngdoc directive
24706 * @name ngHide
24707 *
24708 * @description
24709 * The `ngHide` directive shows or hides the given HTML element based on the expression
24710 * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
24711 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
24712 * in AngularJS and sets the display style to none (using an !important flag).
24713 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
24714 *
24715 * ```html
24716 * <!-- when $scope.myValue is truthy (element is hidden) -->
24717 * <div ng-hide="myValue" class="ng-hide"></div>
24718 *
24719 * <!-- when $scope.myValue is falsy (element is visible) -->
24720 * <div ng-hide="myValue"></div>
24721 * ```
24722 *
24723 * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
24724 * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
24725 * from the element causing the element not to appear hidden.
24726 *
24727 * ## Why is !important used?
24728 *
24729 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
24730 * can be easily overridden by heavier selectors. For example, something as simple
24731 * as changing the display style on a HTML list item would make hidden elements appear visible.
24732 * This also becomes a bigger issue when dealing with CSS frameworks.
24733 *
24734 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
24735 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
24736 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
24737 *
24738 * ### Overriding `.ng-hide`
24739 *
24740 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24741 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24742 * class in CSS:
24743 *
24744 * ```css
24745 * .ng-hide {
24746 *   /&#42; this is just another form of hiding an element &#42;/
24747 *   display: block!important;
24748 *   position: absolute;
24749 *   top: -9999px;
24750 *   left: -9999px;
24751 * }
24752 * ```
24753 *
24754 * By default you don't need to override in CSS anything and the animations will work around the display style.
24755 *
24756 * ## A note about animations with `ngHide`
24757 *
24758 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
24759 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
24760 * CSS class is added and removed for you instead of your own CSS class.
24761 *
24762 * ```css
24763 * //
24764 * //a working example can be found at the bottom of this page
24765 * //
24766 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24767 *   transition: 0.5s linear all;
24768 * }
24769 *
24770 * .my-element.ng-hide-add { ... }
24771 * .my-element.ng-hide-add.ng-hide-add-active { ... }
24772 * .my-element.ng-hide-remove { ... }
24773 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
24774 * ```
24775 *
24776 * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
24777 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
24778 *
24779 * @animations
24780 * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
24781 * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
24782 *
24783 * @element ANY
24784 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
24785 *     the element is shown or hidden respectively.
24786 *
24787 * @example
24788  <example module="ngAnimate" deps="angular-animate.js" animations="true">
24789    <file name="index.html">
24790      Click me: <input type="checkbox" ng-model="checked"><br/>
24791      <div>
24792        Show:
24793        <div class="check-element animate-hide" ng-show="checked">
24794          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
24795        </div>
24796      </div>
24797      <div>
24798        Hide:
24799        <div class="check-element animate-hide" ng-hide="checked">
24800          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
24801        </div>
24802      </div>
24803    </file>
24804    <file name="glyphicons.css">
24805      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
24806    </file>
24807    <file name="animations.css">
24808      .animate-hide {
24809        -webkit-transition: all linear 0.5s;
24810        transition: all linear 0.5s;
24811        line-height: 20px;
24812        opacity: 1;
24813        padding: 10px;
24814        border: 1px solid black;
24815        background: white;
24816      }
24817
24818      .animate-hide.ng-hide {
24819        line-height: 0;
24820        opacity: 0;
24821        padding: 0 10px;
24822      }
24823
24824      .check-element {
24825        padding: 10px;
24826        border: 1px solid black;
24827        background: white;
24828      }
24829    </file>
24830    <file name="protractor.js" type="protractor">
24831      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
24832      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
24833
24834      it('should check ng-show / ng-hide', function() {
24835        expect(thumbsUp.isDisplayed()).toBeFalsy();
24836        expect(thumbsDown.isDisplayed()).toBeTruthy();
24837
24838        element(by.model('checked')).click();
24839
24840        expect(thumbsUp.isDisplayed()).toBeTruthy();
24841        expect(thumbsDown.isDisplayed()).toBeFalsy();
24842      });
24843    </file>
24844  </example>
24845 */
24846var ngHideDirective = ['$animate', function($animate) {
24847  return {
24848    restrict: 'A',
24849    multiElement: true,
24850    link: function(scope, element, attr) {
24851      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
24852        // The comment inside of the ngShowDirective explains why we add and
24853        // remove a temporary class for the show/hide animation
24854        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
24855          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
24856        });
24857      });
24858    }
24859  };
24860}];
24861
24862/**
24863 * @ngdoc directive
24864 * @name ngStyle
24865 * @restrict AC
24866 *
24867 * @description
24868 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
24869 *
24870 * @element ANY
24871 * @param {expression} ngStyle
24872 *
24873 * {@link guide/expression Expression} which evals to an
24874 * object whose keys are CSS style names and values are corresponding values for those CSS
24875 * keys.
24876 *
24877 * Since some CSS style names are not valid keys for an object, they must be quoted.
24878 * See the 'background-color' style in the example below.
24879 *
24880 * @example
24881   <example>
24882     <file name="index.html">
24883        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
24884        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
24885        <input type="button" value="clear" ng-click="myStyle={}">
24886        <br/>
24887        <span ng-style="myStyle">Sample Text</span>
24888        <pre>myStyle={{myStyle}}</pre>
24889     </file>
24890     <file name="style.css">
24891       span {
24892         color: black;
24893       }
24894     </file>
24895     <file name="protractor.js" type="protractor">
24896       var colorSpan = element(by.css('span'));
24897
24898       it('should check ng-style', function() {
24899         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
24900         element(by.css('input[value=\'set color\']')).click();
24901         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
24902         element(by.css('input[value=clear]')).click();
24903         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
24904       });
24905     </file>
24906   </example>
24907 */
24908var ngStyleDirective = ngDirective(function(scope, element, attr) {
24909  scope.$watchCollection(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
24910    if (oldStyles && (newStyles !== oldStyles)) {
24911      forEach(oldStyles, function(val, style) { element.css(style, '');});
24912    }
24913    if (newStyles) element.css(newStyles);
24914  });
24915});
24916
24917/**
24918 * @ngdoc directive
24919 * @name ngSwitch
24920 * @restrict EA
24921 *
24922 * @description
24923 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
24924 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
24925 * as specified in the template.
24926 *
24927 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
24928 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
24929 * matches the value obtained from the evaluated expression. In other words, you define a container element
24930 * (where you place the directive), place an expression on the **`on="..."` attribute**
24931 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
24932 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
24933 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
24934 * attribute is displayed.
24935 *
24936 * <div class="alert alert-info">
24937 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
24938 * as literal string values to match against.
24939 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
24939omeVal"` not against the
24940 * value of the expression `$scope.someVal`.
24941 * </div>
24942
24943 * @animations
24944 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
24945 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
24946 *
24947 * @usage
24948 *
24949 * ```
24950 * <ANY ng-switch="expression">
24951 *   <ANY ng-switch-when="matchValue1">...</ANY>
24952 *   <ANY ng-switch-when="matchValue2">...</ANY>
24953 *   <ANY ng-switch-default>...</ANY>
24954 * </ANY>
24955 * ```
24956 *
24957 *
24958 * @scope
24959 * @priority 1200
24960 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
24961 * On child elements add:
24962 *
24963 * * `ngSwitchWhen`: the case statement to match against. If match then this
24964 *   case will be displayed. If the same match appears multiple times, all the
24965 *   elements will be displayed.
24966 * * `ngSwitchDefault`: the default case when no other case match. If there
24967 *   are multiple default cases, all of them will be displayed when no other
24968 *   case match.
24969 *
24970 *
24971 * @example
24972  <example module="switchExample" deps="angular-animate.js" animations="true">
24973    <file name="index.html">
24974      <div ng-controller="ExampleController">
24975        <select ng-model="selection" ng-options="item for item in items">
24976        </select>
24977        <tt>selection={{selection}}</tt>
24978        <hr/>
24979        <div class="animate-switch-container"
24980          ng-switch on="selection">
24981            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
24982            <div class="animate-switch" ng-switch-when="home">Home Span</div>
24983            <div class="animate-switch" ng-switch-default>default</div>
24984        </div>
24985      </div>
24986    </file>
24987    <file name="script.js">
24988      angular.module('switchExample', ['ngAnimate'])
24989        .controller('ExampleController', ['$scope', function($scope) {
24990          $scope.items = ['settings', 'home', 'other'];
24991          $scope.selection = $scope.items[0];
24992        }]);
24993    </file>
24994    <file name="animations.css">
24995      .animate-switch-container {
24996        position:relative;
24997        background:white;
24998        border:1px solid black;
24999        height:40px;
25000        overflow:hidden;
25001      }
25002
25003      .animate-switch {
25004        padding:10px;
25005      }
25006
25007      .animate-switch.ng-animate {
25008        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25009        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
25010
25011        position:absolute;
25012        top:0;
25013        left:0;
25014        right:0;
25015        bottom:0;
25016      }
25017
25018      .animate-switch.ng-leave.ng-leave-active,
25019      .animate-switch.ng-enter {
25020        top:-50px;
25021      }
25022      .animate-switch.ng-leave,
25023      .animate-switch.ng-enter.ng-enter-active {
25024        top:0;
25025      }
25026    </file>
25027    <file name="protractor.js" type="protractor">
25028      var switchElem = element(by.css('[ng-switch]'));
25029      var select = element(by.model('selection'));
25030
25031      it('should start in settings', function() {
25032        expect(switchElem.getText()).toMatch(/Settings Div/);
25033      });
25034      it('should change to home', function() {
25035        select.all(by.css('option')).get(1).click();
25036        expect(switchElem.getText()).toMatch(/Home Span/);
25037      });
25038      it('should select default', function() {
25039        select.all(by.css('option')).get(2).click();
25040        expect(switchElem.getText()).toMatch(/default/);
25041      });
25042    </file>
25043  </example>
25044 */
25045var ngSwitchDirective = ['$animate', function($animate) {
25046  return {
25047    restrict: 'EA',
25048    require: 'ngSwitch',
25049
25050    // asks for $scope to fool the BC controller module
25051    controller: ['$scope', function ngSwitchController() {
25052     this.cases = {};
25053    }],
25054    link: function(scope, element, attr, ngSwitchController) {
25055      var watchExpr = attr.ngSwitch || attr.on,
25056          selectedTranscludes = [],
25057          selectedElements = [],
25058          previousLeaveAnimations = [],
25059          selectedScopes = [];
25060
25061      var spliceFactory = function(array, index) {
25062          return function() { array.splice(index, 1); };
25063      };
25064
25065      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
25066        var i, ii;
25067        for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
25068          $animate.cancel(previousLeaveAnimations[i]);
25069        }
25070        previousLeaveAnimations.length = 0;
25071
25072        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
25073          var selected = getBlockNodes(selectedElements[i].clone);
25074          selectedScopes[i].$destroy();
25075          var promise = previousLeaveAnimations[i] = $animate.leave(selected);
25076          promise.then(spliceFactory(previousLeaveAnimations, i));
25077        }
25078
25079        selectedElements.length = 0;
25080        selectedScopes.length = 0;
25081
25082        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
25083          forEach(selectedTranscludes, function(selectedTransclude) {
25084            selectedTransclude.transclude(function(caseElement, selectedScope) {
25085              selectedScopes.push(selectedScope);
25086              var anchor = selectedTransclude.element;
25087              caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
25088              var block = { clone: caseElement };
25089
25090              selectedElements.push(block);
25091              $animate.enter(caseElement, anchor.parent(), anchor);
25092            });
25093          });
25094        }
25095      });
25096    }
25097  };
25098}];
25099
25100var ngSwitchWhenDirective = ngDirective({
25101  transclude: 'element',
25102  priority: 1200,
25103  require: '^ngSwitch',
25104  multiElement: true,
25105  link: function(scope, element, attrs, ctrl, $transclude) {
25106    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
25107    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
25108  }
25109});
25110
25111var ngSwitchDefaultDirective = ngDirective({
25112  transclude: 'element',
25113  priority: 1200,
25114  require: '^ngSwitch',
25115  multiElement: true,
25116  link: function(scope, element, attr, ctrl, $transclude) {
25117    ctrl.cases['?'] = (ctrl.cases['?'] || []);
25118    ctrl.cases['?'].push({ transclude: $transclude, element: element });
25119   }
25120});
25121
25122/**
25123 * @ngdoc directive
25124 * @name ngTransclude
25125 * @restrict EAC
25126 *
25127 * @description
25128 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
25129 *
25130 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
25131 *
25132 * @element ANY
25133 *
25134 * @example
25135   <example module="transcludeExample">
25136     <file name="index.html">
25137       <script>
25138         angular.module('transcludeExample', [])
25139          .directive('pane', function(){
25140             return {
25141               restrict: 'E',
25142               transclude: true,
25143               scope: { title:'@' },
25144               template: '<div style="border: 1px solid black;">' +
25145                           '<div style="background-color: gray">{{title}}</div>' +
25146                           '<ng-transclude></ng-transclude>' +
25147                         '</div>'
25148             };
25149         })
25150         .controller('ExampleController', ['$scope', function($scope) {
25151           $scope.title = 'Lorem Ipsum';
25152           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
25153         }]);
25154       </script>
25155       <div ng-controller="ExampleController">
25156         <input ng-model="title"> <br/>
25157         <textarea ng-model="text"></textarea> <br/>
25158         <pane title="{{title}}">{{text}}</pane>
25159       </div>
25160     </file>
25161     <file name="protractor.js" type="protractor">
25162        it('should have transcluded', function() {
25163          var titleElement = element(by.model('title'));
25164          titleElement.clear();
25165          titleElement.sendKeys('TITLE');
25166          var textElement = element(by.model('text'));
25167          textElement.clear();
25168          textElement.sendKeys('TEXT');
25169          expect(element(by.binding('title')).getText()).toEqual('TITLE');
25170          expect(element(by.binding('text')).getText()).toEqual('TEXT');
25171        });
25172     </file>
25173   </example>
25174 *
25175 */
25176var ngTranscludeDirective = ngDirective({
25177  restrict: 'EAC',
25178  link: function($scope, $element, $attrs, controller, $transclude) {
25179    if (!$transclude) {
25180      throw minErr('ngTransclude')('orphan',
25181       'Illegal use of ngTransclude directive in the template! ' +
25182       'No parent directive that requires a transclusion found. ' +
25183       'Element: {0}',
25184       startingTag($element));
25185    }
25186
25187    $transclude(function(clone) {
25188      $element.empty();
25189      $element.append(clone);
25190    });
25191  }
25192});
25193
25194/**
25195 * @ngdoc directive
25196 * @name script
25197 * @restrict E
25198 *
25199 * @description
25200 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
25201 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
25202 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
25203 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
25204 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
25205 *
25206 * @param {string} type Must be set to `'text/ng-template'`.
25207 * @param {string} id Cache name of the template.
25208 *
25209 * @example
25210  <example>
25211    <file name="index.html">
25212      <script type="text/ng-template" id="/tpl.html">
25213        Content of the template.
25214      </script>
25215
25216      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
25217      <div id="tpl-content" ng-include src="currentTpl"></div>
25218    </file>
25219    <file name="protractor.js" type="protractor">
25220      it('should load template defined inside script tag', function() {
25221        element(by.css('#tpl-link')).click();
25222        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
25223      });
25224    </file>
25225  </example>
25226 */
25227var scriptDirective = ['$templateCache', function($templateCache) {
25228  return {
25229    restrict: 'E',
25230    terminal: true,
25231    compile: function(element, attr) {
25232      if (attr.type == 'text/ng-template') {
25233        var templateUrl = attr.id,
25234            text = element[0].text;
25235
25236        $templateCache.put(templateUrl, text);
25237      }
25238    }
25239  };
25240}];
25241
25242var ngOptionsMinErr = minErr('ngOptions');
25243/**
25244 * @ngdoc directive
25245 * @name select
25246 * @restrict E
25247 *
25248 * @description
25249 * HTML `SELECT` element with angular data-binding.
25250 *
25251 * # `ngOptions`
25252 *
25253 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
25254 * elements for the `<select>` element using the array or object obtained by evaluating the
25255 * `ngOptions` comprehension expression.
25256 *
25257 * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
25258 * similar result. However, `ngOptions` provides some benefits such as reducing memory and
25259 * increasing speed by not creating a new scope for each repeated instance, as well as providing
25260 * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
25261 * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
25262 *  to a non-string value. This is because an option element can only be bound to string values at
25263 * present.
25264 *
25265 * When an item in the `<select>` menu is selected, the array element or object property
25266 * represented by the selected option will be bound to the model identified by the `ngModel`
25267 * directive.
25268 *
25269 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
25270 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
25271 * option. See example below for demonstration.
25272 *
25273 * <div class="alert alert-warning">
25274 * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
25275 * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
25276 * </div>
25277 *
25278 * ## `select` **`as`**
25279 *
25280 * Using `select` **`as`** will bind the result of the `select` expression to the model, but
25281 * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
25282 * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
25283 * is used, the result of that expression will be set as the value of the `option` and `select` elements.
25284 *
25285 *
25286 * ### `select` **`as`** and **`track by`**
25287 *
25288 * <div class="alert alert-warning">
25289 * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
25290 * </div>
25291 *
25292 * Consider the following example:
25293 *
25294 * ```html
25295 * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
25296 * ```
25297 *
25298 * ```js
25299 * $scope.values = [{
25300 *   id: 1,
25301 *   label: 'aLabel',
25302 *   subItem: { name: 'aSubItem' }
25303 * }, {
25304 *   id: 2,
25305 *   label: 'bLabel',
25306 *   subItem: { name: 'bSubItem' }
25307 * }];
25308 *
25309 * $scope.selected = { name: 'aSubItem' };
25310 * ```
25311 *
25312 * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
25313 * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
25314 * following:
25315 *
25316 * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
25317 * 2. Apply **`track by`** to the already selected value in `ngModel`.
25318 *    In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
25319 *    value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
25320 *    a wrong object, the selected element can't be found, `<select>` is always reset to the "not
25321 *    selected" option.
25322 *
25323 *
25324 * @param {string} ngModel Assignable angular expression to data-bind to.
25325 * @param {string=} name Property name of the form under which the control is published.
25326 * @param {string=} required The control is considered valid only if value is entered.
25327 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25328 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25329 *    `required` when you want to data-bind to the `required` attribute.
25330 * @param {comprehension_expression=} ngOptions in one of the following forms:
25331 *
25332 *   * for array data sources:
25333 *     * `label` **`for`** `value` **`in`** `array`
25334 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
25335 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25336 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25337 *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
25338 *        (for including a filter with `track by`)
25339 *   * for object data sources:
25340 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25341 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25342 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
25343 *     * `select` **`as`** `label` **`group by`** `group`
25344 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
25345 *
25346 * Where:
25347 *
25348 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
25349 *   * `value`: local variable which will refer to each item in the `array` or each property value
25350 *      of `object` during iteration.
25351 *   * `key`: local variable which will refer to a property name in `object` during iteration.
25352 *   * `label`: The result of this expression will be the label for `<option>` element. The
25353 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
25354 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
25355 *      element. If not specified, `select` expression will default to `value`.
25356 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
25357 *      DOM element.
25358 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
25359 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
25360 *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
25361 *      even when the options are recreated (e.g. reloaded from the server).
25362 *
25363 * @example
25364    <example module="selectExample">
25365      <file name="index.html">
25366        <script>
25367        angular.module('selectExample', [])
25368          .controller('ExampleController', ['$scope', function($scope) {
25369            $scope.colors = [
25370              {name:'black', shade:'dark'},
25371              {name:'white', shade:'light'},
25372              {name:'red', shade:'dark'},
25373              {name:'blue', shade:'dark'},
25374              {name:'yellow', shade:'light'}
25375            ];
25376            $scope.myColor = $scope.colors[2]; // red
25377          }]);
25378        </script>
25379        <div ng-controller="ExampleController">
25380          <ul>
25381            <li ng-repeat="color in colors">
25382              Name: <input ng-model="color.name">
25383              [<a href ng-click="colors.splice($index, 1)">X</a>]
25384            </li>
25385            <li>
25386              [<a href ng-click="colors.push({})">add</a>]
25387            </li>
25388          </ul>
25389          <hr/>
25390          Color (null not allowed):
25391          <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
25392
25393          Color (null allowed):
25394          <span  class="nullable">
25395            <select ng-model="myColor" ng-options="color.name for color in colors">
25396              <option value="">-- choose color --</option>
25397            </select>
25398          </span><br/>
25399
25400          Color grouped by shade:
25401          <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
25402          </select><br/>
25403
25404
25405          Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
25406          <hr/>
25407          Currently selected: {{ {selected_color:myColor} }}
25408          <div style="border:solid 1px black; height:20px"
25409               ng-style="{'background-color':myColor.name}">
25410          </div>
25411        </div>
25412      </file>
25413      <file name="protractor.js" type="protractor">
25414         it('should check ng-options', function() {
25415           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
25416           element.all(by.model('myColor')).first().click();
25417           element.all(by.css('select[ng-model="myColor"] option')).first().click();
25418           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
25419           element(by.css('.nullable select[ng-model="myColor"]')).click();
25420           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
25421           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
25422         });
25423      </file>
25424    </example>
25425 */
25426
25427var ngOptionsDirective = valueFn({
25428  restrict: 'A',
25429  terminal: true
25430});
25431
25432// jshint maxlen: false
25433var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
25434                         //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
25435  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]+?))?$/,
25436      nullModelCtrl = {$setViewValue: noop};
25437// jshint maxlen: 100
25438
25439  return {
25440    restrict: 'E',
25441    require: ['select', '?ngModel'],
25442    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
25443      var self = this,
25444          optionsMap = {},
25445          ngModelCtrl = nullModelCtrl,
25446          nullOption,
25447          unknownOption;
25448
25449
25450      self.databound = $attrs.ngModel;
25451
25452
25453      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
25454        ngModelCtrl = ngModelCtrl_;
25455        nullOption = nullOption_;
25456        unknownOption = unknownOption_;
25457      };
25458
25459
25460      self.addOption = function(value, element) {
25461        assertNotHasOwnProperty(value, '"option value"');
25462        optionsMap[value] = true;
25463
25464        if (ngModelCtrl.$viewValue == value) {
25465          $element.val(value);
25466          if (unknownOption.parent()) unknownOption.remove();
25467        }
25468        // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
25469        // Adding an <option selected="selected"> element to a <select required="required"> should
25470        // automatically select the new element
25471        if (element && element[0].hasAttribute('selected')) {
25472          element[0].selected = true;
25473        }
25474      };
25475
25476
25477      self.removeOption = function(value) {
25478        if (this.hasOption(value)) {
25479          delete optionsMap[value];
25480          if (ngModelCtrl.$viewValue === value) {
25481            this.renderUnknownOption(value);
25482          }
25483        }
25484      };
25485
25486
25487      self.renderUnknownOption = function(val) {
25488        var unknownVal = '? ' + hashKey(val) + ' ?';
25489        unknownOption.val(unknownVal);
25490        $element.prepend(unknownOption);
25491        $element.val(unknownVal);
25492        unknownOption.prop('selected', true); // needed for IE
25493      };
25494
25495
25496      self.hasOption = function(value) {
25497        return optionsMap.hasOwnProperty(value);
25498      };
25499
25500      $scope.$on('$destroy', function() {
25501        // disable unknown option so that we don't do work when the whole select is being destroyed
25502        self.renderUnknownOption = noop;
25503      });
25504    }],
25505
25506    link: function(scope, element, attr, ctrls) {
25507      // if ngModel is not defined, we don't need to do anything
25508      if (!ctrls[1]) return;
25509
25510      var selectCtrl = ctrls[0],
25511          ngModelCtrl = ctrls[1],
25512          multiple = attr.multiple,
25513          optionsExp = attr.ngOptions,
25514          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
25515          emptyOption,
25516          renderScheduled = false,
25517          // we can't just jqLite('<option>') since jqLite is not smart enough
25518          // to create it in <select> and IE barfs otherwise.
25519          optionTemplate = jqLite(document.createElement('option')),
25520          optGroupTemplate =jqLite(document.createElement('optgroup')),
25521          unknownOption = optionTemplate.clone();
25522
25523      // find "null" option
25524      for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
25525        if (children[i].value === '') {
25526          emptyOption = nullOption = children.eq(i);
25527          break;
25528        }
25529      }
25530
25531      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
25532
25533      // required validator
25534      if (multiple) {
25535        ngModelCtrl.$isEmpty = function(value) {
25536          return !value || value.length === 0;
25537        };
25538      }
25539
25540      if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
25541      else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
25542      else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
25543
25544
25545      ////////////////////////////
25546
25547
25548
25549      function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
25550        ngModelCtrl.$render = function() {
25551          var viewValue = ngModelCtrl.$viewValue;
25552
25553          if (selectCtrl.hasOption(viewValue)) {
25554            if (unknownOption.parent()) unknownOption.remove();
25555            selectElement.val(viewValue);
25556            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
25557          } else {
25558            if (isUndefined(viewValue) && emptyOption) {
25559              selectElement.val('');
25560            } else {
25561              selectCtrl.renderUnknownOption(viewValue);
25562            }
25563          }
25564        };
25565
25566        selectElement.on('change', function() {
25567          scope.$apply(function() {
25568            if (unknownOption.parent()) unknownOption.remove();
25569            ngModelCtrl.$setViewValue(selectElement.val());
25570          });
25571        });
25572      }
25573
25574      function setupAsMultiple(scope, selectElement, ctrl) {
25575        var lastView;
25576        ctrl.$render = function() {
25577          var items = new HashMap(ctrl.$viewValue);
25578          forEach(selectElement.find('option'), function(option) {
25579            option.selected = isDefined(items.get(option.value));
25580          });
25581        };
25582
25583        // we have to do it on each watch since ngModel watches reference, but
25584        // we need to work of an array, so we need to see if anything was inserted/removed
25585        scope.$watch(function selectMultipleWatch() {
25586          if (!equals(lastView, ctrl.$viewValue)) {
25587            lastView = shallowCopy(ctrl.$viewValue);
25588            ctrl.$render();
25589          }
25590        });
25591
25592        selectElement.on('change', function() {
25593          scope.$apply(function() {
25594            var array = [];
25595            forEach(selectElement.find('option'), function(option) {
25596              if (option.selected) {
25597                array.push(option.value);
25598              }
25599            });
25600            ctrl.$setViewValue(array);
25601          });
25602        });
25603      }
25604
25605      function setupAsOptions(scope, selectElement, ctrl) {
25606        var match;
25607
25608        if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
25609          throw ngOptionsMinErr('iexp',
25610            "Expected expression in form of " +
25611            "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
25612            " but got '{0}'. Element: {1}",
25613            optionsExp, startingTag(selectElement));
25614        }
25615
25616        var displayFn = $parse(match[2] || match[1]),
25617            valueName = match[4] || match[6],
25618            selectAs = / as /.test(match[0]) && match[1],
25619            selectAsFn = selectAs ? $parse(selectAs) : null,
25620            keyName = match[5],
25621            groupByFn = $parse(match[3] || ''),
25622            valueFn = $parse(match[2] ? match[1] : valueName),
25623            valuesFn = $parse(match[7]),
25624            track = match[8],
25625            trackFn = track ? $parse(match[8]) : null,
25626            trackKeysCache = {},
25627            // This is an array of array of existing option groups in DOM.
25628            // We try to reuse these if possible
25629            // - optionGroupsCache[0] is the options with no option group
25630            // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
25631            optionGroupsCache = [[{element: selectElement, label:''}]],
25632            //re-usable object to represent option's locals
25633            locals = {};
25634
25635        if (nullOption) {
25636          // compile the element since there might be bindings in it
25637          $compile(nullOption)(scope);
25638
25639          // remove the class, which is added automatically because we recompile the element and it
25640          // becomes the compilation root
25641          nullOption.removeClass('ng-scope');
25642
25643          // we need to remove it before calling selectElement.empty() because otherwise IE will
25644          // remove the label from the element. wtf?
25645          nullOption.remove();
25646        }
25647
25648        // clear contents, we'll add what's needed based on the model
25649        selectElement.empty();
25650
25651        selectElement.on('change', selectionChanged);
25652
25653        ctrl.$render = render;
25654
25655        scope.$watchCollection(valuesFn, scheduleRendering);
25656        scope.$watchCollection(getLabels, scheduleRendering);
25657
25658        if (multiple) {
25659          scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
25660        }
25661
25662        // ------------------------------------------------------------------ //
25663
25664        function callExpression(exprFn, key, value) {
25665          locals[valueName] = value;
25666          if (keyName) locals[keyName] = key;
25667          return exprFn(scope, locals);
25668        }
25669
25670        function selectionChanged() {
25671          scope.$apply(function() {
25672            var collection = valuesFn(scope) || [];
25673            var viewValue;
25674            if (multiple) {
25675              viewValue = [];
25676              forEach(selectElement.val(), function(selectedKey) {
25677                  selectedKey = trackFn ? trackKeysCache[selectedKey] : selectedKey;
25678                viewValue.push(getViewValue(selectedKey, collection[selectedKey]));
25679              });
25680            } else {
25681              var selectedKey = trackFn ? trackKeysCache[selectElement.val()] : selectElement.val();
25682              viewValue = getViewValue(selectedKey, collection[selectedKey]);
25683            }
25684            ctrl.$setViewValue(viewValue);
25685            render();
25686          });
25687        }
25688
25689        function getViewValue(key, value) {
25690          if (key === '?') {
25691            return undefined;
25692          } else if (key === '') {
25693            return null;
25694          } else {
25695            var viewValueFn = selectAsFn ? selectAsFn : valueFn;
25696            return callExpression(viewValueFn, key, value);
25697          }
25698        }
25699
25700        function getLabels() {
25701          var values = valuesFn(scope);
25702          var toDisplay;
25703          if (values && isArray(values)) {
25704            toDisplay = new Array(values.length);
25705            for (var i = 0, ii = values.length; i < ii; i++) {
25706              toDisplay[i] = callExpression(displayFn, i, values[i]);
25707            }
25708            return toDisplay;
25709          } else if (values) {
25710            // TODO: Add a test for this case
25711            toDisplay = {};
25712            for (var prop in values) {
25713              if (values.hasOwnProperty(prop)) {
25714                toDisplay[prop] = callExpression(displayFn, prop, values[prop]);
25715              }
25716            }
25717          }
25718          return toDisplay;
25719        }
25720
25721        function createIsSelectedFn(viewValue) {
25722          var selectedSet;
25723          if (multiple) {
25724            if (trackFn && isArray(viewValue)) {
25725
25726              selectedSet = new HashMap([]);
25727              for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
25728                // tracking by key
25729                selectedSet.put(callExpression(trackFn, null, viewValue[trackIndex]), true);
25730              }
25731            } else {
25732              selectedSet = new HashMap(viewValue);
25733            }
25734          } else if (trackFn) {
25735            viewValue = callExpression(trackFn, null, viewValue);
25736          }
25737
25738          return function isSelected(key, value) {
25739            var compareValueFn;
25740            if (trackFn) {
25741              compareValueFn = trackFn;
25742            } else if (selectAsFn) {
25743              compareValueFn = selectAsFn;
25744            } else {
25745              compareValueFn = valueFn;
25746            }
25747
25748            if (multiple) {
25749              return isDefined(selectedSet.remove(callExpression(compareValueFn, key, value)));
25750            } else {
25751              return viewValue === callExpression(compareValueFn, key, value);
25752            }
25753          };
25754        }
25755
25756        function scheduleRendering() {
25757          if (!renderScheduled) {
25758            scope.$$postDigest(render);
25759            renderScheduled = true;
25760          }
25761        }
25762
25763        /**
25764         * A new labelMap is created with each render.
25765         * This function is called for each existing option with added=false,
25766         * and each new option with added=true.
25767         * - Labels that are passed to this method twice,
25768         * (once with added=true and once with added=false) will end up with a value of 0, and
25769         * will cause no change to happen to the corresponding option.
25770         * - Labels that are passed to this method only once with added=false will end up with a
25771         * value of -1 and will eventually be passed to selectCtrl.removeOption()
25772         * - Labels that are passed to this method only once with added=true will end up with a
25773         * value of 1 and will eventually be passed to selectCtrl.addOption()
25774        */
25775        function updateLabelMap(labelMap, label, added) {
25776          labelMap[label] = labelMap[label] || 0;
25777          labelMap[label] += (added ? 1 : -1);
25778        }
25779
25780        function render() {
25781          renderScheduled = false;
25782
25783          // Temporary location for the option groups before we render them
25784          var optionGroups = {'':[]},
25785              optionGroupNames = [''],
25786              optionGroupName,
25787              optionGroup,
25788              option,
25789              existingParent, existingOptions, existingOption,
25790              viewValue = ctrl.$viewValue,
25791              values = valuesFn(scope) || [],
25792              keys = keyName ? sortedKeys(values) : values,
25793              key,
25794              value,
25795              groupLength, length,
25796              groupIndex, index,
25797              labelMap = {},
25798              selected,
25799              isSelected = createIsSelectedFn(viewValue),
25800              anySelected = false,
25801              lastElement,
25802              element,
25803              label,
25804              optionId;
25805
25806          trackKeysCache = {};
25807
25808          // We now build up the list of options we need (we merge later)
25809          for (index = 0; length = keys.length, index < length; index++) {
25810            key = index;
25811            if (keyName) {
25812              key = keys[index];
25813              if (key.charAt(0) === '$') continue;
25814            }
25815            value = values[key];
25816
25817            optionGroupName = callExpression(groupByFn, key, value) || '';
25818            if (!(optionGroup = optionGroups[optionGroupName])) {
25819              optionGroup = optionGroups[optionGroupName] = [];
25820              optionGroupNames.push(optionGroupName);
25821            }
25822
25823            selected = isSelected(key, value);
25824            anySelected = anySelected || selected;
25825
25826            label = callExpression(displayFn, key, value); // what will be seen by the user
25827
25828            // doing displayFn(scope, locals) || '' overwrites zero values
25829            label = isDefined(label) ? label : '';
25830            optionId = trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index);
25831            if (trackFn) {
25832              trackKeysCache[optionId] = key;
25833            }
25834
25835            optionGroup.push({
25836              // either the index into array or key from object
25837              id: optionId,
25838              label: label,
25839              selected: selected                   // determine if we should be selected
25840            });
25841          }
25842          if (!multiple) {
25843            if (nullOption || viewValue === null) {
25844              // insert null option if we have a placeholder, or the model is null
25845              optionGroups[''].unshift({id:'', label:'', selected:!anySelected});
25846            } else if (!anySelected) {
25847              // option could not be found, we have to insert the undefined item
25848              optionGroups[''].unshift({id:'?', label:'', selected:true});
25849            }
25850          }
25851
25852          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
25853          for (groupIndex = 0, groupLength = optionGroupNames.length;
25854               groupIndex < groupLength;
25855               groupIndex++) {
25856            // current option group name or '' if no group
25857            optionGroupName = optionGroupNames[groupIndex];
25858
25859            // list of options for that group. (first item has the parent)
25860            optionGroup = optionGroups[optionGroupName];
25861
25862            if (optionGroupsCache.length <= groupIndex) {
25863              // we need to grow the optionGroups
25864              existingParent = {
25865                element: optGroupTemplate.clone().attr('label', optionGroupName),
25866                label: optionGroup.label
25867              };
25868              existingOptions = [existingParent];
25869              optionGroupsCache.push(existingOptions);
25870              selectElement.append(existingParent.element);
25871            } else {
25872              existingOptions = optionGroupsCache[groupIndex];
25873              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
25874
25875              // update the OPTGROUP label if not the same.
25876              if (existingParent.label != optionGroupName) {
25877                existingParent.element.attr('label', existingParent.label = optionGroupName);
25878              }
25879            }
25880
25881            lastElement = null;  // start at the beginning
25882            for (index = 0, length = optionGroup.length; index < length; index++) {
25883              option = optionGroup[index];
25884              if ((existingOption = existingOptions[index + 1])) {
25885                // reuse elements
25886                lastElement = existingOption.element;
25887                if (existingOption.label !== option.label) {
25888                  updateLabelMap(labelMap, existingOption.label, false);
25889                  updateLabelMap(labelMap, option.label, true);
25890                  lastElement.text(existingOption.label = option.label);
25891                  lastElement.prop('label', existingOption.label);
25892                }
25893                if (existingOption.id !== option.id) {
25894                  lastElement.val(existingOption.id = option.id);
25895                }
25896                // lastElement.prop('selected') provided by jQuery has side-effects
25897                if (lastElement[0].selected !== option.selected) {
25898                  lastElement.prop('selected', (existingOption.selected = option.selected));
25899                  if (msie) {
25900                    // See #7692
25901                    // The selected item wouldn't visually update on IE without this.
25902                    // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
25903                    lastElement.prop('selected', existingOption.selected);
25904                  }
25905                }
25906              } else {
25907                // grow elements
25908
25909                // if it's a null option
25910                if (option.id === '' && nullOption) {
25911                  // put back the pre-compiled element
25912                  element = nullOption;
25913                } else {
25914                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
25915                  // in this version of jQuery on some browser the .text() returns a string
25916                  // rather then the element.
25917                  (element = optionTemplate.clone())
25918                      .val(option.id)
25919                      .prop('selected', option.selected)
25920                      .attr('selected', option.selected)
25921                      .prop('label', option.label)
25922                      .text(option.label);
25923                }
25924
25925                existingOptions.push(existingOption = {
25926                    element: element,
25927                    label: option.label,
25928                    id: option.id,
25929                    selected: option.selected
25930                });
25931                updateLabelMap(labelMap, option.label, true);
25932                if (lastElement) {
25933                  lastElement.after(element);
25934                } else {
25935                  existingParent.element.append(element);
25936                }
25937                lastElement = element;
25938              }
25939            }
25940            // remove any excessive OPTIONs in a group
25941            index++; // increment since the existingOptions[0] is parent element not OPTION
25942            while (existingOptions.length > index) {
25943              option = existingOptions.pop();
25944              updateLabelMap(labelMap, option.label, false);
25945              option.element.remove();
25946            }
25947          }
25948          // remove any excessive OPTGROUPs from select
25949          while (optionGroupsCache.length > groupIndex) {
25950            // remove all the labels in the option group
25951            optionGroup = optionGroupsCache.pop();
25952            for (index = 1; index < optionGroup.length; ++index) {
25953              updateLabelMap(labelMap, optionGroup[index].label, false);
25954            }
25955            optionGroup[0].element.remove();
25956          }
25957          forEach(labelMap, function(count, label) {
25958            if (count > 0) {
25959              selectCtrl.addOption(label);
25960            } else if (count < 0) {
25961              selectCtrl.removeOption(label);
25962            }
25963          });
25964        }
25965      }
25966    }
25967  };
25968}];
25969
25970var optionDirective = ['$interpolate', function($interpolate) {
25971  var nullSelectCtrl = {
25972    addOption: noop,
25973    removeOption: noop
25974  };
25975
25976  return {
25977    restrict: 'E',
25978    priority: 100,
25979    compile: function(element, attr) {
25980      if (isUndefined(attr.value)) {
25981        var interpolateFn = $interpolate(element.text(), true);
25982        if (!interpolateFn) {
25983          attr.$set('value', element.text());
25984        }
25985      }
25986
25987      return function(scope, element, attr) {
25988        var selectCtrlName = '$selectController',
25989            parent = element.parent(),
25990            selectCtrl = parent.data(selectCtrlName) ||
25991              parent.parent().data(selectCtrlName); // in case we are in optgroup
25992
25993        if (!selectCtrl || !selectCtrl.databound) {
25994          selectCtrl = nullSelectCtrl;
25995        }
25996
25997        if (interpolateFn) {
25998          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
25999            attr.$set('value', newVal);
26000            if (oldVal !== newVal) {
26001              selectCtrl.removeOption(oldVal);
26002            }
26003            selectCtrl.addOption(newVal, element);
26004          });
26005        } else {
26006          selectCtrl.addOption(attr.value, element);
26007        }
26008
26009        element.on('$destroy', function() {
26010          selectCtrl.removeOption(attr.value);
26011        });
26012      };
26013    }
26014  };
26015}];
26016
26017var styleDirective = valueFn({
26018  restrict: 'E',
26019  terminal: false
26020});
26021
26022var requiredDirective = function() {
26023  return {
26024    restrict: 'A',
26025    require: '?ngModel',
26026    link: function(scope, elm, attr, ctrl) {
26027      if (!ctrl) return;
26028      attr.required = true; // force truthy in case we are on non input element
26029
26030      ctrl.$validators.required = function(modelValue, viewValue) {
26031        return !attr.required || !ctrl.$isEmpty(viewValue);
26032      };
26033
26034      attr.$observe('required', function() {
26035        ctrl.$validate();
26036      });
26037    }
26038  };
26039};
26040
26041
26042var patternDirective = function() {
26043  return {
26044    restrict: 'A',
26045    require: '?ngModel',
26046    link: function(scope, elm, attr, ctrl) {
26047      if (!ctrl) return;
26048
26049      var regexp, patternExp = attr.ngPattern || attr.pattern;
26050      attr.$observe('pattern', function(regex) {
26051        if (isString(regex) && regex.length > 0) {
26052          regex = new RegExp('^' + regex + '$');
26053        }
26054
26055        if (regex && !regex.test) {
26056          throw minErr('ngPattern')('noregexp',
26057            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
26058            regex, startingTag(elm));
26059        }
26060
26061        regexp = regex || undefined;
26062        ctrl.$validate();
26063      });
26064
26065      ctrl.$validators.pattern = function(value) {
26066        return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
26067      };
26068    }
26069  };
26070};
26071
26072
26073var maxlengthDirective = function() {
26074  return {
26075    restrict: 'A',
26076    require: '?ngModel',
26077    link: function(scope, elm, attr, ctrl) {
26078      if (!ctrl) return;
26079
26080      var maxlength = -1;
26081      attr.$observe('maxlength', function(value) {
26082        var intVal = int(value);
26083        maxlength = isNaN(intVal) ? -1 : intVal;
26084        ctrl.$validate();
26085      });
26086      ctrl.$validators.maxlength = function(modelValue, viewValue) {
26087        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
26088      };
26089    }
26090  };
26091};
26092
26093var minlengthDirective = function() {
26094  return {
26095    restrict: 'A',
26096    require: '?ngModel',
26097    link: function(scope, elm, attr, ctrl) {
26098      if (!ctrl) return;
26099
26100      var minlength = 0;
26101      attr.$observe('minlength', function(value) {
26102        minlength = int(value) || 0;
26103        ctrl.$validate();
26104      });
26105      ctrl.$validators.minlength = function(modelValue, viewValue) {
26106        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
26107      };
26108    }
26109  };
26110};
26111
26112  if (window.angular.bootstrap) {
26113    //AngularJS is already loaded, so we can return here...
26114    console.log('WARNING: Tried to load angular more than once.');
26115    return;
26116  }
26117
26118  //try to bind to jquery now so that one can write jqLite(document).ready()
26119  //but we will rebind on bootstrap again.
26120  bindJQuery();
26121
26122  publishExternalAPI(angular);
26123
26124  jqLite(document).ready(function() {
26125    angularInit(document, bootstrap);
26126  });
26127
26128})(window, document);
26129
26130!window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>');

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