PageSourceSearch

https://esfga.pt/expsitenovo/wp-content/plugins/wp-visual-slidebox…/modules/angular/angular.js?ver=7.1.2

js esfga.pt collected 2026-10-02 09:55:20 UTC 1,032,467 bytes, 28,133 lines download raw bytes

1/**
2 * @license AngularJS v1.4.0
3 * (c) 2010-2015 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 SKIP_INDEXES = 2;
42
43    var templateArgs = arguments,
44      code = templateArgs[0],
45      message = '[' + (module ? module + ':' : '') + code + '] ',
46      template = templateArgs[1],
47      paramPrefix, i;
48
49    message += template.replace(/\{\d+\}/g, function(match) {
50      var index = +match.slice(1, -1),
51        shiftedIndex = index + SKIP_INDEXES;
52
53      if (shiftedIndex < templateArgs.length) {
54        return toDebugString(templateArgs[shiftedIndex]);
55      }
56
57      return match;
58    });
59
60    message += '\nhttp://errors.angularjs.org/1.4.0/' +
61      (module ? module + '/' : '') + code;
62
63    for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
64      message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
65        encodeURIComponent(toDebugString(templateArgs[i]));
66    }
67
68    return new ErrorConstructor(message);
69  };
70}
71
72/* We need to tell jshint what variables are being exported */
73/* global angular: true,
74  msie: true,
75  jqLite: true,
76  jQuery: true,
77  slice: true,
78  splice: true,
79  push: true,
80  toString: true,
81  ngMinErr: true,
82  angularModule: true,
83  uid: true,
84  REGEX_STRING_REGEXP: true,
85  VALIDITY_STATE_PROPERTY: true,
86
87  lowercase: true,
88  uppercase: true,
89  manualLowercase: true,
90  manualUppercase: true,
91  nodeName_: true,
92  isArrayLike: true,
93  forEach: true,
94  forEachSorted: true,
95  reverseParams: true,
96  nextUid: true,
97  setHashKey: true,
98  extend: true,
99  toInt: true,
100  inherit: true,
101  merge: true,
102  noop: true,
103  identity: true,
104  valueFn: true,
105  isUndefined: true,
106  isDefined: true,
107  isObject: true,
108  isBlankObject: true,
109  isString: true,
110  isNumber: true,
111  isDate: true,
112  isArray: true,
113  isFunction: true,
114  isRegExp: true,
115  isWindow: true,
116  isScope: true,
117  isFile: true,
118  isFormData: true,
119  isBlob: true,
120  isBoolean: true,
121  isPromiseLike: true,
122  trim: true,
123  escapeForRegexp: true,
124  isElement: true,
125  makeMap: true,
126  includes: true,
127  arrayRemove: true,
128  copy: true,
129  shallowCopy: true,
130  equals: true,
131  csp: true,
132  jq: true,
133  concat: true,
134  sliceArgs: true,
135  bind: true,
136  toJsonReplacer: true,
137  toJson: true,
138  fromJson: true,
139  convertTimezoneToLocal: true,
140  timezoneToOffset: true,
141  startingTag: true,
142  tryDecodeURIComponent: true,
143  parseKeyValue: true,
144  toKeyValue: true,
145  encodeUriSegment: true,
146  encodeUriQuery: true,
147  angularInit: true,
148  bootstrap: true,
149  getTestability: true,
150  snake_case: true,
151  bindJQuery: true,
152  assertArg: true,
153  assertArgFn: true,
154  assertNotHasOwnProperty: true,
155  getter: true,
156  getBlockNodes: true,
157  hasOwnProperty: true,
158  createMap: true,
159
160  NODE_TYPE_ELEMENT: true,
161  NODE_TYPE_ATTRIBUTE: true,
162  NODE_TYPE_TEXT: true,
163  NODE_TYPE_COMMENT: true,
164  NODE_TYPE_DOCUMENT: true,
165  NODE_TYPE_DOCUMENT_FRAGMENT: true,
166*/
167
168////////////////////////////////////
169
170/**
171 * @ngdoc module
172 * @name ng
173 * @module ng
174 * @description
175 *
176 * # ng (core module)
177 * The ng module is loaded by default when an AngularJS application is started. The module itself
178 * contains the essential components for an AngularJS application to function. The table below
179 * lists a high level breakdown of each of the services/factories, filters, directives and testing
180 * components available within this core module.
181 *
182 * <div doc-module-components="ng"></div>
183 */
184
185var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
186
187// The name of a form control's ValidityState property.
188// This is used so that it's possible for internal tests to create mock ValidityStates.
189var VALIDITY_STATE_PROPERTY = 'validity';
190
191/**
192 * @ngdoc function
193 * @name angular.lowercase
194 * @module ng
195 * @kind function
196 *
197 * @description Converts the specified string to lowercase.
198 * @param {string} string String to be converted to lowercase.
199 * @returns {string} Lowercased string.
200 */
201var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
202var hasOwnProperty = Object.prototype.hasOwnProperty;
203
204/**
205 * @ngdoc function
206 * @name angular.uppercase
207 * @module ng
208 * @kind function
209 *
210 * @description Converts the specified string to uppercase.
211 * @param {string} string String to be converted to uppercase.
212 * @returns {string} Uppercased string.
213 */
214var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
215
216
217var manualLowercase = function(s) {
218  /* jshint bitwise: false */
219  return isString(s)
220      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
221      : s;
222};
223var manualUppercase = function(s) {
224  /* jshint bitwise: false */
225  return isString(s)
226      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
227      : s;
228};
229
230
231// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
232// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
233// with correct but slower alternatives.
234if ('i' !== 'I'.toLowerCase()) {
235  lowercase = manualLowercase;
236  uppercase = manualUppercase;
237}
238
239
240var
241    msie,             // holds major version number for IE, or NaN if UA is not IE.
242    jqLite,           // delay binding since jQuery could be loaded after us.
243    jQuery,           // delay binding
244    slice             = [].slice,
245    splice            = [].splice,
246    push              = [].push,
247    toString          = Object.prototype.toString,
248    getPrototypeOf    = Object.getPrototypeOf,
249    ngMinErr          = minErr('ng'),
250
251    /** @name angular */
252    angular           = window.angular || (window.angular = {}),
253    angularModule,
254    uid               = 0;
255
256/**
257 * documentMode is an IE-only property
258 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
259 */
260msie = document.documentMode;
261
262
263/**
264 * @private
265 * @param {*} obj
266 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
267 *                   String ...)
268 */
269function isArrayLike(obj) {
270  if (obj == null || isWindow(obj)) {
271    return false;
272  }
273
274  // Support: iOS 8.2 (not reproducible in simulator)
275  // "length" in obj used to prevent JIT error (gh-11508)
276  var length = "length" in Object(obj) && obj.length;
277
278  if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
279    return true;
280  }
281
282  return isString(obj) || isArray(obj) || length === 0 ||
283         typeof length === 'number' && length > 0 && (length - 1) in obj;
284}
285
286/**
287 * @ngdoc function
288 * @name angular.forEach
289 * @module ng
290 * @kind function
291 *
292 * @description
293 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
294 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
295 * is the value of an object property or an array element, `key` is the object property key or
296 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
297 *
298 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
299 * using the `hasOwnProperty` method.
300 *
301 * Unlike ES262's
302 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
303 * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
304 * return the value provided.
305 *
306   ```js
307     var values = {name: 'misko', gender: 'male'};
308     var log = [];
309     angular.forEach(values, function(value, key) {
310       this.push(key + ': ' + value);
311     }, log);
312     expect(log).toEqual(['name: misko', 'gender: male']);
313   ```
314 *
315 * @param {Object|Array} obj Object to iterate over.
316 * @param {Function} iterator Iterator function.
317 * @param {Object=} context Object to become context (`this`) for the iterator function.
318 * @returns {Object|Array} Reference to `obj`.
319 */
320
321function forEach(obj, iterator, context) {
322  var key, length;
323  if (obj) {
324    if (isFunction(obj)) {
325      for (key in obj) {
326        // Need to check if hasOwnProperty exists,
327        // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
328        if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
329          iterator.call(context, obj[key], key, obj);
330        }
331      }
332    } else if (isArray(obj) || isArrayLike(obj)) {
333      var isPrimitive = typeof obj !== 'object';
334      for (key = 0, length = obj.length; key < length; key++) {
335        if (isPrimitive || key in obj) {
336          iterator.call(context, obj[key], key, obj);
337        }
338      }
339    }
vendor: 11,067 bytes, lines 339-804
339 else if (obj.forEach && obj.forEach !== forEach) {
340        obj.forEach(iterator, context, obj);
341    } else if (isBlankObject(obj)) {
342      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
343      for (key in obj) {
344        iterator.call(context, obj[key], key, obj);
345      }
346    } else if (typeof obj.hasOwnProperty === 'function') {
347      // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
348      for (key in obj) {
349        if (obj.hasOwnProperty(key)) {
350          iterator.call(context, obj[key], key, obj);
351        }
352      }
353    } else {
354      // Slow path for objects which do not have a method `hasOwnProperty`
355      for (key in obj) {
356        if (hasOwnProperty.call(obj, key)) {
357          iterator.call(context, obj[key], key, obj);
358        }
359      }
360    }
361  }
362  return obj;
363}
364
365function forEachSorted(obj, iterator, context) {
366  var keys = Object.keys(obj).sort();
367  for (var i = 0; i < keys.length; i++) {
368    iterator.call(context, obj[keys[i]], keys[i]);
369  }
370  return keys;
371}
372
373
374/**
375 * when using forEach the params are value, key, but it is often useful to have key, value.
376 * @param {function(string, *)} iteratorFn
377 * @returns {function(*, string)}
378 */
379function reverseParams(iteratorFn) {
380  return function(value, key) { iteratorFn(key, value); };
381}
382
383/**
384 * A consistent way of creating unique IDs in angular.
385 *
386 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
387 * we hit number precision issues in JavaScript.
388 *
389 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
390 *
391 * @returns {number} an unique alpha-numeric string
392 */
393function nextUid() {
394  return ++uid;
395}
396
397
398/**
399 * Set or clear the hashkey for an object.
400 * @param obj object
401 * @param h the hashkey (!truthy to delete the hashkey)
402 */
403function setHashKey(obj, h) {
404  if (h) {
405    obj.$$hashKey = h;
406  } else {
407    delete obj.$$hashKey;
408  }
409}
410
411
412function baseExtend(dst, objs, deep) {
413  var h = dst.$$hashKey;
414
415  for (var i = 0, ii = objs.length; i < ii; ++i) {
416    var obj = objs[i];
417    if (!isObject(obj) && !isFunction(obj)) continue;
418    var keys = Object.keys(obj);
419    for (var j = 0, jj = keys.length; j < jj; j++) {
420      var key = keys[j];
421      var src = obj[key];
422
423      if (deep && isObject(src)) {
424        if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
425        baseExtend(dst[key], [src], true);
426      } else {
427        dst[key] = src;
428      }
429    }
430  }
431
432  setHashKey(dst, h);
433  return dst;
434}
435
436/**
437 * @ngdoc function
438 * @name angular.extend
439 * @module ng
440 * @kind function
441 *
442 * @description
443 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
444 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
445 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
446 *
447 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
448 * {@link angular.merge} for this.
449 *
450 * @param {Object} dst Destination object.
451 * @param {...Object} src Source object(s).
452 * @returns {Object} Reference to `dst`.
453 */
454function extend(dst) {
455  return baseExtend(dst, slice.call(arguments, 1), false);
456}
457
458
459/**
460* @ngdoc function
461* @name angular.merge
462* @module ng
463* @kind function
464*
465* @description
466* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
467* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
468* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
469*
470* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
471* objects, performing a deep copy.
472*
473* @param {Object} dst Destination object.
474* @param {...Object} src Source object(s).
475* @returns {Object} Reference to `dst`.
476*/
477function merge(dst) {
478  return baseExtend(dst, slice.call(arguments, 1), true);
479}
480
481
482
483function toInt(str) {
484  return parseInt(str, 10);
485}
486
487
488function inherit(parent, extra) {
489  return extend(Object.create(parent), extra);
490}
491
492/**
493 * @ngdoc function
494 * @name angular.noop
495 * @module ng
496 * @kind function
497 *
498 * @description
499 * A function that performs no operations. This function can be useful when writing code in the
500 * functional style.
501   ```js
502     function foo(callback) {
503       var result = calculateResult();
504       (callback || angular.noop)(result);
505     }
506   ```
507 */
508function noop() {}
509noop.$inject = [];
510
511
512/**
513 * @ngdoc function
514 * @name angular.identity
515 * @module ng
516 * @kind function
517 *
518 * @description
519 * A function that returns its first argument. This function is useful when writing code in the
520 * functional style.
521 *
522   ```js
523     function transformer(transformationFn, value) {
524       return (transformationFn || angular.identity)(value);
525     };
526   ```
527  * @param {*} value to be returned.
528  * @returns {*} the value passed in.
529 */
530function identity($) {return $;}
531identity.$inject = [];
532
533
534function valueFn(value) {return function() {return value;};}
535
536/**
537 * @ngdoc function
538 * @name angular.isUndefined
539 * @module ng
540 * @kind function
541 *
542 * @description
543 * Determines if a reference is undefined.
544 *
545 * @param {*} value Reference to check.
546 * @returns {boolean} True if `value` is undefined.
547 */
548function isUndefined(value) {return typeof value === 'undefined';}
549
550
551/**
552 * @ngdoc function
553 * @name angular.isDefined
554 * @module ng
555 * @kind function
556 *
557 * @description
558 * Determines if a reference is defined.
559 *
560 * @param {*} value Reference to check.
561 * @returns {boolean} True if `value` is defined.
562 */
563function isDefined(value) {return typeof value !== 'undefined';}
564
565
566/**
567 * @ngdoc function
568 * @name angular.isObject
569 * @module ng
570 * @kind function
571 *
572 * @description
573 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
574 * considered to be objects. Note that JavaScript arrays are objects.
575 *
576 * @param {*} value Reference to check.
577 * @returns {boolean} True if `value` is an `Object` but not `null`.
578 */
579function isObject(value) {
580  // http://jsperf.com/isobject4
581  return value !== null && typeof value === 'object';
582}
583
584
585/**
586 * Determine if a value is an object with a null prototype
587 *
588 * @returns {boolean} True if `value` is an `Object` with a null prototype
589 */
590function isBlankObject(value) {
591  return value !== null && typeof value === 'object' && !getPrototypeOf(value);
592}
593
594
595/**
596 * @ngdoc function
597 * @name angular.isString
598 * @module ng
599 * @kind function
600 *
601 * @description
602 * Determines if a reference is a `String`.
603 *
604 * @param {*} value Reference to check.
605 * @returns {boolean} True if `value` is a `String`.
606 */
607function isString(value) {return typeof value === 'string';}
608
609
610/**
611 * @ngdoc function
612 * @name angular.isNumber
613 * @module ng
614 * @kind function
615 *
616 * @description
617 * Determines if a reference is a `Number`.
618 *
619 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
620 *
621 * If you wish to exclude these then you can use the native
622 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
623 * method.
624 *
625 * @param {*} value Reference to check.
626 * @returns {boolean} True if `value` is a `Number`.
627 */
628function isNumber(value) {return typeof value === 'number';}
629
630
631/**
632 * @ngdoc function
633 * @name angular.isDate
634 * @module ng
635 * @kind function
636 *
637 * @description
638 * Determines if a value is a date.
639 *
640 * @param {*} value Reference to check.
641 * @returns {boolean} True if `value` is a `Date`.
642 */
643function isDate(value) {
644  return toString.call(value) === '[object Date]';
645}
646
647
648/**
649 * @ngdoc function
650 * @name angular.isArray
651 * @module ng
652 * @kind function
653 *
654 * @description
655 * Determines if a reference is an `Array`.
656 *
657 * @param {*} value Reference to check.
658 * @returns {boolean} True if `value` is an `Array`.
659 */
660var isArray = Array.isArray;
661
662/**
663 * @ngdoc function
664 * @name angular.isFunction
665 * @module ng
666 * @kind function
667 *
668 * @description
669 * Determines if a reference is a `Function`.
670 *
671 * @param {*} value Reference to check.
672 * @returns {boolean} True if `value` is a `Function`.
673 */
674function isFunction(value) {return typeof value === 'function';}
675
676
677/**
678 * Determines if a value is a regular expression object.
679 *
680 * @private
681 * @param {*} value Reference to check.
682 * @returns {boolean} True if `value` is a `RegExp`.
683 */
684function isRegExp(value) {
685  return toString.call(value) === '[object RegExp]';
686}
687
688
689/**
690 * Checks if `obj` is a window object.
691 *
692 * @private
693 * @param {*} obj Object to check
694 * @returns {boolean} True if `obj` is a window obj.
695 */
696function isWindow(obj) {
697  return obj && obj.window === obj;
698}
699
700
701function isScope(obj) {
702  return obj && obj.$evalAsync && obj.$watch;
703}
704
705
706function isFile(obj) {
707  return toString.call(obj) === '[object File]';
708}
709
710
711function isFormData(obj) {
712  return toString.call(obj) === '[object FormData]';
713}
714
715
716function isBlob(obj) {
717  return toString.call(obj) === '[object Blob]';
718}
719
720
721function isBoolean(value) {
722  return typeof value === 'boolean';
723}
724
725
726function isPromiseLike(obj) {
727  return obj && isFunction(obj.then);
728}
729
730
731var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/;
732function isTypedArray(value) {
733  return TYPED_ARRAY_REGEXP.test(toString.call(value));
734}
735
736
737var trim = function(value) {
738  return isString(value) ? value.trim() : value;
739};
740
741// Copied from:
742// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
743// Prereq: s is a string.
744var escapeForRegexp = function(s) {
745  return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
746           replace(/\x08/g, '\\x08');
747};
748
749
750/**
751 * @ngdoc function
752 * @name angular.isElement
753 * @module ng
754 * @kind function
755 *
756 * @description
757 * Determines if a reference is a DOM element (or wrapped jQuery element).
758 *
759 * @param {*} value Reference to check.
760 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
761 */
762function isElement(node) {
763  return !!(node &&
764    (node.nodeName  // we are a direct element
765    || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
766}
767
768/**
769 * @param str 'key1,key2,...'
770 * @returns {object} in the form of {key1:true, key2:true, ...}
771 */
772function makeMap(str) {
773  var obj = {}, items = str.split(","), i;
774  for (i = 0; i < items.length; i++) {
775    obj[items[i]] = true;
776  }
777  return obj;
778}
779
780
781function nodeName_(element) {
782  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
783}
784
785function includes(array, obj) {
786  return Array.prototype.indexOf.call(array, obj) != -1;
787}
788
789function arrayRemove(array, value) {
790  var index = array.indexOf(value);
791  if (index >= 0) {
792    array.splice(index, 1);
793  }
794  return index;
795}
796
797/**
798 * @ngdoc function
799 * @name angular.copy
800 * @module ng
801 * @kind function
802 *
803 * @description
804 * Creates a deep copy of `source`, which should be an object or an array.
805 *
806 * * If no destination is supplied, a copy of the object or array is created.
807 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
808 *   are deleted and then all elements/properties from the source are copied to it.
809 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
810 * * If `source` is identical to 'destination' an exception will be thrown.
811 *
812 * @param {*} source The source that will be used to make a copy.
813 *                   Can be any type, including primitives, `null`, and `undefined`.
814 * @param {(Object|Array)=} destination Destination into which the source is copied. If
815 *     provided, must be of the same type as `source`.
816 * @returns {*} The copy or updated `destination`, if `destination` was specified.
817 *
818 * @example
819 <example module="copyExample">
820 <file name="index.html">
821 <div ng-controller="ExampleController">
822 <form novalidate class="simple-form">
823 Name: <input type="text" ng-model="user.name" /><br />
824 E-mail: <input type="email" ng-model="user.email" /><br />
825 Gender: <input type="radio" ng-model="user.gender" value="male" />male
826 <input type="radio" ng-model="user.gender" value="female" />female<br />
827 <button ng-click="reset()">RESET</button>
828 <button ng-click="update(user)">SAVE</button>
829 </form>
830 <pre>form = {{user | json}}</pre>
831 <pre>master = {{master | json}}</pre>
832 </div>
833
834 <script>
835  angular.module('copyExample', [])
836    .controller('ExampleController', ['$scope', function($scope) {
837      $scope.master= {};
838
839      $scope.update = function(user) {
840        // Example with 1 argument
841        $scope.master= angular.copy(user);
842      };
843
844      $scope.reset = function() {
845        // Example with 2 arguments
846        angular.copy($scope.master, $scope.user);
847      };
848
849      $scope.reset();
850    }]);
851 </script>
852 </file>
853 </example>
854 */
855function copy(source, destination, stackSource, stackDest) {
856  if (isWindow(source) || isScope(source)) {
857    throw ngMinErr('cpws',
858      "Can't copy! Making copies of Window or Scope instances is not supported.");
859  }
860  if (isTypedArray(destination)) {
861    throw ngMinErr('cpta',
862      "Can't copy! TypedArray destination cannot be mutated.");
863  }
864
865  if (!destination) {
866    destination = source;
867    if (source) {
868      if (isArray(source)) {
869        destination = copy(source, [], stackSource, stackDest);
870      } else if (isTypedArray(source)) {
871        destination = new source.constructor(source);
872      } else if (isDate(source)) {
873        destination = new Date(source.getTime());
874      } else if (isRegExp(source)) {
875        destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
876        destination.lastIndex = source.lastIndex;
877      } else if (isObject(source)) {
878        var emptyObject = Object.create(getPrototypeOf(source));
879        destination = copy(source, emptyObject, stackSource, stackDest);
880      }
881    }
882  } else {
883    if (source === destination) throw ngMinErr('cpi',
884      "Can't copy! Source and destination are identical.");
885
886    stackSource = stackSource || [];
887    stackDest = stackDest || [];
888
889    if (isObject(source)) {
890      var index = stackSource.indexOf(source);
891      if (index !== -1) return stackDest[index];
892
893      stackSource.push(source);
894      stackDest.push(destination);
895    }
896
897    var result, key;
898    if (isArray(source)) {
899      destination.length = 0;
900      for (var i = 0; i < source.length; i++) {
901        result = copy(source[i], null, stackSource, stackDest);
902        if (isObject(source[i])) {
903          stackSource.push(source[i]);
904          stackDest.push(result);
905        }
906        destination.push(result);
907      }
908    } else {
909      var h = destination.$$hashKey;
910      if (isArray(destination)) {
911        destination.length = 0;
912      } else {
913        forEach(destination, function(value, key) {
914          delete destination[key];
915        });
916      }
917      if (isBlankObject(source)) {
918        // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
919        for (key in source) {
920          putValue(key, source[key], destination, stackSource, stackDest);
921        }
922      } else if (source && typeof source.hasOwnProperty === 'function') {
923        // Slow path, which must rely on hasOwnProperty
924        for (key in source) {
925          if (source.hasOwnProperty(key)) {
926            putValue(key, source[key], destination, stackSource, stackDest);
927          }
928        }
929      } else {
930        // Slowest path --- hasOwnProperty can't be called as a method
931        for (key in source) {
932          if (hasOwnProperty.call(source, key)) {
933            putValue(key, source[key], destination, stackSource, stackDest);
934          }
935        }
936      }
937      setHashKey(destination,h);
938    }
939  }
940  return destination;
941
942  function putValue(key, val, destination, stackSource, stackDest) {
943    // No context allocation, trivial outer scope, easily inlined
944    var result = copy(val, null, stackSource, stackDest);
945    if (isObject(val)) {
946      stackSource.push(val);
947      stackDest.push(result);
948    }
949    destination[key] = result;
950  }
951}
952
953/**
954 * Creates a shallow copy of an object, an array or a primitive.
955 *
956 * Assumes that there are no proto properties for objects.
957 */
958function shallowCopy(src, dst) {
959  if (isArray(src)) {
960    dst = dst || [];
961
962    for (var i = 0, ii = src.length; i < ii; i++) {
963      dst[i] = src[i];
964    }
965  } else if (isObject(src)) {
966    dst = dst || {};
967
968    for (var key in src) {
969      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
970        dst[key] = src[key];
971      }
972    }
973  }
974
975  return dst || src;
976}
977
978
979/**
980 * @ngdoc function
981 * @name angular.equals
982 * @module ng
983 * @kind function
984 *
985 * @description
986 * Determines if two objects or two values are equivalent. Supports value types, regular
987 * expressions, arrays and objects.
988 *
989 * Two objects or values are considered equivalent if at least one of the following is true:
990 *
991 * * Both objects or values pass `===` comparison.
992 * * Both objects or values are of the same type and all of their properties are equal by
993 *   comparing them with `angular.equals`.
994 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
995 * * Both values represent the same regular expression (In JavaScript,
996 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
997 *   representation matches).
998 *
999 * During a property comparison, properties of `function` type and properties with names
1000 * that begin with `$` are ignored.
1001 *
1002 * Scope and DOMWindow objects are being compared only by identify (`===`).
1003 *
1004 * @param {*} o1 Object or value to compare.
1005 * @param {*} o2 Object or value to compare.
1006 * @returns {boolean} True if arguments are equal.
1007 */
1008function equals(o1, o2) {
1009  if (o1 === o2) return true;
1010  if (o1 === null || o2 === null) return false;
1011  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1012  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1013  if (t1 == t2) {
1014    if (t1 == 'object') {
1015      if (isArray(o1)) {
1016        if (!isArray(o2)) return false;
1017        if ((length = o1.length) == o2.length) {
1018          for (key = 0; key < length; key++) {
1019            if (!equals(o1[key], o2[key])) return false;
1020          }
1021          return true;
1022        }
1023      } else if (isDate(o1)) {
1024        if (!isDate(o2)) return false;
1025        return equals(o1.getTime(), o2.getTime());
1026      } else if (isRegExp(o1)) {
1027        return isRegExp(o2) ? o1.toString() == o2.toString() : false;
1028      } else {
1029        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1030          isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1031        keySet = createMap();
1032        for (key in o1) {
1033          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1034          if (!equals(o1[key], o2[key])) return false;
1035          keySet[key] = true;
1036        }
1037        for (key in o2) {
1038          if (!(key in keySet) &&
1039              key.charAt(0) !== '$' &&
1040              o2[key] !== undefined &&
1041              !isFunction(o2[key])) return false;
1042        }
1043        return true;
1044      }
1045    }
1046  }
1047  return false;
1048}
1049
1050var csp = function() {
1051  if (isDefined(csp.isActive_)) return csp.isActive_;
1052
1053  var active = !!(document.querySelector('[ng-csp]') ||
1054                  document.querySelector('[data-ng-csp]'));
1055
1056  if (!active) {
1057    try {
1058      /* jshint -W031, -W054 */
1059      new Function('');
1060      /* jshint +W031, +W054 */
1061    } catch (e) {
1062      active = true;
1063    }
1064  }
1065
1066  return (csp.isActive_ = active);
1067};
1068
1069/**
1070 * @ngdoc directive
1071 * @module ng
1072 * @name ngJq
1073 *
1074 * @element ANY
1075 * @param {string=} ngJq the name of the library available under `window`
1076 * to be used for angular.element
1077 * @description
1078 * Use this directive to force the angular.element library.  This should be
1079 * used to force either jqLite by leaving ng-jq blank or setting the name of
1080 * the jquery variable under window (eg. jQuery).
1081 *
1082 * Since angular looks for this directive when it is loaded (doesn't wait for the
1083 * DOMContentLoaded event), it must be placed on an element that comes before the script
1084 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1085 * others ignored.
1086 *
1087 * @example
1088 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1089 ```html
1090 <!doctype html>
1091 <html ng-app ng-jq>
1092 ...
1093 ...
1094 </html>
1095 ```
1096 * @example
1097 * This example shows how to use a jQuery based library of a different name.
1098 * The library name must be available at the top most 'window'.
1099 ```html
1100 <!doctype html>
1101 <html ng-app ng-jq="jQueryLib">
1102 ...
1103 ...
1104 </html>
1105 ```
1106 */
1107var jq = function() {
1108  if (isDefined(jq.name_)) return jq.name_;
1109  var el;
1110  var i, ii = ngAttrPrefixes.length, prefix, name;
1111  for (i = 0; i < ii; ++i) {
1112    prefix = ngAttrPrefixes[i];
1113    if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1114      name = el.getAttribute(prefix + 'jq');
1115      break;
1116    }
1117  }
1118
1119  return (jq.name_ = name);
1120};
1121
1122function concat(array1, array2, index) {
1123  return array1.concat(slice.call(array2, index));
1124}
1125
1126function sliceArgs(args, startIndex) {
1127  return slice.call(args, startIndex || 0);
1128}
1129
1130
vendor: 8,838 bytes, lines 1131-1408
1131/* jshint -W101 */
1132/**
1133 * @ngdoc function
1134 * @name angular.bind
1135 * @module ng
1136 * @kind function
1137 *
1138 * @description
1139 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1140 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1141 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1142 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1143 *
1144 * @param {Object} self Context which `fn` should be evaluated in.
1145 * @param {function()} fn Function to be bound.
1146 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1147 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1148 */
1149/* jshint +W101 */
1150function bind(self, fn) {
1151  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1152  if (isFunction(fn) && !(fn instanceof RegExp)) {
1153    return curryArgs.length
1154      ? function() {
1155          return arguments.length
1156            ? fn.apply(self, concat(curryArgs, arguments, 0))
1157            : fn.apply(self, curryArgs);
1158        }
1159      : function() {
1160          return arguments.length
1161            ? fn.apply(self, arguments)
1162            : fn.call(self);
1163        };
1164  } else {
1165    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1166    return fn;
1167  }
1168}
1169
1170
1171function toJsonReplacer(key, value) {
1172  var val = value;
1173
1174  if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1175    val = undefined;
1176  } else if (isWindow(value)) {
1177    val = '$WINDOW';
1178  } else if (value &&  document === value) {
1179    val = '$DOCUMENT';
1180  } else if (isScope(value)) {
1181    val = '$SCOPE';
1182  }
1183
1184  return val;
1185}
1186
1187
1188/**
1189 * @ngdoc function
1190 * @name angular.toJson
1191 * @module ng
1192 * @kind function
1193 *
1194 * @description
1195 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1196 * stripped since angular uses this notation internally.
1197 *
1198 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1199 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1200 *    If set to an integer, the JSON output will contain that many spaces per indentation.
1201 * @returns {string|undefined} JSON-ified string representing `obj`.
1202 */
1203function toJson(obj, pretty) {
1204  if (typeof obj === 'undefined') return undefined;
1205  if (!isNumber(pretty)) {
1206    pretty = pretty ? 2 : null;
1207  }
1208  return JSON.stringify(obj, toJsonReplacer, pretty);
1209}
1210
1211
1212/**
1213 * @ngdoc function
1214 * @name angular.fromJson
1215 * @module ng
1216 * @kind function
1217 *
1218 * @description
1219 * Deserializes a JSON string.
1220 *
1221 * @param {string} json JSON string to deserialize.
1222 * @returns {Object|Array|string|number} Deserialized JSON string.
1223 */
1224function fromJson(json) {
1225  return isString(json)
1226      ? JSON.parse(json)
1227      : json;
1228}
1229
1230
1231function timezoneToOffset(timezone, fallback) {
1232  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1233  return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1234}
1235
1236
1237function addDateMinutes(date, minutes) {
1238  date = new Date(date.getTime());
1239  date.setMinutes(date.getMinutes() + minutes);
1240  return date;
1241}
1242
1243
1244function convertTimezoneToLocal(date, timezone, reverse) {
1245  reverse = reverse ? -1 : 1;
1246  var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
1247  return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
1248}
1249
1250
1251/**
1252 * @returns {string} Returns the string representation of the element.
1253 */
1254function startingTag(element) {
1255  element = jqLite(element).clone();
1256  try {
1257    // turns out IE does not let you set .html() on elements which
1258    // are not allowed to have children. So we just ignore it.
1259    element.empty();
1260  } catch (e) {}
1261  var elemHtml = jqLite('<div>').append(element).html();
1262  try {
1263    return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1264        elemHtml.
1265          match(/^(<[^>]+>)/)[1].
1266          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
1267  } catch (e) {
1268    return lowercase(elemHtml);
1269  }
1270
1271}
1272
1273
1274/////////////////////////////////////////////////
1275
1276/**
1277 * Tries to decode the URI component without throwing an exception.
1278 *
1279 * @private
1280 * @param str value potential URI component to check.
1281 * @returns {boolean} True if `value` can be decoded
1282 * with the decodeURIComponent function.
1283 */
1284function tryDecodeURIComponent(value) {
1285  try {
1286    return decodeURIComponent(value);
1287  } catch (e) {
1288    // Ignore any invalid uri component
1289  }
1290}
1291
1292
1293/**
1294 * Parses an escaped url query string into key-value pairs.
1295 * @returns {Object.<string,boolean|Array>}
1296 */
1297function parseKeyValue(/**string*/keyValue) {
1298  var obj = {}, key_value, key;
1299  forEach((keyValue || "").split('&'), function(keyValue) {
1300    if (keyValue) {
1301      key_value = keyValue.replace(/\+/g,'%20').split('=');
1302      key = tryDecodeURIComponent(key_value[0]);
1303      if (isDefined(key)) {
1304        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1305        if (!hasOwnProperty.call(obj, key)) {
1306          obj[key] = val;
1307        } else if (isArray(obj[key])) {
1308          obj[key].push(val);
1309        } else {
1310          obj[key] = [obj[key],val];
1311        }
1312      }
1313    }
1314  });
1315  return obj;
1316}
1317
1318function toKeyValue(obj) {
1319  var parts = [];
1320  forEach(obj, function(value, key) {
1321    if (isArray(value)) {
1322      forEach(value, function(arrayValue) {
1323        parts.push(encodeUriQuery(key, true) +
1324                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1325      });
1326    } else {
1327    parts.push(encodeUriQuery(key, true) +
1328               (value === true ? '' : '=' + encodeUriQuery(value, true)));
1329    }
1330  });
1331  return parts.length ? parts.join('&') : '';
1332}
1333
1334
1335/**
1336 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1337 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1338 * segments:
1339 *    segment       = *pchar
1340 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1341 *    pct-encoded   = "%" HEXDIG HEXDIG
1342 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1343 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1344 *                     / "*" / "+" / "," / ";" / "="
1345 */
1346function encodeUriSegment(val) {
1347  return encodeUriQuery(val, true).
1348             replace(/%26/gi, '&').
1349             replace(/%3D/gi, '=').
1350             replace(/%2B/gi, '+');
1351}
1352
1353
1354/**
1355 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1356 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1357 * encoded per http://tools.ietf.org/html/rfc3986:
1358 *    query       = *( pchar / "/" / "?" )
1359 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1360 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1361 *    pct-encoded   = "%" HEXDIG HEXDIG
1362 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1363 *                     / "*" / "+" / "," / ";" / "="
1364 */
1365function encodeUriQuery(val, pctEncodeSpaces) {
1366  return encodeURIComponent(val).
1367             replace(/%40/gi, '@').
1368             replace(/%3A/gi, ':').
1369             replace(/%24/g, '$').
1370             replace(/%2C/gi, ',').
1371             replace(/%3B/gi, ';').
1372             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1373}
1374
1375var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1376
1377function getNgAttribute(element, ngAttr) {
1378  var attr, i, ii = ngAttrPrefixes.length;
1379  for (i = 0; i < ii; ++i) {
1380    attr = ngAttrPrefixes[i] + ngAttr;
1381    if (isString(attr = element.getAttribute(attr))) {
1382      return attr;
1383    }
1384  }
1385  return null;
1386}
1387
1388/**
1389 * @ngdoc directive
1390 * @name ngApp
1391 * @module ng
1392 *
1393 * @element ANY
1394 * @param {angular.Module} ngApp an optional application
1395 *   {@link angular.module module} name to load.
1396 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1397 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
1398 *   do not use explicit function annotation (and are thus unsuitable for minification), as described
1399 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1400 *   tracking down the root of these bugs.
1401 *
1402 * @description
1403 *
1404 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1405 * designates the **root element** of the application and is typically placed near the root element
1406 * of the page - e.g. on the `<body>` or `<html>` tags.
1407 *
1408 * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngAp
1408p`
1409 * found in the document will be used to define the root element to auto-bootstrap as an
1410 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1411 * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1412 *
1413 * You can specify an **AngularJS module** to be used as the root module for the application.  This
1414 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1415 * should contain the application code needed or have dependencies on other modules that will
1416 * contain the code. See {@link angular.module} for more information.
1417 *
1418 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1419 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1420 * would not be resolved to `3`.
1421 *
1422 * `ngApp` is the easiest, and most common way to bootstrap an application.
1423 *
1424 <example module="ngAppDemo">
1425   <file name="index.html">
1426   <div ng-controller="ngAppDemoController">
1427     I can add: {{a}} + {{b}} =  {{ a+b }}
1428   </div>
1429   </file>
1430   <file name="script.js">
1431   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1432     $scope.a = 1;
1433     $scope.b = 2;
1434   });
1435   </file>
1436 </example>
1437 *
1438 * Using `ngStrictDi`, you would see something like this:
1439 *
1440 <example ng-app-included="true">
1441   <file name="index.html">
1442   <div ng-app="ngAppStrictDemo" ng-strict-di>
1443       <div ng-controller="GoodController1">
1444           I can add: {{a}} + {{b}} =  {{ a+b }}
1445
1446           <p>This renders because the controller does not fail to
1447              instantiate, by using explicit annotation style (see
1448              script.js for details)
1449           </p>
1450       </div>
1451
1452       <div ng-controller="GoodController2">
1453           Name: <input ng-model="name"><br />
1454           Hello, {{name}}!
1455
1456           <p>This renders because the controller does not fail to
1457              instantiate, by using explicit annotation style
1458              (see script.js for details)
1459           </p>
1460       </div>
1461
1462       <div ng-controller="BadController">
1463           I can add: {{a}} + {{b}} =  {{ a+b }}
1464
1465           <p>The controller could not be instantiated, due to relying
1466              on automatic function annotations (which are disabled in
1467              strict mode). As such, the content of this section is not
1468              interpolated, and there should be an error in your web console.
1469           </p>
1470       </div>
1471   </div>
1472   </file>
1473   <file name="script.js">
1474   angular.module('ngAppStrictDemo', [])
1475     // BadController will fail to instantiate, due to relying on automatic function annotation,
1476     // rather than an explicit annotation
1477     .controller('BadController', function($scope) {
1478       $scope.a = 1;
1479       $scope.b = 2;
1480     })
1481     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1482     // due to using explicit annotations using the array style and $inject property, respectively.
1483     .controller('GoodController1', ['$scope', function($scope) {
1484       $scope.a = 1;
1485       $scope.b = 2;
1486     }])
1487     .controller('GoodController2', GoodController2);
1488     function GoodController2($scope) {
1489       $scope.name = "World";
1490     }
1491     GoodController2.$inject = ['$scope'];
1492   </file>
1493   <file name="style.css">
1494   div[ng-controller] {
1495       margin-bottom: 1em;
1496       -webkit-border-radius: 4px;
1497       border-radius: 4px;
1498       border: 1px solid;
1499       padding: .5em;
1500   }
1501   div[ng-controller^=Good] {
1502       border-color: #d6e9c6;
1503       background-color: #dff0d8;
1504       color: #3c763d;
1505   }
1506   div[ng-controller^=Bad] {
1507       border-color: #ebccd1;
1508       background-color: #f2dede;
1509       color: #a94442;
1510       margin-bottom: 0;
1511   }
1512   </file>
1513 </example>
1514 */
1515function angularInit(element, bootstrap) {
1516  var appElement,
1517      module,
1518      config = {};
1519
1520  // The element `element` has priority over any other element
1521  forEach(ngAttrPrefixes, function(prefix) {
1522    var name = prefix + 'app';
1523
1524    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1525      appElement = element;
1526      module = element.getAttribute(name);
1527    }
1528  });
1529  forEach(ngAttrPrefixes, function(prefix) {
1530    var name = prefix + 'app';
1531    var candidate;
1532
1533    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1534      appElement = candidate;
1535      module = candidate.getAttribute(name);
1536    }
1537  });
1538  if (appElement) {
1539    config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1540    bootstrap(appElement, module ? [module] : [], config);
1541  }
1542}
1543
1544/**
1545 * @ngdoc function
1546 * @name angular.bootstrap
1547 * @module ng
1548 * @description
1549 * Use this function to manually start up angular application.
1550 *
1551 * See: {@link guide/bootstrap Bootstrap}
1552 *
1553 * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
1554 * They must use {@link ng.directive:ngApp ngApp}.
1555 *
1556 * Angular will detect if it has been loaded into the browser more than once and only allow the
1557 * first loaded script to be bootstrapped and will report a warning to the browser console for
1558 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1559 * multiple instances of Angular try to work on the DOM.
1560 *
1561 * ```html
1562 * <!doctype html>
1563 * <html>
1564 * <body>
1565 * <div ng-controller="WelcomeController">
1566 *   {{greeting}}
1567 * </div>
1568 *
1569 * <script src="angular.js"></script>
1570 * <script>
1571 *   var app = angular.module('demo', [])
1572 *   .controller('WelcomeController', function($scope) {
1573 *       $scope.greeting = 'Welcome!';
1574 *   });
1575 *   angular.bootstrap(document, ['demo']);
1576 * </script>
1577 * </body>
1578 * </html>
1579 * ```
1580 *
1581 * @param {DOMElement} element DOM element which is the root of angular application.
1582 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1583 *     Each item in the array should be the name of a predefined module or a (DI annotated)
1584 *     function that will be invoked by the injector as a `config` block.
1585 *     See: {@link angular.module modules}
1586 * @param {Object=} config an object for defining configuration options for the application. The
1587 *     following keys are supported:
1588 *
1589 * * `strictDi` - disable automatic function annotation for the application. This is meant to
1590 *   assist in finding bugs which break minified code. Defaults to `false`.
1591 *
1592 * @returns {auto.$injector} Returns the newly created injector for this app.
1593 */
1594function bootstrap(element, modules, config) {
1595  if (!isObject(config)) config = {};
1596  var defaultConfig = {
1597    strictDi: false
1598  };
1599  config = extend(defaultConfig, config);
1600  var doBootstrap = function() {
1601    element = jqLite(element);
1602
1603    if (element.injector()) {
1604      var tag = (element[0] === document) ? 'document' : startingTag(element);
1605      //Encode angle brackets to prevent input from being sanitized to empty string #8683
1606      throw ngMinErr(
1607          'btstrpd',
1608          "App Already Bootstrapped with this Element '{0}'",
1609          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1610    }
1611
1612    modules = modules || [];
1613    modules.unshift(['$provide', function($provide) {
1614      $provide.value('$rootElement', element);
1615    }]);
1616
1617    if (config.debugInfoEnabled) {
1618      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1619      modules.push(['$compileProvider', function($compileProvider) {
1620        $compileProvider.debugInfoEnabled(true);
1621      }]);
1622    }
1623
1624    modules.unshift('ng');
1625    var injector = createInjector(modules, config.strictDi);
1626    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1627       function bootstrapApply(scope, element, compile, injector) {
1628        scope.$apply(function() {
1629          element.data('$injector', injector);
1630          compile(element)(scope);
1631        });
1632      }]
1633    );
1634    return injector;
1635  };
1636
1637  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1638  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1639
1640  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1641    config.debugInfoEnabled = true;
1642    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1643  }
1644
1645  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1646    return doBootstrap();
1647  }
1648
1649  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1650  angular.resumeBootstrap = function(extraModules) {
1651    forEach(extraModules, function(module) {
1652      modules.push(module);
1653    });
1654    return doBootstrap();
1655  };
1656
1657  if (isFunction(angular.resumeDeferredBootstrap)) {
1658    angular.resumeDeferredBootstrap();
1659  }
1660}
1661
1662/**
1663 * @ngdoc function
1664 * @name angular.reloadWithDebugInfo
1665 * @module ng
1666 * @description
1667 * Use this function to reload the current application with debug information turned on.
1668 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1669 *
1670 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1671 */
1672function reloadWithDebugInfo() {
1673  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1674  window.location.reload();
1675}
1676
1677/**
1678 * @name angular.getTestability
1679 * @module ng
1680 * @description
1681 * Get the testability service for the instance of Angular on the given
1682 * element.
1683 * @param {DOMElement} element DOM element which is the root of angular application.
1684 */
1685function getTestability(rootElement) {
1686  var injector = angular.element(rootElement).injector();
1687  if (!injector) {
1688    throw ngMinErr('test',
1689      'no injector found for element argument to getTestability');
1690  }
1691  return injector.get('$$testability');
1692}
1693
1694var SNAKE_CASE_REGEXP = /[A-Z]/g;
1695function snake_case(name, separator) {
1696  separator = separator || '_';
1697  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1698    return (pos ? separator : '') + letter.toLowerCase();
1699  });
1700}
1701
1702var bindJQueryFired = false;
1703var skipDestroyOnNextJQueryCleanData;
1704function bindJQuery() {
1705  var originalCleanData;
1706
1707  if (bindJQueryFired) {
1708    return;
1709  }
1710
1711  // bind to jQuery if present;
1712  var jqName = jq();
1713  jQuery = window.jQuery; // use default jQuery.
1714  if (isDefined(jqName)) { // `ngJq` present
1715    jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`.
1716  }
1717
1718  // Use jQuery if it exists with proper functionality, otherwise default to us.
1719  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1720  // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1721  // versions. It will not work for sure with jQuery <1.7, though.
1722  if (jQuery && jQuery.fn.on) {
1723    jqLite = jQuery;
1724    extend(jQuery.fn, {
1725      scope: JQLitePrototype.scope,
1726      isolateScope: JQLitePrototype.isolateScope,
1727      controller: JQLitePrototype.controller,
1728      injector: JQLitePrototype.injector,
1729      inheritedData: JQLitePrototype.inheritedData
1730    });
1731
1732    // All nodes removed from the DOM via various jQuery APIs like .remove()
1733    // are passed through jQuery.cleanData. Monkey-patch this method to fire
1734    // the $destroy event on all removed nodes.
1735    originalCleanData = jQuery.cleanData;
1736    jQuery.cleanData = function(elems) {
1737      var events;
1738      if (!skipDestroyOnNextJQueryCleanData) {
1739        for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1740          events = jQuery._data(elem, "events");
1741          if (events && events.$destroy) {
1742            jQuery(elem).triggerHandler('$destroy');
1743          }
1744        }
1745      } else {
1746        skipDestroyOnNextJQueryCleanData = false;
1747      }
1748      originalCleanData(elems);
1749    };
1750  } else {
1751    jqLite = JQLite;
1752  }
1753
1754  angular.element = jqLite;
1755
1756  // Prevent double-proxying.
1757  bindJQueryFired = true;
1758}
1759
1760/**
1761 * throw error if the argument is falsy.
1762 */
1763function assertArg(arg, name, reason) {
1764  if (!arg) {
1765    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1766  }
1767  return arg;
1768}
1769
1770function assertArgFn(arg, name, acceptArrayAnnotation) {
1771  if (acceptArrayAnnotation && isArray(arg)) {
1772      arg = arg[arg.length - 1];
1773  }
1774
1775  assertArg(isFunction(arg), name, 'not a function, got ' +
1776      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1777  return arg;
1778}
1779
1780/**
1781 * throw error if the name given is hasOwnProperty
1782 * @param  {String} name    the name to test
1783 * @param  {String} context the context in which the name is used, such as module or directive
1784 */
1785function assertNotHasOwnProperty(name, context) {
1786  if (name === 'hasOwnProperty') {
1787    throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1788  }
1789}
1790
1791/**
1792 * Return the value accessible from the object by path. Any undefined traversals are ignored
1793 * @param {Object} obj starting object
1794 * @param {String} path path to traverse
1795 * @param {boolean} [bindFnToScope=true]
1796 * @returns {Object} value as accessible by path
1797 */
1798//TODO(misko): this function needs to be removed
1799function getter(obj, path, bindFnToScope) {
1800  if (!path) return obj;
1801  var keys = path.split('.');
1802  var key;
1803  var lastInstance = obj;
1804  var len = keys.length;
1805
1806  for (var i = 0; i < len; i++) {
1807    key = keys[i];
1808    if (obj) {
1809      obj = (lastInstance = obj)[key];
1810    }
1811  }
1812  if (!bindFnToScope && isFunction(obj)) {
1813    return bind(lastInstance, obj);
1814  }
1815  return obj;
1816}
1817
1818/**
1819 * Return the DOM siblings between the first and last node in the given array.
1820 * @param {Array} array like object
1821 * @returns {jqLite} jqLite collection containing the nodes
1822 */
1823function getBlockNodes(nodes) {
1824  // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
1825  //             collection, otherwise update the original collection.
1826  var node = nodes[0];
1827  var endNode = nodes[nodes.length - 1];
1828  var blockNodes = [node];
1829
1830  do {
1831    node = node.nextSibling;
1832    if (!node) break;
1833    blockNodes.push(node);
1834  } while (node !== endNode);
1835
1836  return jqLite(blockNodes);
1837}
1838
1839
1840/**
1841 * Creates a new object without a prototype. This object is useful for lookup without having to
1842 * guard against prototypically inherited properties via hasOwnProperty.
1843 *
1844 * Related micro-benchmarks:
1845 * - http://jsperf.com/object-create2
1846 * - http://jsperf.com/proto-map-lookup/2
1847 * - http://jsperf.com/for-in-vs-object-keys2
1848 *
1849 * @returns {Object}
1850 */
1851function createMap() {
1852  return Object.create(null);
1853}
1854
1855var NODE_TYPE_ELEMENT = 1;
1856var NODE_TYPE_ATTRIBUTE = 2;
1857var NODE_TYPE_TEXT = 3;
1858var NODE_TYPE_COMMENT = 8;
1859var NODE_TYPE_DOCUMENT = 9;
1860var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1861
1862/**
1863 * @ngdoc type
1864 * @name angular.Module
1865 * @module ng
1866 * @description
1867 *
1868 * Interface for configuring angular {@link angular.module modules}.
1869 */
1870
1871function setupModuleLoader(window) {
1872
1873  var $injectorMinErr = minErr('$injector');
1874  var ngMinErr = minErr('ng');
1875
1876  function ensure(obj, name, factory) {
vendor: 4,138 bytes, lines 1877-1991
1877    return obj[name] || (obj[name] = factory());
1878  }
1879
1880  var angular = ensure(window, 'angular', Object);
1881
1882  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1883  angular.$$minErr = angular.$$minErr || minErr;
1884
1885  return ensure(angular, 'module', function() {
1886    /** @type {Object.<string, angular.Module>} */
1887    var modules = {};
1888
1889    /**
1890     * @ngdoc function
1891     * @name angular.module
1892     * @module ng
1893     * @description
1894     *
1895     * The `angular.module` is a global place for creating, registering and retrieving Angular
1896     * modules.
1897     * All modules (angular core or 3rd party) that should be available to an application must be
1898     * registered using this mechanism.
1899     *
1900     * When passed two or more arguments, a new module is created.  If passed only one argument, an
1901     * existing module (the name passed as the first argument to `module`) is retrieved.
1902     *
1903     *
1904     * # Module
1905     *
1906     * A module is a collection of services, directives, controllers, filters, and configuration information.
1907     * `angular.module` is used to configure the {@link auto.$injector $injector}.
1908     *
1909     * ```js
1910     * // Create a new module
1911     * var myModule = angular.module('myModule', []);
1912     *
1913     * // register a new service
1914     * myModule.value('appName', 'MyCoolApp');
1915     *
1916     * // configure existing services inside initialization blocks.
1917     * myModule.config(['$locationProvider', function($locationProvider) {
1918     *   // Configure existing providers
1919     *   $locationProvider.hashPrefix('!');
1920     * }]);
1921     * ```
1922     *
1923     * Then you can create an injector and load your modules like this:
1924     *
1925     * ```js
1926     * var injector = angular.injector(['ng', 'myModule'])
1927     * ```
1928     *
1929     * However it's more likely that you'll just use
1930     * {@link ng.directive:ngApp ngApp} or
1931     * {@link angular.bootstrap} to simplify this process for you.
1932     *
1933     * @param {!string} name The name of the module to create or retrieve.
1934     * @param {!Array.<string>=} requires If specified then new module is being created. If
1935     *        unspecified then the module is being retrieved for further configuration.
1936     * @param {Function=} configFn Optional configuration function for the module. Same as
1937     *        {@link angular.Module#config Module#config()}.
1938     * @returns {module} new module with the {@link angular.Module} api.
1939     */
1940    return function module(name, requires, configFn) {
1941      var assertNotHasOwnProperty = function(name, context) {
1942        if (name === 'hasOwnProperty') {
1943          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1944        }
1945      };
1946
1947      assertNotHasOwnProperty(name, 'module');
1948      if (requires && modules.hasOwnProperty(name)) {
1949        modules[name] = null;
1950      }
1951      return ensure(modules, name, function() {
1952        if (!requires) {
1953          throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1954             "the module name or forgot to load it. If registering a module ensure that you " +
1955             "specify the dependencies as the second argument.", name);
1956        }
1957
1958        /** @type {!Array.<Array.<*>>} */
1959        var invokeQueue = [];
1960
1961        /** @type {!Array.<Function>} */
1962        var configBlocks = [];
1963
1964        /** @type {!Array.<Function>} */
1965        var runBlocks = [];
1966
1967        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
1968
1969        /** @type {angular.Module} */
1970        var moduleInstance = {
1971          // Private state
1972          _invokeQueue: invokeQueue,
1973          _configBlocks: configBlocks,
1974          _runBlocks: runBlocks,
1975
1976          /**
1977           * @ngdoc property
1978           * @name angular.Module#requires
1979           * @module ng
1980           *
1981           * @description
1982           * Holds the list of modules which the injector will load before the current module is
1983           * loaded.
1984           */
1985          requires: requires,
1986
1987          /**
1988           * @ngdoc property
1989           * @name angular.Module#name
1990           * @module ng
1991           *
1992           * @description
1993           * Name of the module.
1994           */
1995          name: name,
1996
1997
1998          /**
1999           * @ngdoc method
2000           * @name angular.Module#provider
2001           * @module ng
2002           * @param {string} name service name
2003           * @param {Function} providerType Construction function for creating new instance of the
2004           *                                service.
2005           * @description
2006           * See {@link auto.$provide#provider $provide.provider()}.
2007           */
2008          provider: invokeLater('$provide', 'provider'),
2009
2010          /**
2011           * @ngdoc method
2012           * @name angular.Module#factory
2013           * @module ng
2014           * @param {string} name service name
2015           * @param {Function} providerFunction Function for creating new instance of the service.
2016           * @description
2017           * See {@link auto.$provide#factory $provide.factory()}.
2018           */
2019          factory: invokeLater('$provide', 'factory'),
2020
2021          /**
2022           * @ngdoc method
2023           * @name angular.Module#service
2024           * @module ng
2025           * @param {string} name service name
2026           * @param {Function} constructor A constructor function that will be instantiated.
2027           * @description
2028           * See {@link auto.$provide#service $provide.service()}.
2029           */
2030          service: invokeLater('$provide', 'service'),
2031
2032          /**
2033           * @ngdoc method
2034           * @name angular.Module#value
2035           * @module ng
2036           * @param {string} name service name
2037           * @param {*} object Service instance object.
2038           * @description
2039           * See {@link auto.$provide#value $provide.value()}.
2040           */
2041          value: invokeLater('$provide', 'value'),
2042
2043          /**
2044           * @ngdoc method
2045           * @name angular.Module#constant
2046           * @module ng
2047           * @param {string} name constant name
2048           * @param {*} object Constant value.
2049           * @description
2050           * Because the constant are fixed, they get applied before other provide methods.
2051           * See {@link auto.$provide#constant $provide.constant()}.
2052           */
2053          constant: invokeLater('$provide', 'constant', 'unshift'),
2054
2055           /**
2056           * @ngdoc method
2057           * @name angular.Module#decorator
2058           * @module ng
2059           * @param {string} The name of the service to decorate.
2060           * @param {Function} This function will be invoked when the service needs to be
2061           *                                    instantiated and should return the decorated service instance.
2062           * @description
2063           * See {@link auto.$provide#decorator $provide.decorator()}.
2064           */
2065          decorator: invokeLater('$provide', 'decorator'),
2066
2067          /**
2068           * @ngdoc method
2069           * @name angular.Module#animation
2070           * @module ng
2071           * @param {string} name animation name
2072           * @param {Function} animationFactory Factory function for creating new instance of an
2073           *                                    animation.
2074           * @description
2075           *
2076           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2077           *
2078           *
2079           * Defines an animation hook that can be later used with
2080           * {@link $animate $animate} service and directives that use this service.
2081           *
2082           * ```js
2083           * module.animation('.animation-name', function($inject1, $inject2) {
2084           *   return {
2085           *     eventName : function(element, done) {
2086           *       //code to run the animation
2087           *       //once complete, then run done()
2088           *       return function cancellationFunction(element) {
2089           *         //code to cancel the animation
2090           *       }
2091           *     }
2092           *   }
2093           * })
2094           * ```
2095           *
2096           * See {@link ng.$animateProvider#register $animateProvider.register()} and
2097           * {@link ngAnimate ngAnimate module} for more information.
2098           */
2099          animation: invokeLater('$animateProvider', 'register'),
2100
2101          /**
2102           * @ngdoc method
2103           * @name angular.Module#filter
2104           * @module ng
2105           * @param {string} name Filter name - this must be a valid angular expression identifier
2106           * @param {Function} filterFactory Factory function for creating new instance of filter.
2107           * @description
2108           * See {@link ng.$filterProvider#register $filterProvider.register()}.
2109           *
2110           * <div class="alert alert-warning">
2111           * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2112           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2113           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2114           * (`myapp_subsection_filterx`).
2115           * </div>
2116           */
2117          filter: invokeLater('$filterProvider', 'register'),
2118
2119          /**
2120           * @ngdoc method
2121           * @name angular.Module#controller
2122           * @module ng
2123           * @param {string|Object} name Controller name, or an object map of controllers where the
2124           *    keys are the names and the values are the constructors.
2125           * @param {Function} constructor Controller constructor function.
2126           * @description
2127           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2128           */
2129          controller: invokeLater('$controllerProvider', 'register'),
2130
2131          /**
2132           * @ngdoc method
2133           * @name angular.Module#directive
2134           * @module ng
2135           * @param {string|Object} name Directive name, or an object map of directives where the
2136           *    keys are the names and the values are the factories.
2137           * @param {Function} directiveFactory Factory function for creating new instance of
2138           * directives.
2139           * @description
2140           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2141           */
2142          directive: invokeLater('$compileProvider', 'directive'),
2143
2144          /**
2145           * @ngdoc method
2146           * @name angular.Module#config
2147           * @module ng
2148           * @param {Function} configFn Execute this function on module load. Useful for service
2149           *    configuration.
2150           * @description
2151           * Use this method to register work which needs to be performed on module loading.
2152           * For more about how to configure services, see
2153           * {@link providers#provider-recipe Provider Recipe}.
2154           */
2155          config: config,
2156
2157          /**
2158           * @ngdoc method
2159           * @name angular.Module#run
2160           * @module ng
2161           * @param {Function} initializationFn Execute this function after injector creation.
2162           *    Useful for application initialization.
2163           * @description
2164           * Use this method to register work which should be performed when the injector is done
2165           * loading all modules.
2166           */
2167          run: function(block) {
2168            runBlocks.push(block);
2169            return this;
2170          }
2171        };
2172
2173        if (configFn) {
2174          config(configFn);
2175        }
2176
2177        return moduleInstance;
2178
2179        /**
2180         * @param {string} provider
2181         * @param {string} method
2182         * @param {String=} insertMethod
2183         * @returns {angular.Module}
2184         */
2185        function invokeLater(provider, method, insertMethod, queue) {
2186          if (!queue) queue = invokeQueue;
2187          return function() {
2188            queue[insertMethod || 'push']([provider, method, arguments]);
2189            return moduleInstance;
2190          };
2191        }
2192      });
2193    };
2194  });
2195
2196}
2197
2198/* global: toDebugString: true */
2199
2200function serializeObject(obj) {
2201  var seen = [];
2202
2203  return JSON.stringify(obj, function(key, val) {
2204    val = toJsonReplacer(key, val);
2205    if (isObject(val)) {
2206
2207      if (seen.indexOf(val) >= 0) return '<<already seen>>';
2208
2209      seen.push(val);
2210    }
2211    return val;
2212  });
2213}
2214
2215function toDebugString(obj) {
2216  if (typeof obj === 'function') {
2217    return obj.toString().replace(/ \{[\s\S]*$/, '');
2218  } else if (typeof obj === 'undefined') {
2219    return 'undefined';
2220  } else if (typeof obj !== 'string') {
2221    return serializeObject(obj);
2222  }
2223  return obj;
2224}
2225
2226/* global angularModule: true,
2227  version: true,
2228
2229  $LocaleProvider,
2230  $CompileProvider,
2231
2232  htmlAnchorDirective,
2233  inputDirective,
2234  inputDirective,
2235  formDirective,
2236  scriptDirective,
2237  selectDirective,
2238  styleDirective,
2239  optionDirective,
2240  ngBindDirective,
2241  ngBindHtmlDirective,
2242  ngBindTemplateDirective,
2243  ngClassDirective,
2244  ngClassEvenDirective,
2245  ngClassOddDirective,
2246  ngCspDirective,
2247  ngCloakDirective,
2248  ngControllerDirective,
2249  ngFormDirective,
2250  ngHideDirective,
2251  ngIfDirective,
2252  ngIncludeDirective,
2253  ngIncludeFillContentDirective,
2254  ngInitDirective,
2255  ngNonBindableDirective,
2256  ngPluralizeDirective,
2257  ngRepeatDirective,
2258  ngShowDirective,
2259  ngStyleDirective,
2260  ngSwitchDirective,
2261  ngSwitchWhenDirective,
2262  ngSwitchDefaultDirective,
2263  ngOptionsDirective,
2264  ngTranscludeDirective,
2265  ngModelDirective,
2266  ngListDirective,
2267  ngChangeDirective,
2268  patternDirective,
2269  patternDirective,
2270  requiredDirective,
2271  requiredDirective,
2272  minlengthDirective,
2273  minlengthDirective,
2274  maxlengthDirective,
2275  maxlengthDirective,
2276  ngValueDirective,
2277  ngModelOptionsDirective,
2278  ngAttributeAliasDirectives,
2279  ngEventDirectives,
2280
2281  $AnchorScrollProvider,
2282  $AnimateProvider,
2283  $$CoreAnimateQueueProvider,
2284  $$CoreAnimateRunnerProvider,
2285  $BrowserProvider,
2286  $CacheFactoryProvider,
2287  $ControllerProvider,
2288  $DocumentProvider,
2289  $ExceptionHandlerProvider,
2290  $FilterProvider,
2291  $InterpolateProvider,
2292  $IntervalProvider,
2293  $$HashMapProvider,
2294  $HttpProvider,
2295  $HttpParamSerializerProvider,
2296  $HttpParamSerializerJQLikeProvider,
2297  $HttpBackendProvider,
2298  $LocationProvider,
2299  $LogProvider,
2300  $ParseProvider,
2301  $RootScopeProvider,
2302  $QProvider,
2303  $$QProvider,
2304  $$SanitizeUriProvider,
2305  $SceProvider,
2306  $SceDelegateProvider,
2307  $SnifferProvider,
2308  $TemplateCacheProvider,
2309  $TemplateRequestProvider,
2310  $$TestabilityProvider,
2311  $TimeoutProvider,
2312  $$RAFProvider,
2313  $$AsyncCallbackProvider,
2314  $WindowProvider,
2315  $$jqLiteProvider,
2316  $$CookieReaderProvider
2317*/
2318
2319
2320/**
2321 * @ngdoc object
2322 * @name angular.version
2323 * @module ng
2324 * @description
2325 * An object that contains information about the current AngularJS version. This object has the
2326 * following properties:
2327 *
2328 * - `full` – `{string}` – Full version string, such as "0.9.18".
2329 * - `major` – `{number}` – Major version number, such as "0".
2330 * - `minor` – `{number}` – Minor version number, such as "9".
2331 * - `dot` – `{number}` – Dot version number, such as "18".
2332 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2333 */
2334var version = {
2335  full: '1.4.0',    // all of these placeholder strings will be replaced by grunt's
2336  major: 1,    // package task
2337  minor: 4,
2338  dot: 0,
2339  codeName: 'jaracimrman-existence'
2340};
2341
2342
2343function publishExternalAPI(angular) {
2344  extend(angular, {
2345    'bootstrap': bootstrap,
2346    'copy': copy,
2347    'extend': extend,
2348    'merge': merge,
2349    'equals': equals,
2350    'element': jqLite,
2351    'forEach': forEach,
2352    'injector': createInjector,
2353    'noop': noop,
2354    'bind': bind,
2355    'toJson': toJson,
2356    'fromJson': fromJson,
2357    'identity': identity,
2358    'isUndefined': isUndefined,
2359    'isDefined': isDefined,
2360    'isString': isString,
2361    'isFunction': isFunction,
2362    'isObject': isObject,
2363    'isNumber': isNumber,
2364    'isElement': isElement,
2365    'isArray': isArray,
2366    'version': version,
2367    'isDate': isDate,
2368    'lowercase': lowercase,
2369    'uppercase': uppercase,
2370    'callbacks': {counter: 0},
2371    'getTestability': getTestability,
2372    '$$minErr': minErr,
2373    '$$csp': csp,
2374    'reloadWithDebugInfo': reloadWithDebugInfo
2375  });
2376
2377  angularModule = setupModuleLoader(window);
2378  try {
2379    angularModule('ngLocale');
2380  } catch (e) {
2381    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2382  }
2383
2384  angularModule('ng', ['ngLocale'], ['$provide',
2385    function ngModule($provide) {
2386      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2387      $provide.provider({
2388        $$sanitizeUri: $$SanitizeUriProvider
2389      });
2390      $provide.provider('$compile', $CompileProvider).
2391        directive({
2392            a: htmlAnchorDirective,
2393            input: inputDirective,
2394            textarea: inputDirective,
2395            form: formDirective,
2396            script: scriptDirective,
2397            select: selectDirective,
2398            style: styleDirective,
2399            option: optionDirective,
2400            ngBind: ngBindDirective,
2401            ngBindHtml: ngBindHtmlDirective,
2402            ngBindTemplate: ngBindTemplateDirective,
2403            ngClass: ngClassDirective,
2404            ngClassEven: ngClassEvenDirective,
2405            ngClassOdd: ngClassOddDirective,
2406            ngCloak: ngCloakDirective,
2407            ngController: ngControllerDirective,
2408            ngForm: ngFormDirective,
2409            ngHide: ngHideDirective,
2410            ngIf: ngIfDirective,
2411            ngInclude: ngIncludeDirective,
2412            ngInit: ngInitDirective,
2413            ngNonBindable: ngNonBindableDirective,
2414            ngPluralize: ngPluralizeDirective,
2415            ngRepeat: ngRepeatDirective,
2416            ngShow: ngShowDirective,
2417            ngStyle: ngStyleDirective,
2418            ngSwitch: ngSwitchDirective,
2419            ngSwitchWhen: ngSwitchWhenDirective,
2420            ngSwitchDefault: ngSwitchDefaultDirective,
2421            ngOptions: ngOptionsDirective,
2422            ngTransclude: ngTranscludeDirective,
2423            ngModel: ngModelDirective,
2424            ngList: ngListDirective,
2425            ngChange: ngChangeDirective,
2426            pattern: patternDirective,
2427            ngPattern: patternDirective,
2428            required: requiredDirective,
2429            ngRequired: requiredDirective,
2430            minlength: minlengthDirective,
2431            ngMinlength: minlengthDirective,
2432            maxlength: maxlengthDirective,
2433            ngMaxlength: maxlengthDirective,
2434            ngValue: ngValueDirective,
2435            ngModelOptions: ngModelOptionsDirective
2436        }).
2437        directive({
2438          ngInclude: ngIncludeFillContentDirective
2439        }).
2440        directive(ngAttributeAliasDirectives).
2441        directive(ngEventDirectives);
2442      $provide.provider({
2443        $anchorScroll: $AnchorScrollProvider,
2444        $animate: $AnimateProvider,
2445        $$animateQueue: $$CoreAnimateQueueProvider,
2446        $$AnimateRunner: $$CoreAnimateRunnerProvider,
2447        $browser: $BrowserProvider,
2448        $cacheFactory: $CacheFactoryProvider,
2449        $controller: $ControllerProvider,
2450        $document: $DocumentProvider,
2451        $exceptionHandler: $ExceptionHandlerProvider,
2452        $filter: $FilterProvider,
2453        $interpolate: $InterpolateProvider,
2454        $interval: $IntervalProvider,
2455        $http: $HttpProvider,
2456        $httpParamSerializer: $HttpParamSerializerProvider,
2457        $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2458        $httpBackend: $HttpBackendProvider,
2459        $location: $LocationProvider,
2460        $log: $LogProvider,
2461        $parse: $ParseProvider,
2462        $rootScope: $RootScopeProvider,
2463        $q: $QProvider,
2464        $$q: $$QProvider,
2465        $sce: $SceProvider,
2466        $sceDelegate: $SceDelegateProvider,
2467        $sniffer: $SnifferProvider,
2468        $templateCache: $TemplateCacheProvider,
2469        $templateRequest: $TemplateRequestProvider,
2470        $$testability: $$TestabilityProvider,
2471        $timeout: $TimeoutProvider,
2472        $window: $WindowProvider,
2473        $$rAF: $$RAFProvider,
2474        $$asyncCallback: $$AsyncCallbackProvider,
2475        $$jqLite: $$jqLiteProvider,
2476        $$HashMap: $$HashMapProvider,
2477        $$cookieReader: $$CookieReaderProvider
2478      });
2479    }
2480  ]);
2481}
2482
2483/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2484 *     Any commits to this file should be reviewed with security in mind.  *
2485 *   Changes to this file can potentially create security vulnerabilities. *
2486 *          An approval from 2 Core members with history of modifying      *
2487 *                         this file is required.                          *
2488 *                                                                         *
2489 *  Does the change somehow allow for arbitrary javascript to be executed? *
2490 *    Or allows for someone to change the prototype of built-in objects?   *
2491 *     Or gives undesired access to variables likes document or window?    *
2492 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2493
2494/* global JQLitePrototype: true,
2495  addEventListenerFn: true,
2496  removeEventListenerFn: true,
2497  BOOLEAN_ATTR: true,
2498  ALIASED_ATTR: true,
2499*/
2500
2501//////////////////////////////////
2502//JQLite
2503//////////////////////////////////
2504
2505/**
2506 * @ngdoc function
2507 * @name angular.element
2508 * @module ng
2509 * @kind function
2510 *
2511 * @description
2512 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2513 *
2514 * If jQuery is available, `angular.element` is an alias for the
2515 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2516 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2517 *
2518 * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2519 * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2520 * commonly needed functionality with the goal of having a very small footprint.</div>
2521 *
2522 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
2523 *
2524 * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2525 * jqLite; they are never raw DOM references.</div>
2526 *
2527 * ## Angular's jqLite
2528 * jqLite provides only the following jQuery methods:
2529 *
2530 * - [`addClass()`](http://api.jquery.com/addClass/)
2531 * - [`after()`](http://api.jquery.com/after/)
2532 * - [`append()`](http://api.jquery.com/append/)
2533 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2534 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2535 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2536 * - [`clone()`](http://api.jquery.com/clone/)
2537 * - [`contents()`](http://api.jquery.com/contents/)
2538 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
2539 * - [`data()`](http://api.jquery.com/data/)
2540 * - [`detach()`](http://api.jquery.com/detach/)
2541 * - [`empty()`](http://api.jquery.com/empty/)
2542 * - [`eq()`](http://api.jquery.com/eq/)
2543 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2544 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2545 * - [`html()`](http://api.jquery.com/html/)
2546 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2547 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2548 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2549 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2550 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2551 * - [`prepend()`](http://api.jquery.com/prepend/)
2552 * - [`prop()`](http://api.jquery.com/prop/)
2553 * - [`ready()`](http://api.jquery.com/ready/)
2554 * - [`remove()`](http://api.jquery.com/remove/)
2555 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2556 * - [`removeClass()`](http://api.jquery.com/removeClass/)
2557 * - [`removeData()`](http://api.jquery.com/removeData/)
2558 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2559 * - [`text()`](http://api.jquery.com/text/)
2560 * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2561 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2562 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2563 * - [`val()`](http://api.jquery.com/val/)
2564 * - [`wrap()`](http://api.jquery.com/wrap/)
2565 *
2566 * ## jQuery/jqLite Extras
2567 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2568 *
2569 * ### Events
2570 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction a
2570pis and fires this event
2571 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2572 *    element before it is removed.
2573 *
2574 * ### Methods
2575 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2576 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2577 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2578 *   `'ngModel'`).
2579 * - `injector()` - retrieves the injector of the current element or its parent.
2580 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2581 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2582 *   be enabled.
2583 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2584 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2585 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2586 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2587 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2588 *   parent element is reached.
2589 *
2590 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2591 * @returns {Object} jQuery object.
2592 */
2593
2594JQLite.expando = 'ng339';
2595
2596var jqCache = JQLite.cache = {},
2597    jqId = 1,
2598    addEventListenerFn = function(element, type, fn) {
2599      element.addEventListener(type, fn, false);
2600    },
2601    removeEventListenerFn = function(element, type, fn) {
2602      element.removeEventListener(type, fn, false);
2603    };
2604
2605/*
2606 * !!! This is an undocumented "private" function !!!
2607 */
2608JQLite._data = function(node) {
2609  //jQuery always returns an object on cache miss
2610  return this.cache[node[this.expando]] || {};
2611};
2612
2613function jqNextId() { return ++jqId; }
2614
2615
2616var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2617var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2618var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2619var jqLiteMinErr = minErr('jqLite');
2620
2621/**
2622 * Converts snake_case to camelCase.
2623 * Also there is special case for Moz prefix starting with upper case letter.
2624 * @param name Name to normalize
2625 */
2626function camelCase(name) {
2627  return name.
2628    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2629      return offset ? letter.toUpperCase() : letter;
2630    }).
2631    replace(MOZ_HACK_REGEXP, 'Moz$1');
2632}
2633
2634var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2635var HTML_REGEXP = /<|&#?\w+;/;
2636var TAG_NAME_REGEXP = /<([\w:]+)/;
2637var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2638
2639var wrapMap = {
2640  'option': [1, '<select multiple="multiple">', '</select>'],
2641
2642  'thead': [1, '<table>', '</table>'],
2643  'col': [2, '<table><colgroup>', '</colgroup></table>'],
2644  'tr': [2, '<table><tbody>', '</tbody></table>'],
2645  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2646  '_default': [0, "", ""]
2647};
2648
2649wrapMap.optgroup = wrapMap.option;
2650wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2651wrapMap.th = wrapMap.td;
2652
2653
2654function jqLiteIsTextNode(html) {
2655  return !HTML_REGEXP.test(html);
2656}
2657
2658function jqLiteAcceptsData(node) {
2659  // The window object can accept data but has no nodeType
2660  // Otherwise we are only interested in elements (1) and documents (9)
2661  var nodeType = node.nodeType;
2662  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2663}
2664
2665function jqLiteBuildFragment(html, context) {
2666  var tmp, tag, wrap,
2667      fragment = context.createDocumentFragment(),
2668      nodes = [], i;
2669
2670  if (jqLiteIsTextNode(html)) {
2671    // Convert non-html into a text node
2672    nodes.push(context.createTextNode(html));
2673  } else {
2674    // Convert html into DOM nodes
2675    tmp = tmp || fragment.appendChild(context.createElement("div"));
2676    tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2677    wrap = wrapMap[tag] || wrapMap._default;
2678    tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2679
2680    // Descend through wrappers to the right content
2681    i = wrap[0];
2682    while (i--) {
2683      tmp = tmp.lastChild;
2684    }
2685
2686    nodes = concat(nodes, tmp.childNodes);
2687
2688    tmp = fragment.firstChild;
2689    tmp.textContent = "";
2690  }
2691
2692  // Remove wrapper from fragment
2693  fragment.textContent = "";
2694  fragment.innerHTML = ""; // Clear inner HTML
2695  forEach(nodes, function(node) {
2696    fragment.appendChild(node);
2697  });
2698
2699  return fragment;
2700}
2701
2702function jqLiteParseHTML(html, context) {
2703  context = context || document;
2704  var parsed;
2705
2706  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2707    return [context.createElement(parsed[1])];
2708  }
2709
2710  if ((parsed = jqLiteBuildFragment(html, context))) {
2711    return parsed.childNodes;
2712  }
2713
2714  return [];
2715}
2716
vendor: 1,065 bytes, lines 2717-2758
2717/////////////////////////////////////////////
2718function JQLite(element) {
2719  if (element instanceof JQLite) {
2720    return element;
2721  }
2722
2723  var argIsString;
2724
2725  if (isString(element)) {
2726    element = trim(element);
2727    argIsString = true;
2728  }
2729  if (!(this instanceof JQLite)) {
2730    if (argIsString && element.charAt(0) != '<') {
2731      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2732    }
2733    return new JQLite(element);
2734  }
2735
2736  if (argIsString) {
2737    jqLiteAddNodes(this, jqLiteParseHTML(element));
2738  } else {
2739    jqLiteAddNodes(this, element);
2740  }
2741}
2742
2743function jqLiteClone(element) {
2744  return element.cloneNode(true);
2745}
2746
2747function jqLiteDealoc(element, onlyDescendants) {
2748  if (!onlyDescendants) jqLiteRemoveData(element);
2749
2750  if (element.querySelectorAll) {
2751    var descendants = element.querySelectorAll('*');
2752    for (var i = 0, l = descendants.length; i < l; i++) {
2753      jqLiteRemoveData(descendants[i]);
2754    }
2755  }
2756}
2757
2758function jqLiteOff(element, type, fn, unsupported) {
2759  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2760
2761  var expandoStore = jqLiteExpandoStore(element);
2762  var events = expandoStore && expandoStore.events;
2763  var handle = expandoStore && expandoStore.handle;
2764
2765  if (!handle) return; //no listeners registered
2766
2767  if (!type) {
2768    for (type in events) {
2769      if (type !== '$destroy') {
2770        removeEventListenerFn(element, type, handle);
2771      }
2772      delete events[type];
2773    }
2774  } else {
2775    forEach(type.split(' '), function(type) {
2776      if (isDefined(fn)) {
2777        var listenerFns = events[type];
2778        arrayRemove(listenerFns || [], fn);
2779        if (listenerFns && listenerFns.length > 0) {
2780          return;
2781        }
2782      }
2783
2784      removeEventListenerFn(element, type, handle);
2785      delete events[type];
2786    });
2787  }
2788}
2789
2790function jqLiteRemoveData(element, name) {
2791  var expandoId = element.ng339;
2792  var expandoStore = expandoId && jqCache[expandoId];
2793
2794  if (expandoStore) {
2795    if (name) {
2796      delete expandoStore.data[name];
2797      return;
2798    }
2799
2800    if (expandoStore.handle) {
2801      if (expandoStore.events.$destroy) {
2802        expandoStore.handle({}, '$destroy');
2803      }
2804      jqLiteOff(element);
2805    }
2806    delete jqCache[expandoId];
2807    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
2808  }
2809}
2810
2811
2812function jqLiteExpandoStore(element, createIfNecessary) {
2813  var expandoId = element.ng339,
2814      expandoStore = expandoId && jqCache[expandoId];
2815
2816  if (createIfNecessary && !expandoStore) {
2817    element.ng339 = expandoId = jqNextId();
2818    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
2819  }
2820
2821  return expandoStore;
2822}
2823
2824
2825function jqLiteData(element, key, value) {
2826  if (jqLiteAcceptsData(element)) {
2827
2828    var isSimpleSetter = isDefined(value);
2829    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
2830    var massGetter = !key;
2831    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
2832    var data = expandoStore && expandoStore.data;
2833
2834    if (isSimpleSetter) { // data('key', value)
2835      data[key] = value;
2836    } else {
2837      if (massGetter) {  // data()
2838        return data;
2839      } else {
2840        if (isSimpleGetter) { // data('key')
2841          // don't force creation of expandoStore if it doesn't exist yet
2842          return data && data[key];
2843        } else { // mass-setter: data({key1: val1, key2: val2})
2844          extend(data, key);
2845        }
2846      }
2847    }
2848  }
2849}
2850
2851function jqLiteHasClass(element, selector) {
2852  if (!element.getAttribute) return false;
2853  return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2854      indexOf(" " + selector + " ") > -1);
2855}
2856
2857function jqLiteRemoveClass(element, cssClasses) {
2858  if (cssClasses && element.setAttribute) {
2859    forEach(cssClasses.split(' '), function(cssClass) {
2860      element.setAttribute('class', trim(
2861          (" " + (element.getAttribute('class') || '') + " ")
2862          .replace(/[\n\t]/g, " ")
2863          .replace(" " + trim(cssClass) + " ", " "))
2864      );
2865    });
2866  }
2867}
2868
2869function jqLiteAddClass(element, cssClasses) {
2870  if (cssClasses && element.setAttribute) {
2871    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2872                            .replace(/[\n\t]/g, " ");
2873
2874    forEach(cssClasses.split(' '), function(cssClass) {
2875      cssClass = trim(cssClass);
2876      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2877        existingClasses += cssClass + ' ';
2878      }
2879    });
2880
2881    element.setAttribute('class', trim(existingClasses));
2882  }
2883}
2884
2885
2886function jqLiteAddNodes(root, elements) {
2887  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
2888
2889  if (elements) {
2890
2891    // if a Node (the most common case)
2892    if (elements.nodeType) {
2893      root[root.length++] = elements;
2894    } else {
2895      var length = elements.length;
2896
2897      // if an Array or NodeList and not a Window
2898      if (typeof length === 'number' && elements.window !== elements) {
2899        if (length) {
2900          for (var i = 0; i < length; i++) {
2901            root[root.length++] = elements[i];
2902          }
2903        }
2904      } else {
2905        root[root.length++] = elements;
2906      }
2907    }
2908  }
2909}
2910
2911
2912function jqLiteController(element, name) {
2913  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
2914}
2915
2916function jqLiteInheritedData(element, name, value) {
2917  // if element is the document object work with the html element instead
2918  // this makes $(document).scope() possible
2919  if (element.nodeType == NODE_TYPE_DOCUMENT) {
2920    element = element.documentElement;
2921  }
2922  var names = isArray(name) ? name : [name];
2923
2924  while (element) {
2925    for (var i = 0, ii = names.length; i < ii; i++) {
2926      if ((value = jqLite.data(element, names[i])) !== undefined) return value;
2927    }
2928
2929    // If dealing with a document fragment node with a host element, and no parent, use the host
2930    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2931    // to lookup parent controllers.
2932    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
2933  }
2934}
2935
2936function jqLiteEmpty(element) {
2937  jqLiteDealoc(element, true);
2938  while (element.firstChild) {
2939    element.removeChild(element.firstChild);
2940  }
2941}
2942
2943function jqLiteRemove(element, keepData) {
2944  if (!keepData) jqLiteDealoc(element);
2945  var parent = element.parentNode;
2946  if (parent) parent.removeChild(element);
2947}
2948
2949
2950function jqLiteDocumentLoaded(action, win) {
2951  win = win || window;
2952  if (win.document.readyState === 'complete') {
2953    // Force the action to be run async for consistent behaviour
2954    // from the action's point of view
2955    // i.e. it will definitely not be in a $apply
2956    win.setTimeout(action);
2957  } else {
2958    // No need to unbind this handler as load is only ever called once
2959    jqLite(win).on('load', action);
2960  }
2961}
2962
2963//////////////////////////////////////////
2964// Functions which are declared directly.
2965//////////////////////////////////////////
2966var JQLitePrototype = JQLite.prototype = {
2967  ready: function(fn) {
2968    var fired = false;
2969
2970    function trigger() {
2971      if (fired) return;
2972      fired = true;
2973      fn();
2974    }
2975
2976    // check if document is already loaded
2977    if (document.readyState === 'complete') {
2978      setTimeout(trigger);
2979    } else {
2980      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2981      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2982      // jshint -W064
2983      JQLite(window).on('load', trigger); // fallback to window.onload for others
2984      // jshint +W064
2985    }
2986  },
2987  toString: function() {
2988    var value = [];
2989    forEach(this, function(e) { value.push('' + e);});
2990    return '[' + value.join(', ') + ']';
2991  },
2992
2993  eq: function(index) {
2994      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2995  },
2996
2997  length: 0,
2998  push: push,
2999  sort: [].sort,
3000  splice: [].splice
3001};
3002
3003//////////////////////////////////////////
3004// Functions iterating getter/setters.
3005// these functions return self on setter and
3006// value on get.
3007//////////////////////////////////////////
3008var BOOLEAN_ATTR = {};
3009forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3010  BOOLEAN_ATTR[lowercase(value)] = value;
3011});
3012var BOOLEAN_ELEMENTS = {};
3013forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3014  BOOLEAN_ELEMENTS[value] = true;
3015});
3016var ALIASED_ATTR = {
3017  'ngMinlength': 'minlength',
3018  'ngMaxlength': 'maxlength',
3019  'ngMin': 'min',
3020  'ngMax': 'max',
3021  'ngPattern': 'pattern'
3022};
3023
3024function getBooleanAttrName(element, name) {
3025  // check dom last since we will most likely fail on name
3026  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3027
3028  // booleanAttr is here twice to minimize DOM access
3029  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3030}
3031
3032function getAliasedAttrName(element, name) {
3033  var nodeName = element.nodeName;
3034  return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
3035}
3036
3037forEach({
3038  data: jqLiteData,
3039  removeData: jqLiteRemoveData
3040}, function(fn, name) {
3041  JQLite[name] = fn;
3042});
3043
3044forEach({
3045  data: jqLiteData,
3046  inheritedData: jqLiteInheritedData,
3047
3048  scope: function(element) {
3049    // Can't use jqLiteData here directly so we stay compatible with jQuery!
3050    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3051  },
3052
3053  isolateScope: function(element) {
3054    // Can't use jqLiteData here directly so we stay compatible with jQuery!
3055    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3056  },
3057
3058  controller: jqLiteController,
3059
3060  injector: function(element) {
3061    return jqLiteInheritedData(element, '$injector');
3062  },
3063
3064  removeAttr: function(element, name) {
3065    element.removeAttribute(name);
3066  },
3067
3068  hasClass: jqLiteHasClass,
3069
3070  css: function(element, name, value) {
3071    name = camelCase(name);
3072
3073    if (isDefined(value)) {
3074      element.style[name] = value;
3075    } else {
3076      return element.style[name];
3077    }
3078  },
3079
3080  attr: function(element, name, value) {
3081    var nodeType = element.nodeType;
3082    if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3083      return;
3084    }
3085    var lowercasedName = lowercase(name);
3086    if (BOOLEAN_ATTR[lowercasedName]) {
3087      if (isDefined(value)) {
3088        if (!!value) {
3089          element[name] = true;
3090          element.setAttribute(name, lowercasedName);
3091        } else {
3092          element[name] = false;
3093          element.removeAttribute(lowercasedName);
3094        }
3095      } else {
3096        return (element[name] ||
3097                 (element.attributes.getNamedItem(name) || noop).specified)
3098               ? lowercasedName
3099               : undefined;
3100      }
3101    } else if (isDefined(value)) {
3102      element.setAttribute(name, value);
3103    } else if (element.getAttribute) {
3104      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3105      // some elements (e.g. Document) don't have get attribute, so return undefined
3106      var ret = element.getAttribute(name, 2);
3107      // normalize non-existing attributes to undefined (as jQuery)
3108      return ret === null ? undefined : ret;
3109    }
3110  },
3111
3112  prop: function(element, name, value) {
3113    if (isDefined(value)) {
3114      element[name] = value;
3115    } else {
3116      return element[name];
3117    }
3118  },
3119
3120  text: (function() {
3121    getText.$dv = '';
3122    return getText;
3123
3124    function getText(element, value) {
3125      if (isUndefined(value)) {
3126        var nodeType = element.nodeType;
3127        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3128      }
3129      element.textContent = value;
3130    }
3131  })(),
3132
3133  val: function(element, value) {
3134    if (isUndefined(value)) {
3135      if (element.multiple && nodeName_(element) === 'select') {
3136        var result = [];
vendor: 3,900 bytes, lines 3137-3266
3137        forEach(element.options, function(option) {
3138          if (option.selected) {
3139            result.push(option.value || option.text);
3140          }
3141        });
3142        return result.length === 0 ? null : result;
3143      }
3144      return element.value;
3145    }
3146    element.value = value;
3147  },
3148
3149  html: function(element, value) {
3150    if (isUndefined(value)) {
3151      return element.innerHTML;
3152    }
3153    jqLiteDealoc(element, true);
3154    element.innerHTML = value;
3155  },
3156
3157  empty: jqLiteEmpty
3158}, function(fn, name) {
3159  /**
3160   * Properties: writes return selection, reads return first value
3161   */
3162  JQLite.prototype[name] = function(arg1, arg2) {
3163    var i, key;
3164    var nodeCount = this.length;
3165
3166    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3167    // in a way that survives minification.
3168    // jqLiteEmpty takes no arguments but is a setter.
3169    if (fn !== jqLiteEmpty &&
3170        (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
3171      if (isObject(arg1)) {
3172
3173        // we are a write, but the object properties are the key/values
3174        for (i = 0; i < nodeCount; i++) {
3175          if (fn === jqLiteData) {
3176            // data() takes the whole object in jQuery
3177            fn(this[i], arg1);
3178          } else {
3179            for (key in arg1) {
3180              fn(this[i], key, arg1[key]);
3181            }
3182          }
3183        }
3184        // return self for chaining
3185        return this;
3186      } else {
3187        // we are a read, so read the first child.
3188        // TODO: do we still need this?
3189        var value = fn.$dv;
3190        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3191        var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
3192        for (var j = 0; j < jj; j++) {
3193          var nodeValue = fn(this[j], arg1, arg2);
3194          value = value ? value + nodeValue : nodeValue;
3195        }
3196        return value;
3197      }
3198    } else {
3199      // we are a write, so apply to all children
3200      for (i = 0; i < nodeCount; i++) {
3201        fn(this[i], arg1, arg2);
3202      }
3203      // return self for chaining
3204      return this;
3205    }
3206  };
3207});
3208
3209function createEventHandler(element, events) {
3210  var eventHandler = function(event, type) {
3211    // jQuery specific api
3212    event.isDefaultPrevented = function() {
3213      return event.defaultPrevented;
3214    };
3215
3216    var eventFns = events[type || event.type];
3217    var eventFnsLength = eventFns ? eventFns.length : 0;
3218
3219    if (!eventFnsLength) return;
3220
3221    if (isUndefined(event.immediatePropagationStopped)) {
3222      var originalStopImmediatePropagation = event.stopImmediatePropagation;
3223      event.stopImmediatePropagation = function() {
3224        event.immediatePropagationStopped = true;
3225
3226        if (event.stopPropagation) {
3227          event.stopPropagation();
3228        }
3229
3230        if (originalStopImmediatePropagation) {
3231          originalStopImmediatePropagation.call(event);
3232        }
3233      };
3234    }
3235
3236    event.isImmediatePropagationStopped = function() {
3237      return event.immediatePropagationStopped === true;
3238    };
3239
3240    // Copy event handlers in case event handlers array is modified during execution.
3241    if ((eventFnsLength > 1)) {
3242      eventFns = shallowCopy(eventFns);
3243    }
3244
3245    for (var i = 0; i < eventFnsLength; i++) {
3246      if (!event.isImmediatePropagationStopped()) {
3247        eventFns[i].call(element, event);
3248      }
3249    }
3250  };
3251
3252  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3253  //       events on `element`
3254  eventHandler.elem = element;
3255  return eventHandler;
3256}
3257
3258//////////////////////////////////////////
3259// Functions iterating traversal.
3260// These functions chain results into a single
3261// selector.
3262//////////////////////////////////////////
3263forEach({
3264  removeData: jqLiteRemoveData,
3265
3266  on: function jqLiteOn(element, type, fn, unsupported) {
3267    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3268
3269    // Do not add event handlers to non-elements because they will not be cleaned up.
3270    if (!jqLiteAcceptsData(element)) {
3271      return;
3272    }
3273
3274    var expandoStore = jqLiteExpandoStore(element, true);
3275    var events = expandoStore.events;
3276    var handle = expandoStore.handle;
3277
3278    if (!handle) {
3279      handle = expandoStore.handle = createEventHandler(element, events);
3280    }
3281
3282    // http://jsperf.com/string-indexof-vs-split
3283    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3284    var i = types.length;
3285
3286    while (i--) {
3287      type = types[i];
3288      var eventFns = events[type];
3289
3290      if (!eventFns) {
3291        events[type] = [];
3292
3293        if (type === 'mouseenter' || type === 'mouseleave') {
3294          // Refer to jQuery's implementation of mouseenter & mouseleave
3295          // Read about mouseenter and mouseleave:
3296          // http://www.quirksmode.org/js/events_mouse.html#link8
3297
3298          jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
3299            var target = this, related = event.relatedTarget;
3300            // For mousenter/leave call the handler if related is outside the target.
3301            // NB: No relatedTarget if the mouse left/entered the browser window
3302            if (!related || (related !== target && !target.contains(related))) {
3303              handle(event, type);
3304            }
3305          });
3306
3307        } else {
3308          if (type !== '$destroy') {
3309            addEventListenerFn(element, type, handle);
3310          }
3311        }
3312        eventFns = events[type];
3313      }
3314      eventFns.push(fn);
3315    }
3316  },
3317
3318  off: jqLiteOff,
3319
3320  one: function(element, type, fn) {
3321    element = jqLite(element);
3322
3323    //add the listener twice so that when it is called
3324    //you can remove the original function and still be
3325    //able to call element.off(ev, fn) normally
3326    element.on(type, function onFn() {
3327      element.off(type, fn);
3328      element.off(type, onFn);
3329    });
3330    element.on(type, fn);
3331  },
3332
3333  replaceWith: function(element, replaceNode) {
3334    var index, parent = element.parentNode;
3335    jqLiteDealoc(element);
3336    forEach(new JQLite(replaceNode), function(node) {
3337      if (index) {
3338        parent.insertBefore(node, index.nextSibling);
3339      } else {
3340        parent.replaceChild(node, element);
3341      }
3342      index = node;
3343    });
3344  },
3345
3346  children: function(element) {
3347    var children = [];
3348    forEach(element.childNodes, function(element) {
3349      if (element.nodeType === NODE_TYPE_ELEMENT) {
3350        children.push(element);
3351      }
3352    });
3353    return children;
3354  },
3355
3356  contents: function(element) {
3357    return element.contentDocument || element.childNodes || [];
3358  },
3359
3360  append: function(element, node) {
3361    var nodeType = element.nodeType;
3362    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3363
3364    node = new JQLite(node);
3365
3366    for (var i = 0, ii = node.length; i < ii; i++) {
3367      var child = node[i];
3368      element.appendChild(child);
3369    }
3370  },
3371
3372  prepend: function(element, node) {
3373    if (element.nodeType === NODE_TYPE_ELEMENT) {
3374      var index = element.firstChild;
3375      forEach(new JQLite(node), function(child) {
3376        element.insertBefore(child, index);
3377      });
3378    }
3379  },
3380
3381  wrap: function(element, wrapNode) {
3382    wrapNode = jqLite(wrapNode).eq(0).clone()[0];
3383    var parent = element.parentNode;
3384    if (parent) {
3385      parent.replaceChild(wrapNode, element);
3386    }
3387    wrapNode.appendChild(element);
3388  },
3389
3390  remove: jqLiteRemove,
3391
3392  detach: function(element) {
3393    jqLiteRemove(element, true);
3394  },
3395
3396  after: function(element, newElement) {
3397    var index = element, parent = element.parentNode;
3398    newElement = new JQLite(newElement);
3399
3400    for (var i = 0, ii = newElement.length; i < ii; i++) {
3401      var node = newElement[i];
3402      parent.insertBefore(node, index.nextSibling);
3403      index = node;
3404    }
3405  },
3406
3407  addClass: jqLiteAddClass,
3408  removeClass: jqLiteRemoveClass,
3409
3410  toggleClass: function(element, selector, condition) {
3411    if (selector) {
vendor: 5,441 bytes, lines 3412-3613
3412      forEach(selector.split(' '), function(className) {
3413        var classCondition = condition;
3414        if (isUndefined(classCondition)) {
3415          classCondition = !jqLiteHasClass(element, className);
3416        }
3417        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3418      });
3419    }
3420  },
3421
3422  parent: function(element) {
3423    var parent = element.parentNode;
3424    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3425  },
3426
3427  next: function(element) {
3428    return element.nextElementSibling;
3429  },
3430
3431  find: function(element, selector) {
3432    if (element.getElementsByTagName) {
3433      return element.getElementsByTagName(selector);
3434    } else {
3435      return [];
3436    }
3437  },
3438
3439  clone: jqLiteClone,
3440
3441  triggerHandler: function(element, event, extraParameters) {
3442
3443    var dummyEvent, eventFnsCopy, handlerArgs;
3444    var eventName = event.type || event;
3445    var expandoStore = jqLiteExpandoStore(element);
3446    var events = expandoStore && expandoStore.events;
3447    var eventFns = events && events[eventName];
3448
3449    if (eventFns) {
3450      // Create a dummy event to pass to the handlers
3451      dummyEvent = {
3452        preventDefault: function() { this.defaultPrevented = true; },
3453        isDefaultPrevented: function() { return this.defaultPrevented === true; },
3454        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3455        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3456        stopPropagation: noop,
3457        type: eventName,
3458        target: element
3459      };
3460
3461      // If a custom event was provided then extend our dummy event with it
3462      if (event.type) {
3463        dummyEvent = extend(dummyEvent, event);
3464      }
3465
3466      // Copy event handlers in case event handlers array is modified during execution.
3467      eventFnsCopy = shallowCopy(eventFns);
3468      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3469
3470      forEach(eventFnsCopy, function(fn) {
3471        if (!dummyEvent.isImmediatePropagationStopped()) {
3472          fn.apply(element, handlerArgs);
3473        }
3474      });
3475    }
3476  }
3477}, function(fn, name) {
3478  /**
3479   * chaining functions
3480   */
3481  JQLite.prototype[name] = function(arg1, arg2, arg3) {
3482    var value;
3483
3484    for (var i = 0, ii = this.length; i < ii; i++) {
3485      if (isUndefined(value)) {
3486        value = fn(this[i], arg1, arg2, arg3);
3487        if (isDefined(value)) {
3488          // any function which returns a value needs to be wrapped
3489          value = jqLite(value);
3490        }
3491      } else {
3492        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3493      }
3494    }
3495    return isDefined(value) ? value : this;
3496  };
3497
3498  // bind legacy bind/unbind to on/off
3499  JQLite.prototype.bind = JQLite.prototype.on;
3500  JQLite.prototype.unbind = JQLite.prototype.off;
3501});
3502
3503
3504// Provider for private $$jqLite service
3505function $$jqLiteProvider() {
3506  this.$get = function $$jqLite() {
3507    return extend(JQLite, {
3508      hasClass: function(node, classes) {
3509        if (node.attr) node = node[0];
3510        return jqLiteHasClass(node, classes);
3511      },
3512      addClass: function(node, classes) {
3513        if (node.attr) node = node[0];
3514        return jqLiteAddClass(node, classes);
3515      },
3516      removeClass: function(node, classes) {
3517        if (node.attr) node = node[0];
3518        return jqLiteRemoveClass(node, classes);
3519      }
3520    });
3521  };
3522}
3523
3524/**
3525 * Computes a hash of an 'obj'.
3526 * Hash of a:
3527 *  string is string
3528 *  number is number as string
3529 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3530 *         that is also assigned to the $$hashKey property of the object.
3531 *
3532 * @param obj
3533 * @returns {string} hash string such that the same input will have the same hash string.
3534 *         The resulting string key is in 'type:hashKey' format.
3535 */
3536function hashKey(obj, nextUidFn) {
3537  var key = obj && obj.$$hashKey;
3538
3539  if (key) {
3540    if (typeof key === 'function') {
3541      key = obj.$$hashKey();
3542    }
3543    return key;
3544  }
3545
3546  var objType = typeof obj;
3547  if (objType == 'function' || (objType == 'object' && obj !== null)) {
3548    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3549  } else {
3550    key = objType + ':' + obj;
3551  }
3552
3553  return key;
3554}
3555
3556/**
3557 * HashMap which can use objects as keys
3558 */
3559function HashMap(array, isolatedUid) {
3560  if (isolatedUid) {
3561    var uid = 0;
3562    this.nextUid = function() {
3563      return ++uid;
3564    };
3565  }
3566  forEach(array, this.put, this);
3567}
3568HashMap.prototype = {
3569  /**
3570   * Store key value pair
3571   * @param key key to store can be any type
3572   * @param value value to store can be any type
3573   */
3574  put: function(key, value) {
3575    this[hashKey(key, this.nextUid)] = value;
3576  },
3577
3578  /**
3579   * @param key
3580   * @returns {Object} the value for the key
3581   */
3582  get: function(key) {
3583    return this[hashKey(key, this.nextUid)];
3584  },
3585
3586  /**
3587   * Remove the key/value pair
3588   * @param key
3589   */
3590  remove: function(key) {
3591    var value = this[key = hashKey(key, this.nextUid)];
3592    delete this[key];
3593    return value;
3594  }
3595};
3596
3597var $$HashMapProvider = [function() {
3598  this.$get = [function() {
3599    return HashMap;
3600  }];
3601}];
3602
3603/**
3604 * @ngdoc function
3605 * @module ng
3606 * @name angular.injector
3607 * @kind function
3608 *
3609 * @description
3610 * Creates an injector object that can be used for retrieving services as well as for
3611 * dependency injection (see {@link guide/di dependency injection}).
3612 *
3613 * @param {Array.<string|Function>}
3613 modules A list of module functions or their aliases. See
3614 *     {@link angular.module}. The `ng` module must be explicitly added.
3615 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3616 *     disallows argument name annotation inference.
3617 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3618 *
3619 * @example
3620 * Typical usage
3621 * ```js
3622 *   // create an injector
3623 *   var $injector = angular.injector(['ng']);
3624 *
3625 *   // use the injector to kick off your application
3626 *   // use the type inference to auto inject arguments, or use implicit injection
3627 *   $injector.invoke(function($rootScope, $compile, $document) {
3628 *     $compile($document)($rootScope);
3629 *     $rootScope.$digest();
3630 *   });
3631 * ```
3632 *
3633 * Sometimes you want to get access to the injector of a currently running Angular app
3634 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3635 * application has been bootstrapped. You can do this using the extra `injector()` added
3636 * to JQuery/jqLite elements. See {@link angular.element}.
3637 *
3638 * *This is fairly rare but could be the case if a third party library is injecting the
3639 * markup.*
3640 *
3641 * In the following example a new block of HTML containing a `ng-controller`
3642 * directive is added to the end of the document body by JQuery. We then compile and link
3643 * it into the current AngularJS scope.
3644 *
3645 * ```js
3646 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3647 * $(document.body).append($div);
3648 *
3649 * angular.element(document).injector().invoke(function($compile) {
3650 *   var scope = angular.element($div).scope();
3651 *   $compile($div)(scope);
3652 * });
3653 * ```
3654 */
3655
3656
3657/**
3658 * @ngdoc module
3659 * @name auto
3660 * @description
3661 *
3662 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3663 */
3664
3665var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3666var FN_ARG_SPLIT = /,/;
3667var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3668var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3669var $injectorMinErr = minErr('$injector');
3670
3671function anonFn(fn) {
3672  // For anonymous functions, showing at the very least the function signature can help in
3673  // debugging.
3674  var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
3675      args = fnText.match(FN_ARGS);
3676  if (args) {
3677    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3678  }
3679  return 'fn';
3680}
3681
3682function annotate(fn, strictDi, name) {
3683  var $inject,
3684      fnText,
3685      argDecl,
3686      last;
3687
3688  if (typeof fn === 'function') {
3689    if (!($inject = fn.$inject)) {
3690      $inject = [];
3691      if (fn.length) {
3692        if (strictDi) {
3693          if (!isString(name) || !name) {
3694            name = fn.name || anonFn(fn);
3695          }
3696          throw $injectorMinErr('strictdi',
3697            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3698        }
3699        fnText = fn.toString().replace(STRIP_COMMENTS, '');
3700        argDecl = fnText.match(FN_ARGS);
3701        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3702          arg.replace(FN_ARG, function(all, underscore, name) {
3703            $inject.push(name);
3704          });
3705        });
3706      }
3707      fn.$inject = $inject;
3708    }
3709  } else if (isArray(fn)) {
3710    last = fn.length - 1;
3711    assertArgFn(fn[last], 'fn');
3712    $inject = fn.slice(0, last);
3713  } else {
3714    assertArgFn(fn, 'fn', true);
3715  }
3716  return $inject;
3717}
3718
3719///////////////////////////////////////
3720
3721/**
3722 * @ngdoc service
3723 * @name $injector
3724 *
3725 * @description
3726 *
3727 * `$injector` is used to retrieve object instances as defined by
3728 * {@link auto.$provide provider}, instantiate types, invoke methods,
3729 * and load modules.
3730 *
3731 * The following always holds true:
3732 *
3733 * ```js
3734 *   var $injector = angular.injector();
3735 *   expect($injector.get('$injector')).toBe($injector);
3736 *   expect($injector.invoke(function($injector) {
3737 *     return $injector;
3738 *   })).toBe($injector);
3739 * ```
3740 *
3741 * # Injection Function Annotation
3742 *
3743 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3744 * following are all valid ways of annotating function with injection arguments and are equivalent.
3745 *
3746 * ```js
3747 *   // inferred (only works if code not minified/obfuscated)
3748 *   $injector.invoke(function(serviceA){});
3749 *
3750 *   // annotated
3751 *   function explicit(serviceA) {};
3752 *   explicit.$inject = ['serviceA'];
3753 *   $injector.invoke(explicit);
3754 *
3755 *   // inline
3756 *   $injector.invoke(['serviceA', function(serviceA){}]);
3757 * ```
3758 *
3759 * ## Inference
3760 *
3761 * In JavaScript calling `toString()` on a function returns the function definition. The definition
3762 * can then be parsed and the function arguments can be extracted. This method of discovering
3763 * annotations is disallowed when the injector is in strict mode.
3764 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3765 * argument names.
3766 *
3767 * ## `$inject` Annotation
3768 * By adding an `$inject` property onto a function the injection parameters can be specified.
3769 *
3770 * ## Inline
3771 * As an array of injection names, where the last item in the array is the function to call.
3772 */
3773
3774/**
3775 * @ngdoc method
3776 * @name $injector#get
3777 *
3778 * @description
3779 * Return an instance of the service.
3780 *
3781 * @param {string} name The name of the instance to retrieve.
3782 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
3783 * @return {*} The instance.
3784 */
3785
3786/**
3787 * @ngdoc method
3788 * @name $injector#invoke
3789 *
3790 * @description
3791 * Invoke the method and supply the method arguments from the `$injector`.
3792 *
3793 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
3794 *   injected according to the {@link guide/di $inject Annotation} rules.
3795 * @param {Object=} self The `this` for the invoked method.
3796 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3797 *                         object first, before the `$injector` is consulted.
3798 * @returns {*} the value returned by the invoked `fn` function.
3799 */
3800
3801/**
3802 * @ngdoc method
3803 * @name $injector#has
3804 *
3805 * @description
3806 * Allows the user to query if the particular service exists.
3807 *
3808 * @param {string} name Name of the service to query.
3809 * @returns {boolean} `true` if injector has given service.
3810 */
3811
3812/**
3813 * @ngdoc method
3814 * @name $injector#instantiate
3815 * @description
3816 * Create a new instance of JS type. The method takes a constructor function, invokes the new
3817 * operator, and supplies all of the arguments to the constructor function as specified by the
3818 * constructor annotation.
3819 *
3820 * @param {Function} Type Annotated constructor function.
3821 * @param {Object=} locals Optional object. If preset then any argument names are read from this
3822 * object first, before the `$injector` is consulted.
3823 * @returns {Object} new instance of `Type`.
3824 */
3825
3826/**
3827 * @ngdoc method
3828 * @name $injector#annotate
3829 *
3830 * @description
3831 * Returns an array of service names which the function is requesting for injection. This API is
3832 * used by the injector to determine which services need to be injected into the function when the
3833 * function is invoked. There are three ways in which the function can be annotated with the needed
3834 * dependencies.
3835 *
3836 * # Argument names
3837 *
3838 * The simplest form is to extract the dependencies from the arguments of the function. This is done
3839 * by converting the function into a string using `toString()` method and extracting the argument
3840 * names.
3841 * ```js
3842 *   // Given
3843 *   function MyController($scope, $route) {
3844 *     // ...
3845 *   }
3846 *
3847 *   // Then
3848 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3849 * ```
3850 *
3851 * You can disallow this method by using strict injection mode.
3852 *
3853 * This method does not work with code minification / obfuscation. For this reason the following
3854 * annotation strategies are supported.
3855 *
3856 * # The `$inject` property
3857 *
3858 * If a function has an `$inject` property and its value is an array of strings, then the strings
3859 * represent names of services to be injected into the function.
3860 * ```js
3861 *   // Given
3862 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3863 *     // ...
3864 *   }
3865 *   // Define function dependencies
3866 *   MyController['$inject'] = ['$scope', '$route'];
3867 *
3868 *   // Then
3869 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3870 * ```
3871 *
3872 * # The array notation
3873 *
3874 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3875 * is very inconvenient. In these situations using the array notation to specify the dependencies in
3876 * a way that survives minification is a better choice:
3877 *
3878 * ```js
3879 *   // We wish to write this (not minification / obfuscation safe)
3880 *   injector.invoke(function($compile, $rootScope) {
3881 *     // ...
3882 *   });
3883 *
3884 *   // We are forced to write break inlining
3885 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3886 *     // ...
3887 *   };
3888 *   tmpFn.$inject = ['$compile', '$rootScope'];
3889 *   injector.invoke(tmpFn);
3890 *
3891 *   // To better support inline function the inline annotation is supported
3892 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3893 *     // ...
3894 *   }]);
3895 *
3896 *   // Therefore
3897 *   expect(injector.annotate(
3898 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3899 *    ).toEqual(['$compile', '$rootScope']);
3900 * ```
3901 *
3902 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3903 * be retrieved as described above.
3904 *
3905 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3906 *
3907 * @returns {Array.<string>} The names of the services which the function requires.
3908 */
3909
3910
3911
3912
3913/**
3914 * @ngdoc service
3915 * @name $provide
3916 *
3917 * @description
3918 *
3919 * The {@link auto.$provide $provide} service has a number of methods for registering components
3920 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3921 * {@link angular.Module}.
3922 *
3923 * An Angular **service** is a singleton object created by a **service factory**.  These **service
3924 * factories** are functions which, in turn, are created by a **service provider**.
3925 * The **service providers** are constructor functions. When instantiated they must contain a
3926 * property called `$get`, which holds the **service factory** function.
3927 *
3928 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3929 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3930 * function to get the instance of the **service**.
3931 *
3932 * Often services have no configuration options and there is no need to add methods to the service
3933 * provider.  The provider will be no more than a constructor function with a `$get` property. For
3934 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3935 * services without specifying a provider.
3936 *
3937 * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3938 *     {@link auto.$injector $injector}
3939 * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3940 *     providers and services.
3941 * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3942 *     services, not providers.
3943 * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3944 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3945 *     given factory function.
3946 * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3947 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3948 *      a new object using the given constructor function.
3949 *
3950 * See the individual methods for more information and examples.
3951 */
3952
3953/**
3954 * @ngdoc method
3955 * @name $provide#provider
3956 * @description
3957 *
3958 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3959 * are constructor functions, whose instances are responsible for "providing" a factory for a
3960 * service.
3961 *
3962 * Service provider names start with the name of the service they provide followed by `Provider`.
3963 * For example, the {@link ng.$log $log} service has a provider called
3964 * {@link ng.$logProvider $logProvider}.
3965 *
3966 * Service provider objects can have additional methods which allow configuration of the provider
3967 * and its service. Importantly, you can configure what kind of service is created by the `$get`
3968 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3969 * method {@link ng.$logProvider#debugEnabled debugEnabled}
3970 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3971 * console or not.
3972 *
3973 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3974                        'Provider'` key.
3975 * @param {(Object|function())} provider If the provider is:
3976 *
3977 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3978 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3979 *   - `Constructor`: a new instance of the provider will be created using
3980 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3981 *
3982 * @returns {Object} registered provider instance
3983
3984 * @example
3985 *
3986 * The following example shows how to create a simple event tracking service and register it using
3987 * {@link auto.$provide#provider $provide.provider()}.
3988 *
3989 * ```js
3990 *  // Define the eventTracker provider
3991 *  function EventTrackerProvider() {
3992 *    var trackingUrl = '/track';
3993 *
3994 *    // A provider method for configuring where the tracked events should been saved
3995 *    this.setTrackingUrl = function(url) {
3996 *      trackingUrl = url;
3997 *    };
3998 *
3999 *    // The service factory function
4000 *    this.$get = ['$http', function($http) {
4001 *      var trackedEvents = {};
4002 *      return {
4003 *        // Call this to track an event
4004 *        event: function(event) {
4005 *          var count = trackedEvents[event] || 0;
4006 *          count += 1;
4007 *          trackedEvents[event] = count;
4008 *          return count;
4009 *        },
4010 *        // Call this to save the tracked events to the trackingUrl
4011 *        save: function() {
4012 *          $http.post(trackingUrl, trackedEvents);
4013 *        }
4014 *      };
4015 *    }];
4016 *  }
4017 *
4018 *  describe('eventTracker', function() {
4019 *    var postSpy;
4020 *
4021 *    beforeEach(module(function($provide) {
4022 *      // Register the eventTracker provider
4023 *      $provide.provider('eventTracker', EventTrackerProvider);
4024 *    }));
4025 *
4026 *    beforeEach(module(function(eventTrackerProvider) {
4027 *      // Configure eventTracker provider
4028 *      eventTrackerProvider.setTrackingUrl('/custom-track');
4029 *    }));
4030 *
4031 *    it('tracks events', inject(function(eventTracker) {
4032 *      expect(eventTracker.event('login')).toEqual(1);
4033 *      expect(eventTracker.event('login')).toEqual(2);
4034 *    }));
4035 *
4036 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
4037 *      postSpy = spyOn($http, 'post');
4038 *      eventTracker.event('login');
4039 *      eventTracker.save();
4040 *      expect(postSpy).toHaveBeenCalled();
4041 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4042 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4043 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4044 *    }));
4045 *  });
4046 * ```
4047 */
4048
4049/**
4050 * @ngdoc method
4051 * @name $provide#factory
4052 * @description
4053 *
4054 * Register a **service factory**, which will be called to return the service instance.
4055 * This is short for registering a service where its provider consists of only a `$get` property,
4056 * which is the given service factory function.
4057 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4058 * configure your service in a provider.
4059 *
4060 * @param {string} name The name of the instance.
4061 * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4062 *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4063 * @returns {Object} registered provider instance
4064 *
4065 * @example
4066 * Here is an example of registering a service
4067 * ```js
4068 *   $provide.factory('ping', ['$http', function($http) {
4069 *     return function ping() {
4070 *       return $http.send('/ping');
4071 *     };
4072 *   }]);
4073 * ```
4074 * You would then inject and use this service like this:
4075 * ```js
4076 *   someModule.controller('Ctrl', ['ping', function(ping) {
4077 *     ping();
4078 *   }]);
4079 * ```
4080 */
4081
4082
4083/**
4084 * @ngdoc method
4085 * @name $provide#service
4086 * @description
4087 *
4088 * Register a **service constructor**, which will be invoked with `new` to create the service
4089 * instance.
4090 * This is short for registering a service where its provider's `$get` property is the service
4091 * constructor function that will be used to instantiate the service instance.
4092 *
4093 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4094 * as a type/class.
4095 *
4096 * @param {string} name The name of the instance.
4097 * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4098 *     that will be instantiated.
4099 * @returns {Object} registered provider instance
4100 *
4101 * @example
4102 * Here is an example of registering a service using
4103 * {@link auto.$provide#service $provide.service(class)}.
4104 * ```js
4105 *   var Ping = function($http) {
4106 *     this.$http = $http;
4107 *   };
4108 *
4109 *   Ping.$inject = ['$http'];
4110 *
4111 *   Ping.prototype.send = function() {
4112 *     return this.$http.get('/ping');
4113 *   };
4114 *   $provide.service('ping', Ping);
4115 * ```
4116 * You would then inject and use this service like this:
4117 * ```js
4118 *   someModule.controller('Ctrl', ['ping', function(ping) {
4119 *     ping.send();
4120 *   }]);
4121 * ```
4122 */
4123
4124
4125/**
4126 * @ngdoc method
4127 * @name $provide#value
4128 * @description
4129 *
4130 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4131 * number, an array, an object or a function.  This is short for registering a service where its
4132 * provider's `$get` property is a factory function that takes no arguments and returns the **value
4133 * service**.
4134 *
4135 * Value services are similar to constant services, except that they cannot be injected into a
4136 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4137 * an Angular
4138 * {@link auto.$provide#decorator decorator}.
4139 *
4140 * @param {string} name The name of the instance.
4141 * @param {*} value The value.
4142 * @returns {Object} registered provider instance
4143 *
4144 * @example
4145 * Here are some examples of creating value services.
4146 * ```js
4147 *   $provide.value('ADMIN_USER', 'admin');
4148 *
4149 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4150 *
4151 *   $provide.value('halfOf', function(value) {
4152 *     return value / 2;
4153 *   });
4154 * ```
4155 */
4156
4157
4158/**
4159 * @ngdoc method
4160 * @name $provide#constant
4161 * @description
4162 *
4163 * Register a **constant service**, such as a string, a number, an array, an object or a function,
4164 * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
4165 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4166 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4167 *
4168 * @param {string} name The name of the constant.
4169 * @param {*} value The constant value.
4170 * @returns {Object} registered instance
4171 *
4172 * @example
4173 * Here a some examples of creating constants:
4174 * ```js
4175 *   $provide.constant('SHARD_HEIGHT', 306);
4176 *
4177 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4178 *
4179 *   $provide.constant('double', function(value) {
4180 *     return value * 2;
4181 *   });
4182 * ```
4183 */
4184
4185
4186/**
4187 * @ngdoc method
4188 * @name $provide#decorator
4189 * @description
4190 *
4191 * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
4192 * intercepts the creation of a service, allowing it to override or modify the behaviour of the
4193 * service. The object returned by the decorator may be the original service, or a new service
4194 * object which replaces or wraps and delegates to the original service.
4195 *
4196 * @param {string} name The name of the service to decorate.
4197 * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4198 *    instantiated and should return the decorated service instance. The function is called using
4199 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4200 *    Local injection arguments:
4201 *
4202 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
4203 *      decorated or delegated to.
4204 *
4205 * @example
4206 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4207 * calls to {@link ng.$log#error $log.warn()}.
4208 * ```js
4209 *   $provide.decorator('$log', ['$delegate', function($delegate) {
4210 *     $delegate.warn = $delegate.error;
4211 *     return $delegate;
4212 *   }]);
4213 * ```
4214 */
4215
4216
4217function createInjector(modulesToLoad, strictDi) {
4218  strictDi = (strictDi === true);
4219  var INSTANTIATING = {},
4220      providerSuffix = 'Provider',
4221      path = [],
4222      loadedModules = new HashMap([], true),
4223      providerCache = {
4224        $provide: {
4225            provider: supportObject(provider),
4226            factory: supportObject(factory),
4227            service: supportObject(service),
4228            value: supportObject(value),
4229            constant: supportObject(constant),
4230            decorator: decorator
4231          }
4232      },
4233      providerInjector = (providerCache.$injector =
4234          createInternalInjector(providerCache, function(serviceName, caller) {
4235            if (angular.isString(caller)) {
4236              path.push(caller);
4237            }
4238            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4239          })),
4240      instanceCache = {},
4241      instanceInjector = (instanceCache.$injector =
4242          createInternalInjector(instanceCache, function(serviceName, caller) {
4243            var provider = providerInjector.get(serviceName + providerSuffix, caller);
4244            return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
4245          }));
4246
4247
4248  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
4249
4250  return instanceInjector;
4251
4252  ////////////////////////////////////
4253  // $provider
4254  ////////////////////////////////////
4255
4256  function supportObject(delegate) {
4257    return function(key, value) {
4258      if (isObject(key)) {
4259        forEach(key, reverseParams(delegate));
4260      } else {
4261        return delegate(key, value);
4262      }
4263    };
4264  }
4265
4266  function provider(name, provider_) {
4267    assertNotHasOwnProperty(name, 'service');
4268    if (isFunction(provider_) || isArray(provider_)) {
4269      provider_ = providerInjector.instantiate(provider_);
4270    }
4271    if (!provider_.$get) {
4272      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4273    }
4274    return providerCache[name + providerSuffix] = provider_;
4275  }
4276
4277  function enforceReturnValue(name, factory) {
4278    return function enforcedReturnValue() {
4279      var result = instanceInjector.invoke(factory, this);
4280      if (isUndefined(result)) {
4281        throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4282      }
4283      return result;
4284    };
4285  }
4286
4287  function factory(name, factoryFn, enforce) {
4288    return provider(name, {
4289      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4290    });
4291  }
4292
4293  function service(name, constructor) {
4294    return factory(name, ['$injector', function($injector) {
4295      return $injector.instantiate(constructor);
4296    }]);
4297  }
4298
4299  function value(name, val) { return factory(name, valueFn(val), false); }
4300
4301  function constant(name, value) {
4302    assertNotHasOwnProperty(name, 'constant');
4303    providerCache[name] = value;
4304    instanceCache[name] = value;
4305  }
4306
4307  function decorator(serviceName, decorFn) {
4308    var origProvider = providerInjector.get(serviceName + providerSuffix),
4309        orig$get = origProvider.$get;
4310
4311    origProvider.$get = function() {
4312      var origInstance = instanceInjector.invoke(orig$get, origProvider);
4313      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4314    };
4315  }
4316
4317  ////////////////////////////////////
4318  // Module Loading
4319  ////////////////////////////////////
4320  function loadModules(modulesToLoad) {
4321    var runBlocks = [], moduleFn;
vendor: 5,290 bytes, lines 4322-4479
4322    forEach(modulesToLoad, function(module) {
4323      if (loadedModules.get(module)) return;
4324      loadedModules.put(module, true);
4325
4326      function runInvokeQueue(queue) {
4327        var i, ii;
4328        for (i = 0, ii = queue.length; i < ii; i++) {
4329          var invokeArgs = queue[i],
4330              provider = providerInjector.get(invokeArgs[0]);
4331
4332          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4333        }
4334      }
4335
4336      try {
4337        if (isString(module)) {
4338          moduleFn = angularModule(module);
4339          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4340          runInvokeQueue(moduleFn._invokeQueue);
4341          runInvokeQueue(moduleFn._configBlocks);
4342        } else if (isFunction(module)) {
4343            runBlocks.push(providerInjector.invoke(module));
4344        } else if (isArray(module)) {
4345            runBlocks.push(providerInjector.invoke(module));
4346        } else {
4347          assertArgFn(module, 'module');
4348        }
4349      } catch (e) {
4350        if (isArray(module)) {
4351          module = module[module.length - 1];
4352        }
4353        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4354          // Safari & FF's stack traces don't contain error.message content
4355          // unlike those of Chrome and IE
4356          // So if stack doesn't contain message, we create a new string that contains both.
4357          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4358          /* jshint -W022 */
4359          e = e.message + '\n' + e.stack;
4360        }
4361        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4362                  module, e.stack || e.message || e);
4363      }
4364    });
4365    return runBlocks;
4366  }
4367
4368  ////////////////////////////////////
4369  // internal Injector
4370  ////////////////////////////////////
4371
4372  function createInternalInjector(cache, factory) {
4373
4374    function getService(serviceName, caller) {
4375      if (cache.hasOwnProperty(serviceName)) {
4376        if (cache[serviceName] === INSTANTIATING) {
4377          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4378                    serviceName + ' <- ' + path.join(' <- '));
4379        }
4380        return cache[serviceName];
4381      } else {
4382        try {
4383          path.unshift(serviceName);
4384          cache[serviceName] = INSTANTIATING;
4385          return cache[serviceName] = factory(serviceName, caller);
4386        } catch (err) {
4387          if (cache[serviceName] === INSTANTIATING) {
4388            delete cache[serviceName];
4389          }
4390          throw err;
4391        } finally {
4392          path.shift();
4393        }
4394      }
4395    }
4396
4397    function invoke(fn, self, locals, serviceName) {
4398      if (typeof locals === 'string') {
4399        serviceName = locals;
4400        locals = null;
4401      }
4402
4403      var args = [],
4404          $inject = createInjector.$$annotate(fn, strictDi, serviceName),
4405          length, i,
4406          key;
4407
4408      for (i = 0, length = $inject.length; i < length; i++) {
4409        key = $inject[i];
4410        if (typeof key !== 'string') {
4411          throw $injectorMinErr('itkn',
4412                  'Incorrect injection token! Expected service name as string, got {0}', key);
4413        }
4414        args.push(
4415          locals && locals.hasOwnProperty(key)
4416          ? locals[key]
4417          : getService(key, serviceName)
4418        );
4419      }
4420      if (isArray(fn)) {
4421        fn = fn[length];
4422      }
4423
4424      // http://jsperf.com/angularjs-invoke-apply-vs-switch
4425      // #5388
4426      return fn.apply(self, args);
4427    }
4428
4429    function instantiate(Type, locals, serviceName) {
4430      // Check if Type is annotated and use just the given function at n-1 as parameter
4431      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4432      // Object creation: http://jsperf.com/create-constructor/2
4433      var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
4434      var returnedValue = invoke(Type, instance, locals, serviceName);
4435
4436      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4437    }
4438
4439    return {
4440      invoke: invoke,
4441      instantiate: instantiate,
4442      get: getService,
4443      annotate: createInjector.$$annotate,
4444      has: function(name) {
4445        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4446      }
4447    };
4448  }
4449}
4450
4451createInjector.$$annotate = annotate;
4452
4453/**
4454 * @ngdoc provider
4455 * @name $anchorScrollProvider
4456 *
4457 * @description
4458 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4459 * {@link ng.$location#hash $location.hash()} changes.
4460 */
4461function $AnchorScrollProvider() {
4462
4463  var autoScrollingEnabled = true;
4464
4465  /**
4466   * @ngdoc method
4467   * @name $anchorScrollProvider#disableAutoScrolling
4468   *
4469   * @description
4470   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4471   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4472   * Use this method to disable automatic scrolling.
4473   *
4474   * If automatic scrolling is disabled, one must explicitly call
4475   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4476   * current hash.
4477   */
4478  this.disableAutoScrolling = function() {
4479    autoScrollingEnabled = false;
4480  };
4481
4482  /**
4483   * @ngdoc service
4484   * @name $anchorScroll
4485   * @kind function
4486   * @requires $window
4487   * @requires $location
4488   * @requires $rootScope
4489   *
4490   * @description
4491   * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4492   * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4493   * in the
4494   * [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4495   *
4496   * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4497   * match any anchor whenever it changes. This can be disabled by calling
4498   * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4499   *
4500   * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4501   * vertical scroll-offset (either fixed or dynamic).
4502   *
4503   * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4504   *                       {@link ng.$location#hash $location.hash()} will be used.
4505   *
4506   * @property {(number|function|jqLite)} yOffset
4507   * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4508   * positioned elements at the top of the page, such as navbars, headers etc.
4509   *
4510   * `yOffset` can be specified in various ways:
4511   * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4512   * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4513   *   a number representing the offset (in pixels).<br /><br />
4514   * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4515   *   the top of the page to the element's bottom will be used as offset.<br />
4516   *   **Note**: The element will be taken into account only as long as its `position` is set to
4517   *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4518   *   their height and/or positioning according to the viewport's size.
4519   *
4520   * <br />
4521   * <div class="alert alert-warning">
4522   * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4523   * not some child element.
4524   * </div>
4525   *
4526   * @example
4527     <example module="anchorScrollExample">
4528       <file name="index.html">
4529         <div id="scrollArea" ng-controller="ScrollController">
4530           <a ng-click="gotoBottom()">Go to bottom</a>
4531           <a id="bottom"></a> You're at the bottom!
4532         </div>
4533       </file>
4534       <file name="script.js">
4535         angular.module('anchorScrollExample', [])
4536           .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4537             function ($scope, $location, $anchorScroll) {
4538               $scope.gotoBottom = function() {
4539                 // set the location.hash to the id of
4540                 // the element you wish to scroll to.
4541                 $location.hash('bottom');
4542
4543                 // call $anchorScroll()
4544                 $anchorScroll();
4545               };
4546             }]);
4547       </file>
4548       <file name="style.css">
4549         #scrollArea {
4550           height: 280px;
4551           overflow: auto;
4552         }
4553
4554         #bottom {
4555           display: block;
4556           margin-top: 2000px;
4557         }
4558       </file>
4559     </example>
4560   *
4561   * <hr />
4562   * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4563   * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4564   *
4565   * @example
4566     <example module="anchorScrollOffsetExample">
4567       <file name="index.html">
4568         <div class="fixed-header" ng-controller="headerCtrl">
4569           <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4570             Go to anchor {{x}}
4571           </a>
4572         </div>
4573         <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4574           Anchor {{x}} of 5
4575         </div>
4576       </file>
4577       <file name="script.js">
4578         angular.module('anchorScrollOffsetExample', [])
4579           .run(['$anchorScroll', function($anchorScroll) {
4580             $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
4581           }])
4582           .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4583             function ($anchorScroll, $location, $scope) {
4584               $scope.gotoAnchor = function(x) {
4585                 var newHash = 'anchor' + x;
4586                 if ($location.hash() !== newHash) {
4587                   // set the $location.hash to `newHash` and
4588                   // $anchorScroll will automatically scroll to it
4589                   $location.hash('anchor' + x);
4590                 } else {
4591                   // call $anchorScroll() explicitly,
4592                   // since $location.hash hasn't changed
4593                   $anchorScroll();
4594                 }
4595               };
4596             }
4597           ]);
4598       </file>
4599       <file name="style.css">
4600         body {
4601           padding-top: 50px;
4602         }
4603
4604         .anchor {
4605           border: 2px dashed DarkOrchid;
4606           padding: 10px 10px 200px 10px;
4607         }
4608
4609         .fixed-header {
4610           background-color: rgba(0, 0, 0, 0.2);
4611           height: 50px;
4612           position: fixed;
4613           top: 0; left: 0; right: 0;
4614         }
4615
4616         .fixed-header > a {
4617           display: inline-block;
4618           margin: 5px 15px;
4619         }
4620       </file>
4621     </example>
4622   */
4623  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4624    var document = $window.document;
4625
4626    // Helper function to get first anchor from a NodeList
4627    // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4628    //  and working in all supported browsers.)
4629    function getFirstAnchor(list) {
4630      var result = null;
4631      Array.prototype.some.call(list, function(element) {
4632        if (nodeName_(element) === 'a') {
4633          result = element;
4634          return true;
4635        }
4636      });
4637      return result;
4638    }
4639
4640    function getYOffset() {
4641
4642      var offset = scroll.yOffset;
4643
4644      if (isFunction(offset)) {
4645        offset = offset();
4646      } else if (isElement(offset)) {
4647        var elem = offset[0];
4648        var style = $window.getComputedStyle(elem);
4649        if (style.position !== 'fixed') {
4650          offset = 0;
4651        } else {
4652          offset = elem.getBoundingClientRect().bottom;
4653        }
4654      } else if (!isNumber(offset)) {
4655        offset = 0;
4656      }
4657
4658      return offset;
4659    }
4660
4661    function scrollTo(elem) {
4662      if (elem) {
4663        elem.scrollIntoView();
4664
4665        var offset = getYOffset();
4666
4667        if (offset) {
4668          // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4669          // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4670          // top of the viewport.
4671          //
4672          // IF the number of pixels from the top of `elem` to the end of the page's content is less
4673          // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4674          // way down the page.
4675          //
4676          // This is often the case for elements near the bottom of the page.
4677          //
4678          // In such cases we do not need to scroll the whole `offset` up, just the difference between
4679          // the top of the element and the offset, which is enough to align the top of `elem` at the
4680          // desired position.
4681          var elemTop = elem.getBoundingClientRect().top;
4682          $window.scrollBy(0, elemTop - offset);
4683        }
4684      } else {
4685        $window.scrollTo(0, 0);
4686      }
4687    }
4688
4689    function scroll(hash) {
4690      hash = isString(hash) ? hash : $location.hash();
4691      var elm;
4692
4693      // empty hash, scroll to the top of the page
4694      if (!hash) scrollTo(null);
4695
4696      // element with given id
4697      else if ((elm = document.getElementById(hash))) scrollTo(elm);
4698
4699      // first anchor with given name :-D
4700      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4701
4702      // no element and hash == 'top', scroll to the top of the page
4703      else if (hash === 'top') scrollTo(null);
4704    }
4705
4706    // does not scroll when user clicks on anchor link that is currently on
4707    // (no url change, no $location.hash() change), browser native does scroll
4708    if (autoScrollingEnabled) {
4709      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
4710        function autoScrollWatchAction(newVal, oldVal) {
4711          // skip the initial scroll if $location.hash is empty
4712          if (newVal === oldVal && newVal === '') return;
4713
4714          jqLiteDocumentLoaded(function() {
4715            $rootScope.$evalAsync(scroll);
4716          });
4717        });
4718    }
4719
4720    return scroll;
4721  }];
4722}
4723
4724var $animateMinErr = minErr('$animate');
4725var ELEMENT_NODE = 1;
4726var NG_ANIMATE_CLASSNAME = 'ng-animate';
4727
4728function mergeClasses(a,b) {
4729  if (!a && !b) return '';
4730  if (!a) return b;
4731  if (!b) return a;
4732  if (isArray(a)) a = a.join(' ');
4733  if (isArray(b)) b = b.join(' ');
4734  return a + ' ' + b;
4735}
4736
4737function extractElementNode(element) {
4738  for (var i = 0; i < element.length; i++) {
4739    var elm = element[i];
4740    if (elm.nodeType === ELEMENT_NODE) {
4741      return elm;
4742    }
4743  }
4744}
4745
4746function splitClasses(classes) {
4747  if (isString(classes)) {
4748    classes = classes.split(' ');
4749  }
4750
4751  // Use createMap() to prevent class assumptions involving property names in
4752  // Object.prototype
4753  var obj = createMap();
4754  forEach(classes, function(klass) {
4755    // sometimes the split leaves empty string values
4756    // incase extra spaces were applied to the options
4757    if (klass.length) {
4758      obj[klass] = true;
4759    }
4760  });
4761  return obj;
4762}
4763
4764// if any other type of options value besides an Object value is
4765// passed into the $animate.method() animation then this helper code
4766// will be run which will ignore it. While this patch is not the
4767// greatest solution to this, a lot of existing plugins depend on
4768// $animate to either call the callback (< 1.2) or return a promise
4769// that can be changed. This helper function ensures that the options
4770// are wiped clean incase a callback function is provided.
4771function prepareAnimateOptions(options) {
4772  return isObject(options)
4773      ? options
4774      : {};
4775}
4776
4777var $$CoreAnimateRunnerProvider = function() {
4778  this.$get = ['$q', '$$rAF', function($q, $$rAF) {
4779    function AnimateRunner() {}
4780    AnimateRunner.all = noop;
4781    AnimateRunner.chain = noop;
4782    AnimateRunner.prototype = {
4783      end: noop,
4784      cancel: noop,
4785      resume: noop,
4786      pause: noop,
4787      complete: noop,
4788      then: function(pass, fail) {
4789        return $q(function(resolve) {
4790          $$rAF(function() {
4791            resolve();
4792          });
4793        }).then(pass, fail);
4794      }
4795    };
4796    return AnimateRunner;
4797  }];
4798};
4799
4800// this is prefixed with Core since it conflicts with
4801// the animateQueueProvider defined in ngAnimate/animateQueue.js
4802var $$CoreAnimateQueueProvider = function() {
4803  var postDigestQueue = new HashMap();
4804  var postDigestElements = [];
4805
4806  this.$get = ['$$AnimateRunner', '$rootScope',
4807       function($$AnimateRunner,   $rootScope) {
4808    return {
4809      enabled: noop,
4810      on: noop,
4811      off: noop,
4812      pin: noop,
4813
4814      push: function(element, event, options, domOperation) {
4815        domOperation        && domOperation();
4816
4817        options = options || {};
4818        options.from        && element.css(options.from);
4819        options.to          && element.css(options.to);
4820
4821        if (options.addClass || options.removeClass) {
4822          addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
4823        }
4824
4825        return new $$AnimateRunner(); // jshint ignore:line
4826      }
4827    };
4828
4829    function addRemoveClassesPostDigest(element, add, remove) {
4830      var data = postDigestQueue.get(element);
4831      var classVal;
4832
4833      if (!data) {
4834        postDigestQueue.put(element, data = {});
4835        postDigestElements.push(element);
4836      }
4837
4838      if (add) {
4839        forEach(add.split(' '), function(className) {
4840          if (className) {
4841            data[className] = true;
4842          }
4843        });
4844      }
4845
4846      if (remove) {
4847        forEach(remove.split(' '), function(className) {
4848          if (className) {
4849            data[className] = false;
4850          }
4851        });
4852      }
4853
4854      if (postDigestElements.length > 1) return;
4855
4856      $rootScope.$$postDigest(function() {
4857        forEach(postDigestElements, function(element) {
4858          var data = postDigestQueue.get(element);
4859          if (data) {
4860            var existing = splitClasses(element.attr('class'));
4861            var toAdd = '';
4862            var toRemove = '';
4863            forEach(data, function(status, className) {
4864              var hasClass = !!existing[className];
4865              if (status !== hasClass) {
4866                if (status) {
4867                  toAdd += (toAdd.length ? ' ' : '') + className;
4868                } else {
4869                  toRemove += (toRemove.length ? ' ' : '') + className;
4870                }
4871              }
4872            });
4873
4874            forEach(element, function(elm) {
4875              toAdd    && jqLiteAddClass(elm, toAdd);
4876              toRemove && jqLiteRemoveClass(elm, toRemove);
4877            });
4878            postDigestQueue.remove(element);
4879          }
4880        });
4881
4882        postDigestElements.length = 0;
4883      });
4884    }
4885  }];
4886};
4887
4888/**
4889 * @ngdoc provider
4890 * @name $animateProvider
4891 *
4892 * @description
4893 * Default implementation of $animate that doesn't perform any animations, instead just
4894 * synchronously performs DOM updates and resolves the returned runner promise.
4895 *
4896 * In order to enable animations the `ngAnimate` module has to be loaded.
4897 *
4898 * To see the functional implementation check out `src/ngAnimate/animate.js`.
4899 */
4900var $AnimateProvider = ['$provide', function($provide) {
4901  var provider = this;
4902
4903  this.$$registeredAnimations = Object.create(null);
4904
4905   /**
4906   * @ngdoc method
4907   * @name $animateProvider#register
4908   *
4909   * @description
4910   * Registers a new injectable animation factory function. The factory function produces the
4911   * animation object which contains callback functions for each event that is expected to be
4912   * animated.
4913   *
4914   *   * `eventFn`: `function(element, ... , doneFunction, options)`
4915   *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
4916   *   on the type of animation additional arguments will be injected into the animation function. The
4917   *   list below explains the function signatures for the different animation methods:
4918   *
4919   *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
4920   *   - addClass: function(element, addedClasses, doneFunction, options)
4921   *   - removeClass: function(element, removedClasses, doneFunction, options)
4922   *   - enter, leave, move: function(element, doneFunction, options)
4923   *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
4924   *
4925   *   Make sure to trigger the `doneFunction` once the animation is fully complete.
4926   *
4927   * ```js
4928   *   return {
4929   *     //enter, leave, move signature
4930   *     eventFn : function(element, done, options) {
4931   *       //code to run the animation
4932   *       //once complete, then run done()
4933   *       return function endFunction(wasCancelled) {
4934   *         //code to cancel the animation
4935   *       }
4936   *     }
4937   *   }
4938   * ```
4939   *
4940   * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
4941   * @param {Function} factory The factory function that will be executed to return the animation
4942   *                           object.
4943   */
4944  this.register = function(name, factory) {
4945    if (name && name.charAt(0) !== '.') {
4946      throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
4947    }
4948
4949    var key = name + '-animation';
4950    provider.$$registeredAnimations[name.substr(1)] = key;
4951    $provide.factory(key, factory);
4952  };
4953
4954  /**
4955   * @ngdoc method
4956   * @name $animateProvider#classNameFilter
4957   *
4958   * @description
4959   * Sets and/or returns the CSS class regular expression that is checked when performing
4960   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4961   * therefore enable $animate to attempt to perform an animation on any element that is triggered.
4962   * When setting the `classNameFilter` value, animations will only be performed on elements
4963   * that successfully match the filter expression. This in turn can boost performance
4964   * for low-powered devices as well as applications containing a lot of structural operations.
4965   * @param {RegExp=} expression The className expression which will be checked against all animations
4966   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4967   */
4968  this.classNameFilter = function(expression) {
4969    if (arguments.length === 1) {
4970      this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4971      if (this.$$classNameFilter) {
4972        var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
4973        if (reservedRegex.test(this.$$classNameFilter.toString())) {
4974          throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
4975
4976        }
4977      }
4978    }
4979    return this.$$classNameFilter;
4980  };
4981
4982  this.$get = ['$$animateQueue', function($$animateQueue) {
4983    function domInsert(element, parentElement, afterElement) {
4984      // if for some reason the previous element was removed
4985      // from the dom sometime before this code runs then let's
4986      // just stick to using the parent element as the anchor
4987      if (afterElement) {
4988        var afterNode = extractElementNode(afterElement);
4989        if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
4990          afterElement = null;
4991        }
4992      }
4993      afterElement ? afterElement.after(element) : parentElement.prepend(element);
4994    }
4995
4996    /**
4997     * @ngdoc service
4998     * @name $animate
4999     * @description The $animate service exposes a series of DOM utility methods that provide support
5000     * for animation hooks. The default behavior is the application of DOM operations, however,
5001     * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5002     * to ensure that animation runs with the triggered DOM operation.
5003     *
5004     * By default $animate doesn't trigger an animations. This is because the `ngAnimate` module isn't
5005     * included and only when it is active then the animation hooks that `$animate` triggers will be
5006     * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5007     * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
5008     * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
5009     *
5010     * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
5011     *
5012     * To learn more about enabling animation support, click here to visit the
5013     * {@link ngAnimate ngAnimate module page}.
5014     */
5015    return {
5016      // we don't call it directly since non-existant arguments may
5017      // be interpreted as null within the sub enabled function
5018
5019      /**
5020       *
5021       * @ngdoc method
5022       * @name $animate#on
5023       * @kind function
5024       * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
5025       *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
5026       *    is fired with the following params:
5027       *
5028       * ```js
5029       * $animate.on('enter', container,
5030       *    function callback(element, phase) {
5031       *      // cool we detected an enter animation within the container
5032       *    }
5033       * );
5034       * ```
5035       *
5036       * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
5037       * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
5038       *     as well as among its children
5039       * @param {Function} callback the callback function that will be fired when the listener is triggered
5040       *
5041       * The arguments present in the callback function are:
5042       * * `element` - The captured DOM element that the animation was fired on.
5043       * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
5044       */
5045      on: $$animateQueue.on,
5046
5047      /**
5048       *
5049       * @ngdoc method
5050       * @name $animate#off
5051       * @kind function
5052       * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
5053       * can be used in three different ways depending on the arguments:
5054       *
5055       * ```js
5056       * // remove all the animation event listeners listening for `enter`
5057       * $animate.off('enter');
5058       *
5059       * // remove all the animation event listeners listening for `enter` on the given element and its children
5060       * $animate.off('enter', container);
5061       *
5062       * // remove the event listener function provided by `listenerFn` that is set
5063       * // to listen for `enter` on the given `element` as well as its children
5064       * $animate.off('enter', container, callback);
5065       * ```
5066       *
5067       * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
5068       * @param {DOMElement=} container the container element the event listener was placed on
5069       * @param {Function=} callback the callback function that was registered as the listener
5070       */
5071      off: $$animateQueue.off,
5072
5073      /**
5074       * @ngdoc method
5075       * @name $animate#pin
5076       * @kind function
5077       * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
5078       *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
5079       *    element despite being outside the realm of the application or within another application. Say for example if the application
5080       *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
5081       *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
5082       *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
5083       *
5084       *    Note that this feature is only active when the `ngAnimate` module is used.
5085       *
5086       * @param {DOMElement} element the external element that will be pinned
5087       * @param {DOMElement} parentElement the host parent element that will be associated with the external element
5088       */
5089      pin: $$animateQueue.pin,
5090
5091      /**
5092       *
5093       * @ngdoc method
5094       * @name $animate#enabled
5095       * @kind function
5096       * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
5097       * function can be called in four ways:
5098       *
5099       * ```js
5100       * // returns true or false
5101       * $animate.enabled();
5102       *
5103       * // changes the enabled state for all animations
5104       * $animate.enabled(false);
5105       * $animate.enabled(true);
5106       *
5107       * // returns true or false if animations are enabled for an element
5108       * $animate.enabled(element);
5109       *
5110       * // changes the enabled state for an element and its children
5111       * $animate.enabled(element, true);
5112       * $animate.enabled(element, false);
5113       * ```
5114       *
5115       * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
5116       * @param {boolean=} enabled whether or not the animations will be enabled for the element
5117       *
5118       * @return {boolean} whether or not animations are enabled
5119       */
5120      enabled: $$animateQueue.enabled,
5121
5122      /**
5123       * @ngdoc method
5124       * @name $animate#cancel
5125       * @kind function
5126       * @description Cancels the provided animation.
5127       *
5128       * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
5129       */
5130      cancel: function(runner) {
5131        runner.end && runner.end();
5132      },
5133
5134      /**
5135       *
5136       * @ngdoc method
5137       * @name $animate#enter
5138       * @kind function
5139       * @description Inserts the element into the DOM either after the `after` element (if provided) or
5140       *   as the first child within the `parent` element and then triggers an animation.
5141       *   A promise is returned that will be resolved during the next digest once the animation
5142       *   has completed.
5143       *
5144       * @param {DOMElement} element the element which will be inserted into the DOM
5145       * @param {DOMElement} parent the parent element which will append the element as
5146       *   a child (so long as the after element is not present)
5147       * @param {DOMElement=} after the sibling element after which the element will be appended
5148       * @param {object=} options an optional collection of options/styles that will be applied to the element
5149       *
5150       * @return {Promise} the animation callback promise
5151       */
5152      enter: function(element, parent, after, options) {
5153        parent = parent && jqLite(parent);
5154        after = after && jqLite(after);
5155        parent = parent || after.parent();
5156        domInsert(element, parent, after);
5157        return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
5158      },
5159
5160      /**
5161       *
5162       * @ngdoc method
5163       * @name $animate#move
5164       * @kind function
5165       * @description Inserts (moves) the element into its new position in the DOM either after
5166       *   the `after` element (if provided) or as the first child within the `parent` element
5167       *   and then triggers an animation. A promise is returned that will be resolved
5168       *   during the next digest once the animation has completed.
5169       *
5170       * @param {DOMElement} element the element which will be moved into the new DOM position
5171       * @param {DOMElement} parent the parent element which will append the element as
5172       *   a child (so long as the after element is not present)
5173       * @param {DOMElement=} after the sibling element after which the element will be appended
5174       * @param {object=} options an optional collection of options/styles that will be applied to the element
5175       *
5176       * @return {Promise} the animation callback promise
5177       */
5178      move: function(element, parent, after, options) {
5179        parent = parent && jqLite(parent);
5180        after = after && jqLite(after);
5181        parent = parent || after.parent();
5182        domInsert(element, parent, after);
5183        return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
5184      },
5185
5186      /**
5187       * @ngdoc method
5188       * @name $animate#leave
5189       * @kind function
5190       * @description Triggers an animation and then removes the element from the DOM.
5191       * When the function is called a promise is returned that will be resolved during the next
5192       * digest once the animation has completed.
5193       *
5194       * @param {DOMElement} element the element which will be removed from the DOM
5195       * @param {object=} options an optional collection of options/styles that will be applied to the element
5196       *
5197       * @return {Promise} the animation callback promise
5198       */
5199      leave: function(element, options) {
5200        return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
5201          element.remove();
5202        });
5203      },
5204
5205      /**
5206       * @ngdoc method
5207       * @name $animate#addClass
5208       * @kind function
5209       *
5210       * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
5211       *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
5212       *   animation if element already contains the CSS class or if the class is removed at a later step.
5213       *   Note that class-based animations are treated differently compared to structural animations
5214       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5215       *   depending if CSS or JavaScript animations are used.
5216       *
5217       * @param {DOMElement} element the element which the CSS classes will be applied to
5218       * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
5219       * @param {object=} options an optional collection of options/styles that will be applied to the element
5220       *
5221       * @return {Promise} the animation callback promise
5222       */
5223      addClass: function(element, className, options) {
5224        options = prepareAnimateOptions(options);
5225        options.addClass = mergeClasses(options.addclass, className);
5226        return $$animateQueue.push(element, 'addClass', options);
5227      },
5228
5229      /**
5230       * @ngdoc method
5231       * @name $animate#removeClass
5232       * @kind function
5233       *
5234       * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
5235       *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
5236       *   animation if element does not contain the CSS class or if the class is added at a later step.
5237       *   Note that class-based animations are treated differently compared to structural animations
5238       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
5239       *   depending if CSS or JavaScript animations are used.
5240       *
5241       * @param {DOMElement} element the element which the CSS classes will be applied to
5242       * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
5243       * @param {object=} options an optional collection of options/styles that will be applied to the element
5244       *
5245       * @return {Promise} the animation callback promise
5246       */
5247      removeClass: function(element, className, options) {
5248        options = prepareAnimateOptions(options);
5249        options.removeClass = mergeClasses(options.removeClass, className);
5250        return $$animateQueue.push(element, 'removeClass', options);
5251      },
5252
5253      /**
5254       * @ngdoc method
5255       * @name $animate#setClass
5256       * @kind function
5257       *
5258       * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
5259       *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
5260       *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
5261       *    passed. Note that class-based animations are treated differently compared to structural animations
5262       *    (like enter, move and leave) since the CSS classes may be added/removed at different points
5263       *    depending if CSS or JavaScript animations are used.
5264       *
5265       * @param {DOMElement} element the element which the CSS classes will be applied to
5266       * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
5267       * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
5268       * @param {object=} options an optional collection of options/styles that will be applied to the element
5269       *
5270       * @return {Promise} the animation callback promise
5271       */
5272      setClass: function(element, add, remove, options) {
5273        options = prepareAnimateOptions(options);
5274        options.addClass = mergeClasses(options.addClass, add);
5275        options.removeClass = mergeClasses(options.removeClass, remove);
5276        return $$animateQueue.push(element, 'setClass', options);
5277      },
5278
5279      /**
5280       * @ngdoc method
5281       * @name $animate#animate
5282       * @kind function
5283       *
5284       * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
5285       * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
5286       * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
5287       * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
5288       * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
5289       *
5290       * @param {DOMElement} element the element which the CSS styles will be applied to
5291       * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
5292       * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
5293       * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
5294       *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
5295       *    (Note that if no animation is detected then this value will not be appplied to the element.)
5296       * @param {object=} options an optional collection of options/styles that will be applied to the element
5297       *
5298       * @return {Promise} the animation callback promise
5299       */
5300      animate: function(element, from, to, className, options) {
5301        options = prepareAnimateOptions(options);
5302        options.from = options.from ? extend(options.from, from) : from;
5303        options.to   = options.to   ? extend(options.to, to)     : to;
5304
5305        className = className || 'ng-inline-animate';
5306        options.tempClasses = mergeClasses(options.tempClasses, className);
5307        return $$animateQueue.push(element, 'animate', options);
5308      }
5309    };
5310  }];
5311}];
5312
5313function $$AsyncCallbackProvider() {
5314  this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
5315    return $$rAF.supported
5316      ? function(fn) { return $$rAF(fn); }
5317      : function(fn) {
5318        return $timeout(fn, 0, false);
5319      };
5320  }];
5321}
5322
5323/* global stripHash: true */
5324
5325/**
5326 * ! This is a private undocumented service !
5327 *
5328 * @name $browser
5329 * @requires $log
5330 * @description
5331 * This object has two goals:
5332 *
5333 * - hide all the global state in the browser caused by the window object
5334 * - abstract away all the browser specific features and inconsistencies
5335 *
5336 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
5337 * service, which can be used for convenient testing of the application without the interaction with
5338 * the real browser apis.
5339 */
5340/**
5341 * @param {object} window The global window object.
5342 * @param {object} document jQuery wrapped document.
5343 * @param {object} $log window.console or an object with the same interface.
5344 * @param {object} $sniffer $sniffer service
5345 */
5346function Browser(window, document, $log, $sniffer) {
5347  var self = this,
5348      rawDocument = document[0],
5349      location = window.location,
5350      history = window.history,
5351      setTimeout = window.setTimeout,
5352      clearTimeout = window.clearTimeout,
5353      pendingDeferIds = {};
5354
5355  self.isMock = false;
5356
5357  var outstandingRequestCount = 0;
5358  var outstandingRequestCallbacks = [];
5359
5360  // TODO(vojta): remove this temporary api
5361  self.$$completeOutstandingRequest = completeOutstandingRequest;
5362  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
5363
5364  /**
5365   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
5366   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
5367   */
5368  function completeOutstandingRequest(fn) {
5369    try {
5370      fn.apply(null, sliceArgs(arguments, 1));
5371    } finally {
5372      outstandingRequestCount--;
5373      if (outstandingRequestCount === 0) {
5374        while (outstandingRequestCallbacks.length) {
5375          try {
5376            outstandingRequestCallbacks.pop()();
5377          } catch (e) {
5378            $log.error(e);
5379          }
5380        }
5381      }
5382    }
5383  }
5384
5385  function getHash(url) {
5386    var index = url.indexOf('#');
5387    return index === -1 ? '' : url.substr(index + 1);
5388  }
5389
5390  /**
5391   * @private
5392   * Note: this method is used only by scenario runner
5393   * TODO(vojta): prefix this method with $$ ?
5394   * @param {function()} callback Function that will be called when no outstanding request
5395   */
5396  self.notifyWhenNoOutstandingRequests = function(callback) {
5397    if (outstandingRequestCount === 0) {
5398      callback();
5399    } else {
5400      outstandingRequestCallbacks.push(callback);
5401    }
5402  };
5403
5404  //////////////////////////////////////////////////////////////
5405  // URL API
5406  //////////////////////////////////////////////////////////////
5407
5408  var cachedState, lastHistoryState,
5409      lastBrowserUrl = location.href,
5410      baseElement = document.find('base'),
5411      reloadLocation = null;
5412
5413  cacheState();
5414  lastHistoryState = cachedState;
5415
5416  /**
5417   * @name $browser#url
5418   *
5419   * @description
5420   * GETTER:
5421   * Without any argument, this method just returns current value of location.href.
5422   *
5423   * SETTER:
5424   * With at least one argument, this method sets url to new value.
5425   * If html5 history api supported, pushState/replaceState is used, otherwise
5426   * location.href/location.replace is used.
5427   * Returns its own instance to allow chaining
5428   *
5429   * NOTE: this api is intended for use only by the $location service. Please use the
5430   * {@link ng.$location $location service} to change url.
5431   *
5432   * @param {string} url New url (when used as setter)
5433   * @param {boolean=} replace Should new url replace current history record?
5434   * @param {object=} state object to use with pushState/replaceState
5435   */
5436  self.url = function(url, replace, state) {
5437    // In modern browsers `history.state` is `null` by default; treating it separately
5438    // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
5439    // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
5440    if (isUndefined(state)) {
5441      state = null;
5442    }
5443
5444    // Android Browser BFCache causes location, history reference to become stale.
5445    if (location !== window.location) location = window.location;
5446    if (history !== window.history) history = window.history;
5447
5448    // setter
5449    if (url) {
5450      var sameState = lastHistoryState === state;
5451
5452      // Don't change anything if previous and current URLs and states match. This also prevents
5453      // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
5454      // See https://github.com/angular/angular.js/commit/ffb2701
5455      if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
5456        return self;
5457      }
5458      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
5459      lastBrowserUrl = url;
5460      lastHistoryState = state;
5461      // Don't use history API if only the hash changed
5462      // due to a bug in IE10/IE11 which leads
5463      // to not firing a `hashchange` nor `popstate` event
5464      // in some cases (see #9143).
5465      if ($sniffer.history && (!sameBase || !sameState)) {
5466        history[replace ? 'replaceState' : 'pushState'](state, '', url);
5467        cacheState();
5468        // Do the assignment again so that those two variables are referentially identical.
5469        lastHistoryState = cachedState;
5470      } else {
5471        if (!sameBase) {
5472          reloadLocation = url;
5473        }
5474        if (replace) {
5475          location.replace(url);
5476        } else if (!sameBase) {
5477          location.href = url;
5478        } else {
5479          location.hash = getHash(url);
5480        }
5481      }
5482      return self;
5483    // getter
5484    } else {
5485      // - reloadLocation is needed as browsers don't allow to read out
5486      //   the new location.href if a reload happened.
5487      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
5488      return reloadLocation || location.href.replace(/%27/g,"'");
5489    }
5490  };
5491
5492  /**
5493   * @name $browser#state
5494   *
5495   * @description
5496   * This method is a getter.
5497   *
5498   * Return history.state or null if history.state is undefined.
5499   *
5500   * @returns {object} state
5501   */
5502  self.state = function() {
5503    return cachedState;
5504  };
5505
5506  var urlChangeListeners = [],
5507      urlChangeInit = false;
5508
5509  function cacheStateAndFireUrlChange() {
5510    cacheState();
5511    fireUrlChange();
5512  }
5513
5514  function getCurrentState() {
5515    try {
5516      return history.state;
5517    } catch (e) {
5518      // MSIE can reportedly throw when there is no state (UNCONFIRMED).
5519    }
5520  }
5521
5522  // This variable should be used *only* inside the cacheState function.
5523  var lastCachedState = null;
5524  function cacheState() {
5525    // This should be the only place in $browser where `history.state` is read.
5526    cachedState = getCurrentState();
5527    cachedState = isUndefined(cachedState) ? null : cachedState;
5528
5529    // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
5530    if (equals(cachedState, lastCachedState)) {
5531      cachedState = lastCachedState;
5532    }
5533    lastCachedState = cachedState;
5534  }
5535
5536  function fireUrlChange() {
5537    if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
5538      return;
5539    }
5540
5541    lastBrowserUrl = self.url();
5542    lastHistoryState = cachedState;
5543    forEach(urlChangeListeners, function(listener) {
5544      listener(self.url(), cachedState);
5545    });
5546  }
5547
5548  /**
5549   * @name $browser#onUrlChange
5550   *
5551   * @description
5552   * Register callback function that will be called, when url changes.
5553   *
5554   * It's only called when the url is changed from outside of angular:
5555   * - user types different url into address bar
5556   * - user clicks on history (forward/back) button
5557   * - user clicks on a link
5558   *
5559   * It's not called when url is changed by $browser.url() method
5560   *
5561   * The listener gets called with new url as parameter.
5562   *
5563   * NOTE: this api is intended for use only by the $location service. Please use the
5564   * {@link ng.$location $location service} to monitor url changes in angular apps.
5565   *
5566   * @param {function(string)} listener Listener function to be called when url changes.
5567   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
5568   */
5569  self.onUrlChange = function(callback) {
5570    // TODO(vojta): refactor to use node's syntax for events
5571    if (!urlChangeInit) {
5572      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
5573      // don't fire popstate when user change the address bar and don't fire hashchange when url
5574      // changed by push/replaceState
5575
5576      // html5 history api - popstate event
5577      if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
5578      // hashchange event
5579      jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
5580
5581      urlChangeInit = true;
5582    }
5583
5584    urlChangeListeners.push(callback);
5585    return callback;
5586  };
5587
5588  /**
5589   * @private
5590   * Remove popstate and hashchange handler from window.
5591   *
5592   * NOTE: this api is intended for use only by $rootScope.
5593   */
5594  self.$$applicationDestroyed = function() {
5595    jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
5596  };
5597
5598  /**
5599   * Checks whether the url has changed outside of Angular.
5600   * Needs to be exported to be able to check for changes that have been done in sync,
5601   * as hashchange/popstate events fire in async.
5602   */
5603  self.$$checkUrlChange = fireUrlChange;
5604
5605  //////////////////////////////////////////////////////////////
5606  // Misc API
5607  //////////////////////////////////////////////////////////////
5608
5609  /**
5610   * @name $browser#baseHref
5611   *
5612   * @description
5613   * Returns current <base href>
5614   * (always relative - without domain)
5615   *
5616   * @returns {string} The current base href
5617   */
5618  self.baseHref = function() {
5619    var href = baseElement.attr('href');
5620    return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
5621  };
5622
5623  /**
5624   * @name $browser#defer
5625   * @param {function()} fn A function, who's execution should be deferred.
5626   * @param {number=} [delay=0] of milliseconds to defer the function execution.
5627   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
5628   *
5629   * @description
5630   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
5631   *
5632   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
5633   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
5634   * via `$browser.defer.flush()`.
5635   *
5636   */
5637  self.defer = function(fn, delay) {
5638    var timeoutId;
5639    outstandingRequestCount++;
5640    timeoutId = setTimeout(function() {
5641      delete pendingDeferIds[timeoutId];
5642      completeOutstandingRequest(fn);
5643    }, delay || 0);
5644    pendingDeferIds[timeoutId] = true;
5645    return timeoutId;
5646  };
5647
5648
5649  /**
5650   * @name $browser#defer.cancel
5651   *
5652   * @description
5653   * Cancels a deferred task identified with `deferId`.
5654   *
5655   * @param {*} deferId Token returned by the `$browser.defer` function.
5656   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
5657   *                    canceled.
5658   */
5659  self.defer.cancel = function(deferId) {
5660    if (pendingDeferIds[deferId]) {
5661      delete pendingDeferIds[deferId];
5662      clearTimeout(deferId);
5663      completeOutstandingRequest(noop);
5664      return true;
5665    }
5666    return false;
5667  };
5668
5669}
5670
5671function $BrowserProvider() {
5672  this.$get = ['$window', '$log', '$sniffer', '$document',
5673      function($window, $log, $sniffer, $document) {
5674        return new Browser($window, $document, $log, $sniffer);
5675      }];
5676}
5677
5678/**
5679 * @ngdoc service
5680 * @name $cacheFactory
5681 *
5682 * @description
5683 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
5684 * them.
5685 *
5686 * ```js
5687 *
5688 *  var cache = $cacheFactory('cacheId');
5689 *  expect($cacheFactory.get('cacheId')).toBe(cache);
5690 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
5691 *
5692 *  cache.put("key", "value");
5693 *  cache.put("another key", "another value");
5694 *
5695 *  // We've specified no options on creation
5696 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
5697 *
5698 * ```
5699 *
5700 *
5701 * @param {string} cacheId Name or id of the newly created cache.
5702 * @param {object=} options Options object that specifies the cache behavior. Properties:
5703 *
5704 *   - `{number=}` `capacity` — turns the cache into LRU cache.
5705 *
5706 * @returns {object} Newly created cache object with the following set of methods:
5707 *
5708 * - `{object}` `info()` — Returns id, size, and options of cache.
5709 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
5710 *   it.
5711 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
5712 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
5713 * - `{void}` `removeAll()` — Removes all cached values.
5714 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
5715 *
5716 * @example
5717   <example module="cacheExampleApp">
5718     <file name="index.html">
5719       <div ng-controller="CacheController">
5720         <input ng-model="newCacheKey" placeholder="Key">
5721         <input ng-model="newCacheValue" placeholder="Value">
5722         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
5723
5724         <p ng-if="keys.length">Cached Values</p>
5725         <div ng-repeat="key in keys">
5726           <span ng-bind="key"></span>
5727           <span>: </span>
5728           <b ng-bind="cache.get(key)"></b>
5729         </div>
5730
5731         <p>Cache Info</p>
5732         <div ng-repeat="(key, value) in cache.info()">
5733           <span ng-bind="key"></span>
5734           <span>: </span>
5735           <b ng-bind="value"></b>
5736         </div>
5737       </div>
5738     </file>
5739     <file name="script.js">
5740       angular.module('cacheExampleApp', []).
5741         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
5742           $scope.keys = [];
5743           $scope.cache = $cacheFactory('cacheId');
5744           $scope.put = function(key, value) {
5745             if ($scope.cache.get(key) === undefined) {
5746               $scope.keys.push(key);
5747             }
5748             $scope.cache.put(key, value === undefined ? null : value);
5749           };
5750         }]);
5751     </file>
5752     <file name="style.css">
5753       p {
5754         margin: 10px 0 3px;
5755       }
5756     </file>
5757   </example>
5758 */
5759function $CacheFactoryProvider() {
5760
5761  this.$get = function() {
5762    var caches = {};
5763
5764    function cacheFactory(cacheId, options) {
5765      if (cacheId in caches) {
5766        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
5767      }
5768
5769      var size = 0,
5770          stats = extend({}, options, {id: cacheId}),
5771          data = {},
5772          capacity = (options && options.capacity) || Number.MAX_VALUE,
5773          lruHash = {},
5774          freshEnd = null,
5775          staleEnd = null;
5776
5777      /**
5778       * @ngdoc type
5779       * @name $cacheFactory.Cache
5780       *
5781       * @description
5782       * A cache object used to store and retrieve data, primarily used by
5783       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
5784       * templates and other data.
5785       *
5786       * ```js
5787       *  angular.module('superCache')
5788       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
5789       *      return $cacheFactory('super-cache');
5790       *    }]);
5791       * ```
5792       *
5793       * Example test:
5794       *
5795       * ```js
5796       *  it('should behave like a cache', inject(function(superCache) {
5797       *    superCache.put('key', 'value');
5798       *    superCache.put('another key', 'another value');
5799       *
5800       *    expect(superCache.info()).toEqual({
5801       *      id: 'super-cache',
5802       *      size: 2
5803       *    });
5804       *
5805       *    superCache.remove('another key');
5806       *    expect(superCache.get('another key')).toBeUndefined();
5807       *
5808       *    superCache.removeAll();
5809       *    expect(superCache.info()).toEqual({
5810       *      id: 'super-cache',
5811       *      size: 0
5812       *    });
5813       *  }));
5814       * ```
5815       */
5816      return caches[cacheId] = {
5817
5818        /**
5819         * @ngdoc method
5820         * @name $cacheFactory.Cache#put
5821         * @kind function
5822         *
5823         * @description
5824         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
5825         * retrieved later, and incrementing the size of the cache if the key was not already
5826         * present in the cache. If behaving like an LRU cache, it will also remove stale
5827         * entries from the set.
5828         *
5829         * It will not insert undefined values into the cache.
5830         *
5831         * @param {string} key the key under which the cached data is stored.
5832         * @param {*} value the value to store alongside the key. If it is undefined, the key
5833         *    will not be stored.
5834         * @returns {*} the value stored.
5835         */
5836        put: function(key, value) {
5837          if (isUndefined(value)) return;
5838          if (capacity < Number.MAX_VALUE) {
5839            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
5840
5841            refresh(lruEntry);
5842          }
5843
5844          if (!(key in data)) size++;
5845          data[key] = value;
5846
5847          if (size > capacity) {
5848            this.remove(staleEnd.key);
5849          }
5850
5851          return value;
5852        },
5853
5854        /**
5855         * @ngdoc method
5856         * @name $cacheFactory.Cache#get
5857         * @kind function
5858         *
5859         * @description
5860         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
5861         *
5862         * @param {string} key the key of the data to be retrieved
5863         * @returns {*} the value stored.
5864         */
5865        get: function(key) {
5866          if (capacity < Number.MAX_VALUE) {
5867            var lruEntry = lruHash[key];
5868
5869            if (!lruEntry) return;
5870
5871            refresh(lruEntry);
5872          }
5873
5874          return data[key];
5875        },
5876
5877
5878        /**
5879         * @ngdoc method
5880         * @name $cacheFactory.Cache#remove
5881         * @kind function
5882         *
5883         * @description
5884         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
5885         *
5886         * @param {string} key the key of the entry to be removed
5887         */
5888        remove: function(key) {
5889          if (capacity < Number.MAX_VALUE) {
5890            var lruEntry = lruHash[key];
5891
5892            if (!lruEntry) return;
5893
5894            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
5895            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
5896            link(lruEntry.n,lruEntry.p);
5897
5898            delete lruHash[key];
5899          }
5900
5901          delete data[key];
5902          size--;
5903        },
5904
5905
5906        /**
5907         * @ngdoc method
5908         * @name $cacheFactory.Cache#removeAll
5909         * @kind function
5910         *
5911         * @description
5912         * Clears the cache object of any entries.
5913         */
5914        removeAll: function() {
5915          data = {};
5916          size = 0;
5917          lruHash = {};
5918          freshEnd = staleEnd = null;
5919        },
5920
5921
5922        /**
5923         * @ngdoc method
5924         * @name $cacheFactory.Cache#destroy
5925         * @kind function
5926         *
5927         * @description
5928         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
5929         * removing it from the {@link $cacheFactory $cacheFactory} set.
5930         */
5931        destroy: function() {
5932          data = null;
5933          stats = null;
5934          lruHash = null;
5935          delete caches[cacheId];
5936        },
5937
5938
5939        /**
5940         * @ngdoc method
5941         * @name $cacheFactory.Cache#info
5942         * @kind function
5943         *
5944         * @description
5945         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
5946         *
5947         * @returns {object} an object with the following properties:
5948         *   <ul>
5949         *     <li>**id**: the id of the cache instance</li>
5950         *     <li>**size**: the number of entries kept in the cache instance</li>
5951         *     <li>**...**: any additional properties from the options object when creating the
5952         *       cache.</li>
5953         *   </ul>
5954         */
5955        info: function() {
5956          return extend({}, stats, {size: size});
5957        }
5958      };
5959
5960
5961      /**
5962       * makes the `entry` the freshEnd of the LRU linked list
5963       */
5964      function refresh(entry) {
5965        if (entry != freshEnd) {
5966          if (!staleEnd) {
5967            staleEnd = entry;
5968          } else if (staleEnd == entry) {
5969            staleEnd = entry.n;
5970          }
5971
5972          link(entry.n, entry.p);
5973          link(entry, freshEnd);
5974          freshEnd = entry;
5975          freshEnd.n = null;
5976        }
5977      }
5978
5979
5980      /**
5981       * bidirectionally links two entries of the LRU linked list
5982       */
5983      function link(nextEntry, prevEntry) {
5984        if (nextEntry != prevEntry) {
5985          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5986          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5987        }
5988      }
5989    }
5990
5991
5992  /**
5993   * @ngdoc method
5994   * @name $cacheFactory#info
5995   *
5996   * @description
5997   * Get information about all the caches that have been created
5998   *
5999   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
6000   */
6001    cacheFactory.info = function() {
6002      var info = {};
6003      forEach(caches, function(cache, cacheId) {
6004        info[cacheId] = cache.info();
6005      });
6006      return info;
6007    };
6008
6009
6010  /**
6011   * @ngdoc method
6012   * @name $cacheFactory#get
6013   *
6014   * @description
6015   * Get access to a cache object by the `cacheId` used when it was created.
6016   *
6017   * @param {string} cacheId Name or id of a cache to access.
6018   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
6019   */
6020    cacheFactory.get = function(cacheId) {
6021      return caches[cacheId];
6022    };
6023
6024
6025    return cacheFactory;
6026  };
6027}
6028
6029/**
6030 * @ngdoc service
6031 * @name $templateCache
6032 *
6033 * @description
6034 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
6035 * can load templates directly into the cache in a `script` tag, or by consuming the
6036 * `$templateCache` service directly.
6037 *
6038 * Adding via the `script` tag:
6039 *
6040 * ```html
6041 *   <script type="text/ng-template" id="templateId.html">
6042 *     <p>This is the content of the template</p>
6043 *   </script>
6044 * ```
6045 *
6046 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
6047 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
6048 * element with ng-app attribute), otherwise the template will be ignored.
6049 *
6050 * Adding via the `$templateCache` service:
6051 *
6052 * ```js
6053 * var myApp = angular.module('myApp', []);
6054 * myApp.run(function($templateCache) {
6055 *   $templateCache.put('templateId.html', 'This is the content of the template');
6056 * });
6057 * ```
6058 *
6059 * To retrieve the template later, simply use it in your HTML:
6060 * ```html
6061 * <div ng-include=" 'templateId.html' "></div>
6062 * ```
6063 *
6064 * or get it via Javascript:
6065 * ```js
6066 * $templateCache.get('templateId.html')
6067 * ```
6068 *
6069 * See {@link ng.$cacheFactory $cacheFactory}.
6070 *
6071 */
6072function $TemplateCacheProvider() {
6073  this.$get = ['$cacheFactory', function($cacheFactory) {
6074    return $cacheFactory('templates');
6075  }];
6076}
6077
6078/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
6079 *     Any commits to this file should be reviewed with security in mind.  *
6080 *   Changes to this file can potentially create security vulnerabilities. *
6081 *          An approval from 2 Core members with history of modifying      *
6082 *                         this file is required.                          *
6083 *                                                                         *
6084 *  Does the change somehow allow for arbitrary javascript to be executed? *
6085 *    Or allows for someone to change the prototype of built-in objects?   *
6086 *     Or gives undesired access to variables likes document or window?    *
6087 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6088
6089/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
6090 *
6091 * DOM-related variables:
6092 *
6093 * - "node" - DOM Node
6094 * - "element" - DOM Element or Node
6095 * - "$node" or "$element" - jqLite-wrapped node or element
6096 *
6097 *
6098 * Compiler related stuff:
6099 *
6100 * - "linkFn" - linking fn of a single directive
6101 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
6102 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
6103 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
6104 */
6105
6106
6107/**
6108 * @ngdoc service
6109 * @name $compile
6110 * @kind function
6111 *
6112 * @description
6113 * Compiles an HTML string or DOM into a template and produces a template function, which
6114 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
6115 *
6116 * The compilation is a process of walking the DOM tree and matching DOM elements to
6117 * {@link ng.$compileProvider#directive directives}.
6118 *
6119 * <div class="alert alert-warning">
6120 * **Note:** This document is an in-depth reference of all directive options.
6121 * For a gentle introduction to directives with examples of common use cases,
6122 * see the {@link guide/directive directive guide}.
6123 * </div>
6124 *
6125 * ## Comprehensive Directive API
6126 *
6127 * There are many different options for a directive.
6128 *
6129 * The difference resides in the return value of the factory function.
6130 * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
6131 * or just the `postLink` function (all other properties will have the default values).
6132 *
6133 * <div class="alert alert-success">
6134 * **Best Practice:** It's recommended to use the "directive definition object" form.
6135 * </div>
6136 *
6137 * Here's an example directive declared with a Directive Definition Object:
6138 *
6139 * ```js
6140 *   var myModule = angular.module(...);
6141 *
6142 *   myModule.directive('directiveName', function factory(injectables) {
6143 *     var directiveDefinitionObject = {
6144 *       priority: 0,
6145 *       template: '<div></div>
6145', // or // function(tElement, tAttrs) { ... },
6146 *       // or
6147 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
6148 *       transclude: false,
6149 *       restrict: 'A',
6150 *       templateNamespace: 'html',
6151 *       scope: false,
6152 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
6153 *       controllerAs: 'stringIdentifier',
6154 *       bindToController: false,
6155 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
6156 *       compile: function compile(tElement, tAttrs, transclude) {
6157 *         return {
6158 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6159 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
6160 *         }
6161 *         // or
6162 *         // return function postLink( ... ) { ... }
6163 *       },
6164 *       // or
6165 *       // link: {
6166 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
6167 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
6168 *       // }
6169 *       // or
6170 *       // link: function postLink( ... ) { ... }
6171 *     };
6172 *     return directiveDefinitionObject;
6173 *   });
6174 * ```
6175 *
6176 * <div class="alert alert-warning">
6177 * **Note:** Any unspecified options will use the default value. You can see the default values below.
6178 * </div>
6179 *
6180 * Therefore the above can be simplified as:
6181 *
6182 * ```js
6183 *   var myModule = angular.module(...);
6184 *
6185 *   myModule.directive('directiveName', function factory(injectables) {
6186 *     var directiveDefinitionObject = {
6187 *       link: function postLink(scope, iElement, iAttrs) { ... }
6188 *     };
6189 *     return directiveDefinitionObject;
6190 *     // or
6191 *     // return function postLink(scope, iElement, iAttrs) { ... }
6192 *   });
6193 * ```
6194 *
6195 *
6196 *
6197 * ### Directive Definition Object
6198 *
6199 * The directive definition object provides instructions to the {@link ng.$compile
6200 * compiler}. The attributes are:
6201 *
6202 * #### `multiElement`
6203 * When this property is set to true, the HTML compiler will collect DOM nodes between
6204 * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
6205 * together as the directive elements. It is recommended that this feature be used on directives
6206 * which are not strictly behavioural (such as {@link ngClick}), and which
6207 * do not manipulate or replace child nodes (such as {@link ngInclude}).
6208 *
6209 * #### `priority`
6210 * When there are multiple directives defined on a single DOM element, sometimes it
6211 * is necessary to specify the order in which the directives are applied. The `priority` is used
6212 * to sort the directives before their `compile` functions get called. Priority is defined as a
6213 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
6214 * are also run in priority order, but post-link functions are run in reverse order. The order
6215 * of directives with the same priority is undefined. The default priority is `0`.
6216 *
6217 * #### `terminal`
6218 * If set to true then the current `priority` will be the last set of directives
6219 * which will execute (any directives at the current priority will still execute
6220 * as the order of execution on same `priority` is undefined). Note that expressions
6221 * and other directives used in the directive's template will also be excluded from execution.
6222 *
6223 * #### `scope`
6224 * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
6225 * same element request a new scope, only one new scope is created. The new scope rule does not
6226 * apply for the root of the template since the root of the template always gets a new scope.
6227 *
6228 * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
6229 * normal scope in that it does not prototypically inherit from the parent scope. This is useful
6230 * when creating reusable components, which should not accidentally read or modify data in the
6231 * parent scope.
6232 *
6233 * The 'isolate' scope takes an object hash which defines a set of local scope properties
6234 * derived from the parent scope. These local properties are useful for aliasing values for
6235 * templates. Locals definition is a hash of local scope property to its source:
6236 *
6237 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
6238 *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
6239 *   attribute name is assumed to be the same as the local name.
6240 *   Given `<widget my-attr="hello {{name}}">` and widget definition
6241 *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
6242 *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
6243 *   `localName` property on the widget scope. The `name` is read from the parent scope (not
6244 *   component scope).
6245 *
6246 * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
6247 *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
6248 *   name is specified then the attribute name is assumed to be the same as the local name.
6249 *   Given `<widget my-attr="parentModel">` and widget definition of
6250 *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
6251 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
6252 *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
6253 *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
6254 *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
6255 *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
6256 *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
6257 *
6258 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
6259 *   If no `attr` name is specified then the attribute name is assumed to be the same as the
6260 *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
6261 *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
6262 *   a function wrapper for the `count = count + value` expression. Often it's desirable to
6263 *   pass data from the isolated scope via an expression to the parent scope, this can be
6264 *   done by passing a map of local variable names and values into the expression wrapper fn.
6265 *   For example, if the expression is `increment(amount)` then we can specify the amount value
6266 *   by calling the `localFn` as `localFn({amount: 22})`.
6267 *
6268 *
6269 * #### `bindToController`
6270 * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
6271 * allow a component to have its properties bound to the controller, rather than to scope. When the controller
6272 * is instantiated, the initial values of the isolate scope bindings are already available.
6273 *
6274 * #### `controller`
6275 * Controller constructor function. The controller is instantiated before the
6276 * pre-linking phase and it is shared with other directives (see
6277 * `require` attribute). This allows the directives to communicate with each other and augment
6278 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
6279 *
6280 * * `$scope` - Current scope associated with the element
6281 * * `$element` - Current element
6282 * * `$attrs` - Current attributes object for the element
6283 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
6284 *   `function([scope], cloneLinkingFn, futureParentElement)`.
6285 *    * `scope`: optional argument to override the scope.
6286 *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
6287 *    * `futureParentElement`:
6288 *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
6289 *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
6290 *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
6291 *          and when the `cloneLinkinFn` is passed,
6292 *          as those elements need to created and cloned in a special way when they are defined outside their
6293 *          usual containers (e.g. like `<svg>`).
6294 *        * See also the `directive.templateNamespace` property.
6295 *
6296 *
6297 * #### `require`
6298 * Require another directive and inject its controller as the fourth argument to the linking function. The
6299 * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
6300 * injected argument will be an array in corresponding order. If no such directive can be
6301 * found, or if the directive does not have a controller, then an error is raised (unless no link function
6302 * is specified, in which case error checking is skipped). The name can be prefixed with:
6303 *
6304 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
6305 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
6306 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
6307 * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
6308 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
6309 *   `null` to the `link` fn if not found.
6310 * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
6311 *   `null` to the `link` fn if not found.
6312 *
6313 *
6314 * #### `controllerAs`
6315 * Identifier name for a reference to the controller in the directive's scope.
6316 * This allows the controller to be referenced from the directive template. The directive
6317 * needs to define a scope for this configuration to be used. Useful in the case when
6318 * directive is used as component.
6319 *
6320 *
6321 * #### `restrict`
6322 * String of subset of `EACM` which restricts the directive to a specific directive
6323 * declaration style. If omitted, the defaults (elements and attributes) are used.
6324 *
6325 * * `E` - Element name (default): `<my-directive></my-directive>`
6326 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
6327 * * `C` - Class: `<div class="my-directive: exp;"></div>`
6328 * * `M` - Comment: `<!-- directive: my-directive exp -->`
6329 *
6330 *
6331 * #### `templateNamespace`
6332 * String representing the document type used by the markup in the template.
6333 * AngularJS needs this information as those elements need to be created and cloned
6334 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
6335 *
6336 * * `html` - All root nodes in the template are HTML. Root nodes may also be
6337 *   top-level elements such as `<svg>` or `<math>`.
6338 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
6339 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
6340 *
6341 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
6342 *
6343 * #### `template`
6344 * HTML markup that may:
6345 * * Replace the contents of the directive's element (default).
6346 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
6347 * * Wrap the contents of the directive's element (if `transclude` is true).
6348 *
6349 * Value may be:
6350 *
6351 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
6352 * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
6353 *   function api below) and returns a string value.
6354 *
6355 *
6356 * #### `templateUrl`
6357 * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
6358 *
6359 * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
6360 * for later when the template has been resolved.  In the meantime it will continue to compile and link
6361 * sibling and parent elements as though this element had not contained any directives.
6362 *
6363 * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
6364 * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
6365 * case when only one deeply nested directive has `templateUrl`.
6366 *
6367 * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
6368 *
6369 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
6370 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
6371 * a string value representing the url.  In either case, the template URL is passed through {@link
6372 * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
6373 *
6374 *
6375 * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
6376 * specify what the template should replace. Defaults to `false`.
6377 *
6378 * * `true` - the template will replace the directive's element.
6379 * * `false` - the template will replace the contents of the directive's element.
6380 *
6381 * The replacement process migrates all of the attributes / classes from the old element to the new
6382 * one. See the {@link guide/directive#template-expanding-directive
6383 * Directives Guide} for an example.
6384 *
6385 * There are very few scenarios where element replacement is required for the application function,
6386 * the main one being reusable custom components that are used within SVG contexts
6387 * (because SVG doesn't work with custom elements in the DOM tree).
6388 *
6389 * #### `transclude`
6390 * Extract the contents of the element where the directive appears and make it available to the directive.
6391 * The contents are compiled and provided to the directive as a **transclusion function**. See the
6392 * {@link $compile#transclusion Transclusion} section below.
6393 *
6394 * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
6395 * directive's element or the entire element:
6396 *
6397 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
6398 * * `'element'` - transclude the whole of the directive's element including any directives on this
6399 *   element that defined at a lower priority than this directive. When used, the `template`
6400 *   property is ignored.
6401 *
6402 *
6403 * #### `compile`
6404 *
6405 * ```js
6406 *   function compile(tElement, tAttrs, transclude) { ... }
6407 * ```
6408 *
6409 * The compile function deals with transforming the template DOM. Since most directives do not do
6410 * template transformation, it is not used often. The compile function takes the following arguments:
6411 *
6412 *   * `tElement` - template element - The element where the directive has been declared. It is
6413 *     safe to do template transformation on the element and child elements only.
6414 *
6415 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
6416 *     between all directive compile functions.
6417 *
6418 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
6419 *
6420 * <div class="alert alert-warning">
6421 * **Note:** The template instance and the link instance may be different objects if the template has
6422 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
6423 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
6424 * should be done in a linking function rather than in a compile function.
6425 * </div>
6426
6427 * <div class="alert alert-warning">
6428 * **Note:** The compile function cannot handle directives that recursively use themselves in their
6429 * own templates or compile functions. Compiling these directives results in an infinite loop and a
6430 * stack overflow errors.
6431 *
6432 * This can be avoided by manually using $compile in the postLink function to imperatively compile
6433 * a directive's template instead of relying on automatic template compilation via `template` or
6434 * `templateUrl` declaration or manual compilation inside the compile function.
6435 * </div>
6436 *
6437 * <div class="alert alert-danger">
6438 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
6439 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
6440 *   to the link function instead.
6441 * </div>
6442
6443 * A compile function can have a return value which can be either a function or an object.
6444 *
6445 * * returning a (post-link) function - is equivalent to registering the linking function via the
6446 *   `link` property of the config object when the compile function is empty.
6447 *
6448 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
6449 *   control when a linking function should be called during the linking phase. See info about
6450 *   pre-linking and post-linking functions below.
6451 *
6452 *
6453 * #### `link`
6454 * This property is used only if the `compile` property is not defined.
6455 *
6456 * ```js
6457 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
6458 * ```
6459 *
6460 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
6461 * executed after the template has been cloned. This is where most of the directive logic will be
6462 * put.
6463 *
6464 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
6465 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
6466 *
6467 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
6468 *     manipulate the children of the element only in `postLink` function since the children have
6469 *     already been linked.
6470 *
6471 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
6472 *     between all directive linking functions.
6473 *
6474 *   * `controller` - the directive's required controller instance(s) - Instances are shared
6475 *     among all directives, which allows the directives to use the controllers as a communication
6476 *     channel. The exact value depends on the directive's `require` property:
6477 *       * `string`: the controller instance
6478 *       * `array`: array of controller instances
6479 *       * no controller(s) required: `undefined`
6480 *
6481 *     If a required controller cannot be found, and it is optional, the instance is `null`,
6482 *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
6483 *
6484 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
6485 *     This is the same as the `$transclude`
6486 *     parameter of directive controllers, see there for details.
6487 *     `function([scope], cloneLinkingFn, futureParentElement)`.
6488 *
6489 * #### Pre-linking function
6490 *
6491 * Executed before the child elements are linked. Not safe to do DOM transformation since the
6492 * compiler linking function will fail to locate the correct elements for linking.
6493 *
6494 * #### Post-linking function
6495 *
6496 * Executed after the child elements are linked.
6497 *
6498 * Note that child elements that contain `templateUrl` directives will not have been compiled
6499 * and linked since they are waiting for their template to load asynchronously and their own
6500 * compilation and linking has been suspended until that occurs.
6501 *
6502 * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
6503 * for their async templates to be resolved.
6504 *
6505 *
6506 * ### Transclusion
6507 *
6508 * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
6509 * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
6510 * scope from where they were taken.
6511 *
6512 * Transclusion is used (often with {@link ngTransclude}) to insert the
6513 * original contents of a directive's element into a specified place in the template of the directive.
6514 * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
6515 * content has access to the properties on the scope from which it was taken, even if the directive
6516 * has isolated scope.
6517 * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
6518 *
6519 * This makes it possible for the widget to have private state for its template, while the transcluded
6520 * content has access to its originating scope.
6521 *
6522 * <div class="alert alert-warning">
6523 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
6524 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
6525 * Testing Transclusion Directives}.
6526 * </div>
6527 *
6528 * #### Transclusion Functions
6529 *
6530 * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
6531 * function** to the directive's `link` function and `controller`. This transclusion function is a special
6532 * **linking function** that will return the compiled contents linked to a new transclusion scope.
6533 *
6534 * <div class="alert alert-info">
6535 * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
6536 * ngTransclude will deal with it for us.
6537 * </div>
6538 *
6539 * If you want to manually control the insertion and removal of the transcluded content in your directive
6540 * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
6541 * object that contains the compiled DOM, which is linked to the correct transclusion scope.
6542 *
6543 * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
6544 * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
6545 * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
6546 *
6547 * <div class="alert alert-info">
6548 * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
6549 * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
6550 * </div>
6551 *
6552 * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
6553 * attach function**:
6554 *
6555 * ```js
6556 * var transcludedContent, transclusionScope;
6557 *
6558 * $transclude(function(clone, scope) {
6559 *   element.append(clone);
6560 *   transcludedContent = clone;
6561 *   transclusionScope = scope;
6562 * });
6563 * ```
6564 *
6565 * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
6566 * associated transclusion scope:
6567 *
6568 * ```js
6569 * transcludedContent.remove();
6570 * transclusionScope.$destroy();
6571 * ```
6572 *
6573 * <div class="alert alert-info">
6574 * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
6575 * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
6576 * then you are also responsible for calling `$destroy` on the transclusion scope.
6577 * </div>
6578 *
6579 * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
6580 * automatically destroy their transluded clones as necessary so you do not need to worry about this if
6581 * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
6582 *
6583 *
6584 * #### Transclusion Scopes
6585 *
6586 * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
6587 * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
6588 * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
6589 * was taken.
6590 *
6591 * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
6592 * like this:
6593 *
6594 * ```html
6595 * <div ng-app>
6596 *   <div isolate>
6597 *     <div transclusion>
6598 *     </div>
6599 *   </div>
6600 * </div>
6601 * ```
6602 *
6603 * The `$parent` scope hierarchy will look like this:
6604 *
6605 * ```
6606 * - $rootScope
6607 *   - isolate
6608 *     - transclusion
6609 * ```
6610 *
6611 * but the scopes will inherit prototypically from different scopes to their `$parent`.
6612 *
6613 * ```
6614 * - $rootScope
6615 *   - transclusion
6616 * - isolate
6617 * ```
6618 *
6619 *
6620 * ### Attributes
6621 *
6622 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
6623 * `link()` or `compile()` functions. It has a variety of uses.
6624 *
6625 * accessing *Normalized attribute names:*
6626 * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
6627 * the attributes object allows for normalized access to
6628 *   the attributes.
6629 *
6630 * * *Directive inter-communication:* All directives share the same instance of the attributes
6631 *   object which allows the directives to use the attributes object as inter directive
6632 *   communication.
6633 *
6634 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
6635 *   allowing other directives to read the interpolated value.
6636 *
6637 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
6638 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
6639 *   the only way to easily get the actual value because during the linking phase the interpolation
6640 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
6641 *
6642 * ```js
6643 * function linkingFn(scope, elm, attrs, ctrl) {
6644 *   // get the attribute value
6645 *   console.log(attrs.ngModel);
6646 *
6647 *   // change the attribute
6648 *   attrs.$set('ngModel', 'new value');
6649 *
6650 *   // observe changes to interpolated attribute
6651 *   attrs.$observe('ngModel', function(value) {
6652 *     console.log('ngModel has changed value to ' + value);
6653 *   });
6654 * }
6655 * ```
6656 *
6657 * ## Example
6658 *
6659 * <div class="alert alert-warning">
6660 * **Note**: Typically directives are registered with `module.directive`. The example below is
6661 * to illustrate how `$compile` works.
6662 * </div>
6663 *
6664 <example module="compileExample">
6665   <file name="index.html">
6666    <script>
6667      angular.module('compileExample', [], function($compileProvider) {
6668        // configure new 'compile' directive by passing a directive
6669        // factory function. The factory function injects the '$compile'
6670        $compileProvider.directive('compile', function($compile) {
6671          // directive factory creates a link function
6672          return function(scope, element, attrs) {
6673            scope.$watch(
6674              function(scope) {
6675                 // watch the 'compile' expression for changes
6676                return scope.$eval(attrs.compile);
6677              },
6678              function(value) {
6679                // when the 'compile' expression changes
6680                // assign it into the current DOM
6681                element.html(value);
6682
6683                // compile the new DOM and link it to the current
6684                // scope.
6685                // NOTE: we only compile .childNodes so that
6686                // we don't get into infinite loop compiling ourselves
6687                $compile(element.contents())(scope);
6688              }
6689            );
6690          };
6691        });
6692      })
6693      .controller('GreeterController', ['$scope', function($scope) {
6694        $scope.name = 'Angular';
6695        $scope.html = 'Hello {{name}}';
6696      }]);
6697    </script>
6698    <div ng-controller="GreeterController">
6699      <input ng-model="name"> <br/>
6700      <textarea ng-model="html"></textarea> <br/>
6701      <div compile="html"></div>
6702    </div>
6703   </file>
6704   <file name="protractor.js" type="protractor">
6705     it('should auto compile', function() {
6706       var textarea = $('textarea');
6707       var output = $('div[compile]');
6708       // The initial state reads 'Hello Angular'.
6709       expect(output.getText()).toBe('Hello Angular');
6710       textarea.clear();
6711       textarea.sendKeys('{{name}}!');
6712       expect(output.getText()).toBe('Angular!');
6713     });
6714   </file>
6715 </example>
6716
6717 *
6718 *
6719 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
6720 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
6721 *
6722 * <div class="alert alert-danger">
6723 * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
6724 *   e.g. will not use the right outer scope. Please pass the transclude function as a
6725 *   `parentBoundTranscludeFn` to the link function instead.
6726 * </div>
6727 *
6728 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
6729 *                 root element(s), not their children)
6730 * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
6731 * (a DOM element/tree) to a scope. Where:
6732 *
6733 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
6734 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
6735 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
6736 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
6737 *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
6738 *
6739 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
6740 *      * `scope` - is the current scope with which the linking function is working with.
6741 *
6742 *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
6743 *  keys may be used to control linking behavior:
6744 *
6745 *      * `parentBoundTranscludeFn` - the transclude function made available to
6746 *        directives; if given, it will be passed through to the link functions of
6747 *        directives found in `element` during compilation.
6748 *      * `transcludeControllers` - an object hash with keys that map controller names
6749 *        to controller instances; if given, it will make the controllers
6750 *        available to directives.
6751 *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
6752 *        the cloned elements; only needed for transcludes that are allowed to contain non html
6753 *        elements (e.g. SVG elements). See also the directive.controller property.
6754 *
6755 * Calling the linking function returns the element of the template. It is either the original
6756 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
6757 *
6758 * After linking the view is not updated until after a call to $digest which typically is done by
6759 * Angular automatically.
6760 *
6761 * If you need access to the bound view, there are two ways to do it:
6762 *
6763 * - If you are not asking the linking function to clone the template, create the DOM element(s)
6764 *   before you send them to the compiler and keep this reference around.
6765 *   ```js
6766 *     var element = $compile('<p>{{total}}</p>')(scope);
6767 *   ```
6768 *
6769 * - if on the other hand, you need the element to be cloned, the view reference from the original
6770 *   example would not point to the clone, but rather to the original template that was cloned. In
6771 *   this case, you can access the clone via the cloneAttachFn:
6772 *   ```js
6773 *     var templateElement = angular.element('<p>{{total}}</p>'),
6774 *         scope = ....;
6775 *
6776 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
6777 *       //attach the clone to DOM document at the right place
6778 *     });
6779 *
6780 *     //now we have reference to the cloned DOM via `clonedElement`
6781 *   ```
6782 *
6783 *
6784 * For information on how the compiler works, see the
6785 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
6786 */
6787
6788var $compileMinErr = minErr('$compile');
6789
6790/**
6791 * @ngdoc provider
6792 * @name $compileProvider
6793 *
6794 * @description
6795 */
6796$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
6797function $CompileProvider($provide, $$sanitizeUriProvider) {
6798  var hasDirectives = {},
6799      Suffix = 'Directive',
6800      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
6801      CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
6802      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
6803      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
6804
6805  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
6806  // The assumption is that future DOM event attribute names will begin with
6807  // 'on' and be composed of only English letters.
6808  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
6809
6810  function parseIsolateBindings(scope, directiveName, isController) {
6811    var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
6812
6813    var bindings = {};
6814
6815    forEach(scope, function(definition, scopeName) {
6816      var match = definition.match(LOCAL_REGEXP);
6817
6818      if (!match) {
6819        throw $compileMinErr('iscp',
6820            "Invalid {3} for directive '{0}'." +
6821            " Definition: {... {1}: '{2}' ...}",
6822            directiveName, scopeName, definition,
6823            (isController ? "controller bindings definition" :
6824            "isolate scope definition"));
6825      }
6826
6827      bindings[scopeName] = {
6828        mode: match[1][0],
6829        collection: match[2] === '*',
6830        optional: match[3] === '?',
6831        attrName: match[4] || scopeName
6832      };
6833    });
6834
6835    return bindings;
6836  }
6837
6838  function parseDirectiveBindings(directive, directiveName) {
6839    var bindings = {
6840      isolateScope: null,
6841      bindToController: null
6842    };
6843    if (isObject(directive.scope)) {
6844      if (directive.bindToController === true) {
6845        bindings.bindToController = parseIsolateBindings(directive.scope,
6846                                                         directiveName, true);
6847        bindings.isolateScope = {};
6848      } else {
6849        bindings.isolateScope = parseIsolateBindings(directive.scope,
6850                                                     directiveName, false);
6851      }
6852    }
6853    if (isObject(directive.bindToController)) {
6854      bindings.bindToController =
6855          parseIsolateBindings(directive.bindToController, directiveName, true);
6856    }
6857    if (isObject(bindings.bindToController)) {
6858      var controller = directive.controller;
6859      var controllerAs = directive.controllerAs;
6860      if (!controller) {
6861        // There is no controller, there may or may not be a controllerAs property
6862        throw $compileMinErr('noctrl',
6863              "Cannot bind to controller without directive '{0}'s controller.",
6864              directiveName);
6865      } else if (!identifierForController(controller, controllerAs)) {
6866        // There is a controller, but no identifier or controllerAs property
6867        throw $compileMinErr('noident',
6868              "Cannot bind to controller without identifier for directive '{0}'.",
6869              directiveName);
6870      }
6871    }
6872    return bindings;
6873  }
6874
6875  function assertValidDirectiveName(name) {
6876    var letter = name.charAt(0);
6877    if (!letter || letter !== lowercase(letter)) {
6878      throw $compileMinErr('baddir', "Directive name '{0}
vendor: 4,558 bytes, lines 6878-6989
6878' is invalid. The first character must be a lowercase letter", name);
6879    }
6880    if (name !== name.trim()) {
6881      throw $compileMinErr('baddir',
6882            "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
6883            name);
6884    }
6885  }
6886
6887  /**
6888   * @ngdoc method
6889   * @name $compileProvider#directive
6890   * @kind function
6891   *
6892   * @description
6893   * Register a new directive with the compiler.
6894   *
6895   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
6896   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
6897   *    names and the values are the factories.
6898   * @param {Function|Array} directiveFactory An injectable directive factory function. See
6899   *    {@link guide/directive} for more info.
6900   * @returns {ng.$compileProvider} Self for chaining.
6901   */
6902   this.directive = function registerDirective(name, directiveFactory) {
6903    assertNotHasOwnProperty(name, 'directive');
6904    if (isString(name)) {
6905      assertValidDirectiveName(name);
6906      assertArg(directiveFactory, 'directiveFactory');
6907      if (!hasDirectives.hasOwnProperty(name)) {
6908        hasDirectives[name] = [];
6909        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
6910          function($injector, $exceptionHandler) {
6911            var directives = [];
6912            forEach(hasDirectives[name], function(directiveFactory, index) {
6913              try {
6914                var directive = $injector.invoke(directiveFactory);
6915                if (isFunction(directive)) {
6916                  directive = { compile: valueFn(directive) };
6917                } else if (!directive.compile && directive.link) {
6918                  directive.compile = valueFn(directive.link);
6919                }
6920                directive.priority = directive.priority || 0;
6921                directive.index = index;
6922                directive.name = directive.name || name;
6923                directive.require = directive.require || (directive.controller && directive.name);
6924                directive.restrict = directive.restrict || 'EA';
6925                var bindings = directive.$$bindings =
6926                    parseDirectiveBindings(directive, directive.name);
6927                if (isObject(bindings.isolateScope)) {
6928                  directive.$$isolateBindings = bindings.isolateScope;
6929                }
6930                directives.push(directive);
6931              } catch (e) {
6932                $exceptionHandler(e);
6933              }
6934            });
6935            return directives;
6936          }]);
6937      }
6938      hasDirectives[name].push(directiveFactory);
6939    } else {
6940      forEach(name, reverseParams(registerDirective));
6941    }
6942    return this;
6943  };
6944
6945
6946  /**
6947   * @ngdoc method
6948   * @name $compileProvider#aHrefSanitizationWhitelist
6949   * @kind function
6950   *
6951   * @description
6952   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6953   * urls during a[href] sanitization.
6954   *
6955   * The sanitization is a security measure aimed at preventing XSS attacks via html links.
6956   *
6957   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
6958   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
6959   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
6960   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6961   *
6962   * @param {RegExp=} regexp New regexp to whitelist urls with.
6963   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6964   *    chaining otherwise.
6965   */
6966  this.aHrefSanitizationWhitelist = function(regexp) {
6967    if (isDefined(regexp)) {
6968      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
6969      return this;
6970    } else {
6971      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
6972    }
6973  };
6974
6975
6976  /**
6977   * @ngdoc method
6978   * @name $compileProvider#imgSrcSanitizationWhitelist
6979   * @kind function
6980   *
6981   * @description
6982   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
6983   * urls during img[src] sanitization.
6984   *
6985   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
6986   *
6987   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
6988   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
6989   * regular expression. If a match is found, the original url is 
6989written into the dom. Otherwise,
6990   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
6991   *
6992   * @param {RegExp=} regexp New regexp to whitelist urls with.
6993   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
6994   *    chaining otherwise.
6995   */
6996  this.imgSrcSanitizationWhitelist = function(regexp) {
6997    if (isDefined(regexp)) {
6998      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
6999      return this;
7000    } else {
7001      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
7002    }
7003  };
7004
7005  /**
7006   * @ngdoc method
7007   * @name  $compileProvider#debugInfoEnabled
7008   *
7009   * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
7010   * current debugInfoEnabled state
7011   * @returns {*} current value if used as getter or itself (chaining) if used as setter
7012   *
7013   * @kind function
7014   *
7015   * @description
7016   * Call this method to enable/disable various debug runtime information in the compiler such as adding
7017   * binding information and a reference to the current scope on to DOM elements.
7018   * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
7019   * * `ng-binding` CSS class
7020   * * `$binding` data property containing an array of the binding expressions
7021   *
7022   * You may want to disable this in production for a significant performance boost. See
7023   * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
7024   *
7025   * The default value is true.
7026   */
7027  var debugInfoEnabled = true;
7028  this.debugInfoEnabled = function(enabled) {
7029    if (isDefined(enabled)) {
7030      debugInfoEnabled = enabled;
7031      return this;
7032    }
7033    return debugInfoEnabled;
7034  };
7035
7036  this.$get = [
7037            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
7038            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
7039    function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
7040             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
7041
7042    var Attributes = function(element, attributesToCopy) {
7043      if (attributesToCopy) {
7044        var keys = Object.keys(attributesToCopy);
7045        var i, l, key;
7046
7047        for (i = 0, l = keys.length; i < l; i++) {
7048          key = keys[i];
7049          this[key] = attributesToCopy[key];
7050        }
7051      } else {
7052        this.$attr = {};
7053      }
7054
7055      this.$$element = element;
7056    };
7057
7058    Attributes.prototype = {
7059      /**
7060       * @ngdoc method
7061       * @name $compile.directive.Attributes#$normalize
7062       * @kind function
7063       *
7064       * @description
7065       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
7066       * `data-`) to its normalized, camelCase form.
7067       *
7068       * Also there is special case for Moz prefix starting with upper case letter.
7069       *
7070       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
7071       *
7072       * @param {string} name Name to normalize
7073       */
7074      $normalize: directiveNormalize,
7075
7076
7077      /**
7078       * @ngdoc method
7079       * @name $compile.directive.Attributes#$addClass
7080       * @kind function
7081       *
7082       * @description
7083       * Adds the CSS class value specified by the classVal parameter to the element. If animations
7084       * are enabled then an animation will be triggered for the class addition.
7085       *
7086       * @param {string} classVal The className value that will be added to the element
7087       */
7088      $addClass: function(classVal) {
7089        if (classVal && classVal.length > 0) {
7090          $animate.addClass(this.$$element, classVal);
7091        }
7092      },
7093
7094      /**
7095       * @ngdoc method
7096       * @name $compile.directive.Attributes#$removeClass
7097       * @kind function
7098       *
7099       * @description
7100       * Removes the CSS class value specified by the classVal parameter from the element. If
7101       * animations are enabled then an animation will be triggered for the class removal.
7102       *
7103       * @param {string} classVal The className value that will be removed from the element
7104       */
7105      $removeClass: function(classVal) {
7106        if (classVal && classVal.length > 0) {
7107          $animate.removeClass(this.$$element, classVal);
7108        }
7109      },
7110
7111      /**
7112       * @ngdoc method
7113       * @name $compile.directive.Attributes#$updateClass
7114       * @kind function
7115       *
7116       * @description
7117       * Adds and removes the appropriate CSS class values to the element based on the difference
7118       * between the new and old CSS class values (specified as newClasses and oldClasses).
7119       *
7120       * @param {string} newClasses The current CSS className value
7121       * @param {string} oldClasses The former CSS className value
7122       */
7123      $updateClass: function(newClasses, oldClasses) {
7124        var toAdd = tokenDifference(newClasses, oldClasses);
7125        if (toAdd && toAdd.length) {
7126          $animate.addClass(this.$$element, toAdd);
7127        }
7128
7129        var toRemove = tokenDifference(oldClasses, newClasses);
7130        if (toRemove && toRemove.length) {
7131          $animate.removeClass(this.$$element, toRemove);
7132        }
7133      },
7134
7135      /**
7136       * Set a normalized attribute on the element in a way such that all directives
7137       * can share the attribute. This function properly handles boolean attributes.
7138       * @param {string} key Normalized key. (ie ngAttribute)
7139       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
7140       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
7141       *     Defaults to true.
7142       * @param {string=} attrName Optional none normalized name. Defaults to key.
7143       */
7144      $set: function(key, value, writeAttr, attrName) {
7145        // TODO: decide whether or not to throw an error if "class"
7146        //is set through this function since it may cause $updateClass to
7147        //become unstable.
7148
7149        var node = this.$$element[0],
7150            booleanKey = getBooleanAttrName(node, key),
7151            aliasedKey = getAliasedAttrName(node, key),
7152            observer = key,
7153            nodeName;
7154
7155        if (booleanKey) {
7156          this.$$element.prop(key, value);
7157          attrName = booleanKey;
7158        } else if (aliasedKey) {
7159          this[aliasedKey] = value;
7160          observer = aliasedKey;
7161        }
7162
7163        this[key] = value;
7164
7165        // translate normalized key to actual key
7166        if (attrName) {
7167          this.$attr[key] = attrName;
7168        } else {
7169          attrName = this.$attr[key];
7170          if (!attrName) {
7171            this.$attr[key] = attrName = snake_case(key, '-');
7172          }
7173        }
7174
7175        nodeName = nodeName_(this.$$element);
7176
7177        if ((nodeName === 'a' && key === 'href') ||
7178            (nodeName === 'img' && key === 'src')) {
7179          // sanitize a[href] and img[src] values
7180          this[key] = value = $$sanitizeUri(value, key === 'src');
7181        } else if (nodeName === 'img' && key === 'srcset') {
7182          // sanitize img[srcset] values
7183          var result = "";
7184
7185          // first check if there are spaces because it's not the same pattern
7186          var trimmedSrcset = trim(value);
7187          //                (   999x   ,|   999w   ,|   ,|,   )
7188          var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
7189          var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
7190
7191          // split srcset into tuple of uri and descriptor except for the last item
7192          var rawUris = trimmedSrcset.split(pattern);
7193
7194          // for each tuples
7195          var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
7196          for (var i = 0; i < nbrUrisWith2parts; i++) {
7197            var innerIdx = i * 2;
7198            // sanitize the uri
7199            result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
7200            // add the descriptor
7201            result += (" " + trim(rawUris[innerIdx + 1]));
7202          }
7203
7204          // split the last item into uri and descriptor
7205          var lastTuple = trim(rawUris[i * 2]).split(/\s/);
7206
7207          // sanitize the last uri
7208          result += $$sanitizeUri(trim(lastTuple[0]), true);
7209
7210          // and add the last descriptor if any
7211          if (lastTuple.length === 2) {
7212            result += (" " + trim(lastTuple[1]));
7213          }
7214          this[key] = value = result;
7215        }
7216
7217        if (writeAttr !== false) {
7218          if (value === null || value === undefined) {
7219            this.$$element.removeAttr(attrName);
7220          } else {
7221            this.$$element.attr(attrName, value);
7222          }
7223        }
7224
7225        // fire observers
7226        var $$observers = this.$$observers;
7227        $$observers && forEach($$observers[observer], function(fn) {
7228          try {
7229            fn(value);
7230          } catch (e) {
7231            $exceptionHandler(e);
7232          }
7233        });
7234      },
7235
7236
7237      /**
7238       * @ngdoc method
7239       * @name $compile.directive.Attributes#$observe
7240       * @kind function
7241       *
7242       * @description
7243       * Observes an interpolated attribute.
7244       *
7245       * The observer function will be invoked once during the next `$digest` following
7246       * compilation. The observer is then invoked whenever the interpolated value
7247       * changes.
7248       *
7249       * @param {string} key Normalized key. (ie ngAttribute) .
7250       * @param {function(interpolatedValue)} fn Function that will be called whenever
7251                the interpolated value of the attribute changes.
7252       *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
7253       * @returns {function()} Returns a deregistration function for this observer.
7254       */
7255      $observe: function(key, fn) {
7256        var attrs = this,
7257            $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
7258            listeners = ($$observers[key] || ($$observers[key] = []));
7259
7260        listeners.push(fn);
7261        $rootScope.$evalAsync(function() {
7262          if (!listeners.$$inter && attrs.hasOwnProperty(key)) {
7263            // no one registered attribute interpolation function, so lets call it manually
7264            fn(attrs[key]);
7265          }
7266        });
7267
7268        return function() {
7269          arrayRemove(listeners, fn);
7270        };
7271      }
7272    };
7273
7274
7275    function safeAddClass($element, className) {
7276      try {
7277        $element.addClass(className);
7278      } catch (e) {
7279        // ignore, since it means that we are trying to set class on
7280        // SVG element, where class name is read-only.
7281      }
7282    }
7283
7284
7285    var startSymbol = $interpolate.startSymbol(),
7286        endSymbol = $interpolate.endSymbol(),
7287        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
7288            ? identity
7289            : function denormalizeTemplate(template) {
7290              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7291        },
7292        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7293
7294    compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7295      var bindings = $element.data('$binding') || [];
7296
7297      if (isArray(binding)) {
7298        bindings = bindings.concat(binding);
7299      } else {
7300        bindings.push(binding);
7301      }
7302
7303      $element.data('$binding', bindings);
7304    } : noop;
7305
7306    compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
7307      safeAddClass($element, 'ng-binding');
7308    } : noop;
7309
7310    compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
7311      var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
7312      $element.data(dataName, scope);
7313    } : noop;
7314
7315    compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
7316      safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
7317    } : noop;
7318
7319    return compile;
7320
7321    //================================
7322
7323    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
7324                        previousCompileContext) {
7325      if (!($compileNodes instanceof jqLite)) {
7326        // jquery always rewraps, whereas we need to preserve the original selector so that we can
7327        // modify it.
7328        $compileNodes = jqLite($compileNodes);
7329      }
7330      // We can not compile top level text elements since text nodes can be merged and we will
7331      // not be able to attach scope data to them, so we will wrap them in <span>
7332      forEach($compileNodes, function(node, index) {
7333        if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
7334          $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
7335        }
7336      });
7337      var compositeLinkFn =
7338              compileNodes($compileNodes, transcludeFn, $compileNodes,
7339                           maxPriority, ignoreDirective, previousCompileContext);
7340      compile.$$addScopeClass($compileNodes);
7341      var namespace = null;
7342      return function publicLinkFn(scope, cloneConnectFn, options) {
7343        assertArg(scope, 'scope');
7344
7345        options = options || {};
7346        var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7347          transcludeControllers = options.transcludeControllers,
7348          futureParentElement = options.futureParentElement;
7349
7350        // When `parentBoundTranscludeFn` is passed, it is a
7351        // `controllersBoundTransclude` function (it was previously passed
7352        // as `transclude` to directive.link) so we must unwrap it to get
7353        // its `boundTranscludeFn`
7354        if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
7355          parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
7356        }
7357
7358        if (!namespace) {
7359          namespace = detectNamespaceForChildElements(futureParentElement);
7360        }
7361        var $linkNode;
7362        if (namespace !== 'html') {
7363          // When using a directive with replace:true and templateUrl the $compileNodes
7364          // (or a child element inside of them)
7365          // might change, so we need to recreate the namespace adapted compileNodes
7366          // for call to the link function.
7367          // Note: This will already clone the nodes...
7368          $linkNode = jqLite(
7369            wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
7370          );
7371        } else if (cloneConnectFn) {
7372          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
vendor: 8,070 bytes, lines 7373-7568
7373          // and sometimes changes the structure of the DOM.
7374          $linkNode = JQLitePrototype.clone.call($compileNodes);
7375        } else {
7376          $linkNode = $compileNodes;
7377        }
7378
7379        if (transcludeControllers) {
7380          for (var controllerName in transcludeControllers) {
7381            $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
7382          }
7383        }
7384
7385        compile.$$addScopeInfo($linkNode, scope);
7386
7387        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
7388        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
7389        return $linkNode;
7390      };
7391    }
7392
7393    function detectNamespaceForChildElements(parentElement) {
7394      // TODO: Make this detect MathML as well...
7395      var node = parentElement && parentElement[0];
7396      if (!node) {
7397        return 'html';
7398      } else {
7399        return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
7400      }
7401    }
7402
7403    /**
7404     * Compile function matches each node in nodeList against the directives. Once all directives
7405     * for a particular node are collected their compile functions are executed. The compile
7406     * functions return values - the linking functions - are combined into a composite linking
7407     * function, which is the a linking function for the node.
7408     *
7409     * @param {NodeList} nodeList an array of nodes or NodeList to compile
7410     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7411     *        scope argument is auto-generated to the new child of the transcluded parent scope.
7412     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
7413     *        the rootElement must be set the jqLite collection of the compile root. This is
7414     *        needed so that the jqLite collection items can be replaced with widgets.
7415     * @param {number=} maxPriority Max directive priority.
7416     * @returns {Function} A composite linking function of all of the matched directives or null.
7417     */
7418    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
7419                            previousCompileContext) {
7420      var linkFns = [],
7421          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
7422
7423      for (var i = 0; i < nodeList.length; i++) {
7424        attrs = new Attributes();
7425
7426        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
7427        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
7428                                        ignoreDirective);
7429
7430        nodeLinkFn = (directives.length)
7431            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
7432                                      null, [], [], previousCompileContext)
7433            : null;
7434
7435        if (nodeLinkFn && nodeLinkFn.scope) {
7436          compile.$$addScopeClass(attrs.$$element);
7437        }
7438
7439        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
7440                      !(childNodes = nodeList[i].childNodes) ||
7441                      !childNodes.length)
7442            ? null
7443            : compileNodes(childNodes,
7444                 nodeLinkFn ? (
7445                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
7446                     && nodeLinkFn.transclude) : transcludeFn);
7447
7448        if (nodeLinkFn || childLinkFn) {
7449          linkFns.push(i, nodeLinkFn, childLinkFn);
7450          linkFnFound = true;
7451          nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
7452        }
7453
7454        //use the previous context only for the first element in the virtual group
7455        previousCompileContext = null;
7456      }
7457
7458      // return a linking function if we have found anything, null otherwise
7459      return linkFnFound ? compositeLinkFn : null;
7460
7461      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
7462        var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
7463        var stableNodeList;
7464
7465
7466        if (nodeLinkFnFound) {
7467          // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
7468          // offsets don't get screwed up
7469          var nodeListLength = nodeList.length;
7470          stableNodeList = new Array(nodeListLength);
7471
7472          // create a sparse array by only copying the elements which have a linkFn
7473          for (i = 0; i < linkFns.length; i+=3) {
7474            idx = linkFns[i];
7475            stableNodeList[idx] = nodeList[idx];
7476          }
7477        } else {
7478          stableNodeList = nodeList;
7479        }
7480
7481        for (i = 0, ii = linkFns.length; i < ii;) {
7482          node = stableNodeList[linkFns[i++]];
7483          nodeLinkFn = linkFns[i++];
7484          childLinkFn = linkFns[i++];
7485
7486          if (nodeLinkFn) {
7487            if (nodeLinkFn.scope) {
7488              childScope = scope.$new();
7489              compile.$$addScopeInfo(jqLite(node), childScope);
7490              var destroyBindings = nodeLinkFn.$$destroyBindings;
7491              if (destroyBindings) {
7492                nodeLinkFn.$$destroyBindings = null;
7493                childScope.$on('$destroyed', destroyBindings);
7494              }
7495            } else {
7496              childScope = scope;
7497            }
7498
7499            if (nodeLinkFn.transcludeOnThisElement) {
7500              childBoundTranscludeFn = createBoundTranscludeFn(
7501                  scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
7502                  nodeLinkFn.elementTranscludeOnThisElement);
7503
7504            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
7505              childBoundTranscludeFn = parentBoundTranscludeFn;
7506
7507            } else if (!parentBoundTranscludeFn && transcludeFn) {
7508              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
7509
7510            } else {
7511              childBoundTranscludeFn = null;
7512            }
7513
7514            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn,
7515                       nodeLinkFn);
7516
7517          } else if (childLinkFn) {
7518            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
7519          }
7520        }
7521      }
7522    }
7523
7524    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
7525
7526      var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
7527
7528        if (!transcludedScope) {
7529          transcludedScope = scope.$new(false, containingScope);
7530          transcludedScope.$$transcluded = true;
7531        }
7532
7533        return transcludeFn(transcludedScope, cloneFn, {
7534          parentBoundTranscludeFn: previousBoundTranscludeFn,
7535          transcludeControllers: controllers,
7536          futureParentElement: futureParentElement
7537        });
7538      };
7539
7540      return boundTranscludeFn;
7541    }
7542
7543    /**
7544     * Looks for directives on the given node and adds them to the directive collection which is
7545     * sorted.
7546     *
7547     * @param node Node to search.
7548     * @param directives An array to which the directives are added to. This array is sorted before
7549     *        the function returns.
7550     * @param attrs The shared attrs object which is used to populate the normalized attributes.
7551     * @param {number=} maxPriority Max directive priority.
7552     */
7553    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
7554      var nodeType = node.nodeType,
7555          attrsMap = attrs.$attr,
7556          match,
7557          className;
7558
7559      switch (nodeType) {
7560        case NODE_TYPE_ELEMENT: /* Element */
7561          // use the node name: <directive>
7562          addDirective(directives,
7563              directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
7564
7565          // iterate over the attributes
7566          for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
7567                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
7568            var attrStartName = false;
7569            var attrEndName = false;
7570
7571            attr = nAttrs[j];
7572            name = attr.name;
7573            value = trim(attr.value);
7574
7575            // support ngAttr attribute binding
7576            ngAttrName = directiveNormalize(name);
7577            if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
7578              name = name.replace(PREFIX_REGEXP, '')
7579                .substr(8).replace(/_(.)/g, function(match, letter) {
7580                  return letter.toUpperCase();
7581                });
7582            }
7583
7584            var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
7585            if (directiveIsMultiElement(directiveNName)) {
7586              if (ngAttrName === directiveNName + 'Start') {
7587                attrStartName = name;
7588                attrEndName = name.substr(0, name.length - 5) + 'end';
7589                name = name.substr(0, name.length - 6);
7590              }
7591            }
7592
7593            nName = directiveNormalize(name.toLowerCase());
7594            attrsMap[nName] = name;
7595            if (isNgAttr || !attrs.hasOwnProperty(nName)) {
7596                attrs[nName] = value;
7597                if (getBooleanAttrName(node, nName)) {
7598                  attrs[nName] = true; // presence means true
7599                }
7600            }
7601            addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
7602            addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
7603                          attrEndName);
7604          }
7605
7606          // use class as directive
7607          className = node.className;
7608          if (isObject(className)) {
7609              // Maybe SVGAnimatedString
7610              className = className.animVal;
7611          }
7612          if (isString(className) && className !== '') {
7613            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
7614              nName = directiveNormalize(match[2]);
7615              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
7616                attrs[nName] = trim(match[3]);
7617              }
7618              className = className.substr(match.index + match[0].length);
7619            }
7620          }
7621          break;
7622        case NODE_TYPE_TEXT: /* Text Node */
7623          addTextInterpolateDirective(directives, node.nodeValue);
7624          break;
7625        case NODE_TYPE_COMMENT: /* Comment */
7626          try {
7627            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
7628            if (match) {
7629              nName = directiveNormalize(match[1]);
7630              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
7631                attrs[nName] = trim(match[2]);
7632              }
7633            }
7634          } catch (e) {
7635            // turns out that under some circumstances IE9 throws errors when one attempts to read
7636            // comment's node value.
7637            // Just ignore it and continue. (Can't seem to reproduce in test case.)
7638          }
7639          break;
7640      }
7641
7642      directives.sort(byPriority);
7643      return directives;
7644    }
7645
7646    /**
7647     * Given a node with an directive-start it collects all of the siblings until it finds
7648     * directive-end.
7649     * @param node
7650     * @param attrStart
7651     * @param attrEnd
7652     * @returns {*}
7653     */
7654    function groupScan(node, attrStart, attrEnd) {
7655      var nodes = [];
7656      var depth = 0;
7657      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
7658        do {
7659          if (!node) {
7660            throw $compileMinErr('uterdir',
7661                      "Unterminated attribute, found '{0}' but no matching '{1}' found.",
7662                      attrStart, attrEnd);
7663          }
7664          if (node.nodeType == NODE_TYPE_ELEMENT) {
7665            if (node.hasAttribute(attrStart)) depth++;
7666            if (node.hasAttribute(attrEnd)) depth--;
7667          }
7668          nodes.push(node);
7669          node = node.nextSibling;
7670        } while (depth > 0);
7671      } else {
7672        nodes.push(node);
7673      }
7674
7675      return jqLite(nodes);
7676    }
7677
7678    /**
7679     * Wrapper for linking function which converts normal linking function into a grouped
7680     * linking function.
7681     * @param linkFn
7682     * @param attrStart
7683     * @param attrEnd
7684     * @returns {Function}
7685     */
7686    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
7687      return function(scope, element, attrs, controllers, transcludeFn) {
7688        element = groupScan(element[0], attrStart, attrEnd);
7689        return linkFn(scope, element, attrs, controllers, transcludeFn);
7690      };
7691    }
7692
7693    /**
7694     * Once the directives have been collected, their compile functions are executed. This method
7695     * is responsible for inlining directive templates as well as terminating the application
7696     * of the directives if the terminal directive has been reached.
7697     *
7698     * @param {Array} directives Array of collected directives to execute their compile function.
7699     *        this needs to be pre-sorted by priority order.
7700     * @param {Node} compileNode The raw DOM node to apply the compile functions to
7701     * @param {Object} templateAttrs The shared attribute function
7702     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
7703     *                                                  scope argument is auto-generated to the new
7704     *                                                  child of the transcluded parent scope.
7705     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
7706     *                              argument has the root jqLite array so that we can replace nodes
7707     *                              on it.
7708     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
7709     *                                           compiling the transclusion.
7710     * @param {Array.<Function>} preLinkFns
7711     * @param {Array.<Function>} postLinkFns
7712     * @param {Object} previousCompileContext Context used for previous compilation of the current
7713     *                                        node
7714     * @returns {Function} linkFn
7715     */
7716    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
7717                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
7718                                   previousCompileContext) {
7719      previousCompileContext = previousCompileContext || {};
7720
7721      var terminalPriority = -Number.MAX_VALUE,
7722          newScopeDirective,
7723          controllerDirectives = previousCompileContext.controllerDirectives,
7724          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
7725          templateDirective = previousCompileContext.templateDirective,
7726          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
7727          hasTranscludeDirective = false,
7728          hasTemplate = false,
7729          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
7730          $compileNode = templateAttrs.$$element = jqLite(compileNode),
7731          directive,
7732          directiveName,
7733          $template,
7734          replaceDirective = originalReplaceDirective,
7735          childTranscludeFn = transcludeFn,
7736          linkFn,
7737          directiveValue;
7738
7739      // executes all directives on the current element
7740      for (var i = 0, ii = directives.length; i < ii; i++) {
7741        directive = directives[i];
7742        var attrStart = directive.$$start;
7743        var attrEnd = directive.$$end;
7744
7745        // collect multiblock sections
7746        if (attrStart) {
7747          $compileNode = groupScan(compileNode, attrStart, attrEnd);
7748        }
7749        $template = undefined;
7750
7751        if (terminalPriority > directive.priority) {
7752          break; // prevent further processing of directives
7753        }
7754
7755        if (directiveValue = directive.scope) {
7756
7757          // skip the check for directives with async templates, we'll check the derived sync
7758          // directive when the template arrives
7759          if (!directive.templateUrl) {
7760            if (isObject(directiveValue)) {
7761              // This directive is trying to add an isolated scope.
7762              // Check that there is no scope of any kind already
7763              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
7764                                directive, $compileNode);
7765              newIsolateScopeDirective = directive;
7766            } else {
7767              // This directive is trying to add a child scope.
7768              // Check that there is no isolated scope already
7769              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
7770                                $compileNode);
7771            }
7772          }
7773
7774          newScopeDirective = newScopeDirective || directive;
7775        }
7776
7777        directiveName = directive.name;
7778
7779        if (!directive.templateUrl && directive.controller) {
7780          directiveValue = directive.controller;
7781          controllerDirectives = controllerDirectives || createMap();
7782          assertNoDuplicate("'" + directiveName + "' controller",
7783              controllerDirectives[directiveName], directive, $compileNode);
7784          controllerDirectives[directiveName] = directive;
7785        }
7786
7787        if (directiveValue = directive.transclude) {
7788          hasTranscludeDirective = true;
7789
7790          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
7791          // This option should only be used by directives that know how to safely handle element transclusion,
7792          // where the transcluded nodes are added or replaced after linking.
7793          if (!directive.$$tlb) {
7794            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
7795            nonTlbTranscludeDirective = directive;
7796          }
7797
7798          if (directiveValue == 'element') {
7799            hasElementTranscludeDirective = true;
7800            terminalPriority = directive.priority;
7801            $template = $compileNode;
7802            $compileNode = templateAttrs.$$element =
7803                jqLite(document.createComment(' ' + directiveName + ': ' +
7804                                              templateAttrs[directiveName] + ' '));
7805            compileNode = $compileNode[0];
7806            replaceWith(jqCollection, sliceArgs($template), compileNode);
7807
7808            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
7809                                        replaceDirective && replaceDirective.name, {
7810                                          // Don't pass in:
7811                                          // - controllerDirectives - otherwise we'll create duplicates controllers
7812                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 4,751 bytes, lines 7812-7920
7812ining templates with
7813                                          //   element transclusion doesn't make sense.
7814                                          //
7815                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
7816                                          // on the same element more than once.
7817                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
7818                                        });
7819          } else {
7820            $template = jqLite(jqLiteClone(compileNode)).contents();
7821            $compileNode.empty(); // clear contents
7822            childTranscludeFn = compile($template, transcludeFn);
7823          }
7824        }
7825
7826        if (directive.template) {
7827          hasTemplate = true;
7828          assertNoDuplicate('template', templateDirective, directive, $compileNode);
7829          templateDirective = directive;
7830
7831          directiveValue = (isFunction(directive.template))
7832              ? directive.template($compileNode, templateAttrs)
7833              : directive.template;
7834
7835          directiveValue = denormalizeTemplate(directiveValue);
7836
7837          if (directive.replace) {
7838            replaceDirective = directive;
7839            if (jqLiteIsTextNode(directiveValue)) {
7840              $template = [];
7841            } else {
7842              $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
7843            }
7844            compileNode = $template[0];
7845
7846            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
7847              throw $compileMinErr('tplrt',
7848                  "Template for directive '{0}' must have exactly one root element. {1}",
7849                  directiveName, '');
7850            }
7851
7852            replaceWith(jqCollection, $compileNode, compileNode);
7853
7854            var newTemplateAttrs = {$attr: {}};
7855
7856            // combine directives from the original node and from the template:
7857            // - take the array of directives for this element
7858            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
7859            // - collect directives from the template and sort them by priority
7860            // - combine directives as: processed + template + unprocessed
7861            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
7862            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
7863
7864            if (newIsolateScopeDirective) {
7865              markDirectivesAsIsolate(templateDirectives);
7866            }
7867            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
7868            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
7869
7870            ii = directives.length;
7871          } else {
7872            $compileNode.html(directiveValue);
7873          }
7874        }
7875
7876        if (directive.templateUrl) {
7877          hasTemplate = true;
7878          assertNoDuplicate('template', templateDirective, directive, $compileNode);
7879          templateDirective = directive;
7880
7881          if (directive.replace) {
7882            replaceDirective = directive;
7883          }
7884
7885          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
7886              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
7887                controllerDirectives: controllerDirectives,
7888                newIsolateScopeDirective: newIsolateScopeDirective,
7889                templateDirective: templateDirective,
7890                nonTlbTranscludeDirective: nonTlbTranscludeDirective
7891              });
7892          ii = directives.length;
7893        } else if (directive.compile) {
7894          try {
7895            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
7896            if (isFunction(linkFn)) {
7897              addLinkFns(null, linkFn, attrStart, attrEnd);
7898            } else if (linkFn) {
7899              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
7900            }
7901          } catch (e) {
7902            $exceptionHandler(e, startingTag($compileNode));
7903          }
7904        }
7905
7906        if (directive.terminal) {
7907          nodeLinkFn.terminal = true;
7908          terminalPriority = Math.max(terminalPriority, directive.priority);
7909        }
7910
7911      }
7912
7913      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
7914      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
7915      nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
7916      nodeLinkFn.templateOnThisElement = hasTemplate;
7917      nodeLinkFn.transclude = childTranscludeFn;
7918
7919      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
7920
7921      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
7922      return nodeLinkFn;
7923
7924      ////////////////////
7925
7926      function addLinkFns(pre, post, attrStart, attrEnd) {
7927        if (pre) {
7928          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
7929          pre.require = directive.require;
7930          pre.directiveName = directiveName;
7931          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7932            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
7933          }
7934          preLinkFns.push(pre);
7935        }
7936        if (post) {
7937          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
7938          post.require = directive.require;
7939          post.directiveName = directiveName;
7940          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
7941            post = cloneAndAnnotateFn(post, {isolateScope: true});
7942          }
7943          postLinkFns.push(post);
7944        }
7945      }
7946
7947
7948      function getControllers(directiveName, require, $element, elementControllers) {
7949        var value;
7950
7951        if (isString(require)) {
7952          var match = require.match(REQUIRE_PREFIX_REGEXP);
7953          var name = require.substring(match[0].length);
7954          var inheritType = match[1] || match[3];
7955          var optional = match[2] === '?';
7956
7957          //If only parents then start at the parent element
7958          if (inheritType === '^^') {
7959            $element = $element.parent();
7960          //Otherwise attempt getting the controller from elementControllers in case
7961          //the element is transcluded (and has no data) and to avoid .data if possible
7962          } else {
7963            value = elementControllers && elementControllers[name];
7964            value = value && value.instance;
7965          }
7966
7967          if (!value) {
7968            var dataName = '$' + name + 'Controller';
7969            value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
7970          }
7971
7972          if (!value && !optional) {
7973            throw $compileMinErr('ctreq',
7974                "Controller '{0}', required by directive '{1}', can't be found!",
7975                name, directiveName);
7976          }
7977        } else if (isArray(require)) {
7978          value = [];
7979          for (var i = 0, ii = require.length; i < ii; i++) {
7980            value[i] = getControllers(directiveName, require[i], $element, elementControllers);
7981          }
7982        }
7983
7984        return value || null;
7985      }
7986
7987      function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
7988        var elementControllers = createMap();
7989        for (var controllerKey in controllerDirectives) {
7990          var directive = controllerDirectives[controllerKey];
7991          var locals = {
7992            $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
7993            $element: $element,
7994            $attrs: attrs,
7995            $transclude: transcludeFn
7996          };
7997
7998          var controller = directive.controller;
7999          if (controller == '@') {
8000            controller = attrs[directive.name];
8001          }
8002
8003          var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
8004
8005          // For directives with element transclusion the element is a comment,
8006          // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
8007          // clean up (http://bugs.jquery.com/ticket/8335).
8008          // Instead, we save the controllers for the element in a local hash and attach to .data
8009          // later, once we have the actual element.
8010          elementControllers[directive.name] = controllerInstance;
8011          if (!hasElementTranscludeDirective) {
8012            $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
8013          }
8014        }
8015        return elementControllers;
8016      }
8017
8018      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn,
8019                          thisLinkFn) {
8020        var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
8021            attrs;
8022
8023        if (compileNode === linkNode) {
8024          attrs = templateAttrs;
8025          $element = templateAttrs.$$element;
8026        } else {
8027          $element = jqLite(linkNode);
8028          attrs = new Attributes($element, templateAttrs);
8029        }
8030
8031        if (newIsolateScopeDirective) {
8032          isolateScope = scope.$new(true);
8033        }
8034
8035        if (boundTranscludeFn) {
8036          // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
8037          // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
8038          transcludeFn = controllersBoundTransclude;
8039          transcludeFn.$$boundTransclude = boundTranscludeFn;
8040        }
8041
8042        if (controllerDirectives) {
8043          elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
8044        }
8045
8046        if (newIsolateScopeDirective) {
8047          // Initialize isolate scope bindings for new isolate scope directive.
8048          compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
8049              templateDirective === newIsolateScopeDirective.$$originalDirective)));
8050          compile.$$addScopeClass($element, true);
8051          isolateScope.$$isolateBindings =
8052              newIsolateScopeDirective.$$isolateBindings;
8053          initializeDirectiveBindings(scope, attrs, isolateScope,
8054                                      isolateScope.$$isolateBindings,
8055                                      newIsolateScopeDirective, isolateScope);
8056        }
8057        if (elementControllers) {
8058          // Initialize bindToController bindings for new/isolate scopes
8059          var scopeDirective = newIsolateScopeDirective || newScopeDirective;
8060          var bindings;
8061          var controllerForBindings;
8062          if (scopeDirective && elementControllers[scopeDirective.name]) {
8063            bindings = scopeDirective.$$bindings.bindToController;
8064            controller = elementControllers[scopeDirective.name];
8065
8066            if (controller && controller.identifier && bindings) {
8067              controllerForBindings = controller;
8068              thisLinkFn.$$destroyBindings =
8069                  initializeDirectiveBindings(scope, attrs, controller.instance,
8070                                              bindings, scopeDirective);
8071            }
8072          }
8073          for (i in elementControllers) {
8074            controller = elementControllers[i];
8075            var controllerResult = controller();
8076            if (controllerResult !== controller.instance) {
8077              controller.instance = controllerResult;
8078              $element.data('$' + directive.name + 'Controller', controllerResult);
8079              if (controller === controllerForBindings) {
8080                // Remove and re-install bindToController bindings
8081                thisLinkFn.$$destroyBindings();
8082                thisLinkFn.$$destroyBindings =
8083                  initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective);
8084              }
8085            }
8086          }
8087        }
8088
8089        // PRELINKING
8090        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
8091          linkFn = preLinkFns[i];
8092          invokeLinkFn(linkFn,
8093              linkFn.isolateScope ? isolateScope : scope,
8094              $element,
8095              attrs,
8096              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8097              transcludeFn
8098          );
8099        }
8100
8101        // RECURSION
8102        // We only pass the isolate scope, if the isolate directive has a template,
8103        // otherwise the child elements do not belong to the isolate directive.
8104        var scopeToChild = scope;
8105        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
8106          scopeToChild = isolateScope;
8107        }
8108        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
8109
8110        // POSTLINKING
8111        for (i = postLinkFns.length - 1; i >= 0; i--) {
8112          linkFn = postLinkFns[i];
8113          invokeLinkFn(linkFn,
8114              linkFn.isolateScope ? isolateScope : scope,
8115              $element,
8116              attrs,
8117              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
8118              transcludeFn
8119          );
8120        }
8121
8122        // This is the function that is injected as `$transclude`.
8123        // Note: all arguments are optional!
8124        function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
8125          var transcludeControllers;
8126
8127          // No scope passed in:
8128          if (!isScope(scope)) {
8129            futureParentElement = cloneAttachFn;
8130            cloneAttachFn = scope;
8131            scope = undefined;
8132          }
8133
8134          if (hasElementTranscludeDirective) {
8135            transcludeControllers = elementControllers;
8136          }
8137          if (!futureParentElement) {
8138            futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
8139          }
8140          return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
8141        }
8142      }
8143    }
8144
8145    function markDirectivesAsIsolate(directives) {
8146      // mark all directives as needing isolate scope.
8147      for (var j = 0, jj = directives.length; j < jj; j++) {
8148        directives[j] = inherit(directives[j], {$$isolateScope: true});
8149      }
8150    }
8151
8152    /**
8153     * looks up the directive and decorates it with exception handling and proper parameters. We
8154     * call this the boundDirective.
8155     *
8156     * @param {string} name name of the directive to look up.
8157     * @param {string} location The directive must be found in specific format.
8158     *   String containing any of theses characters:
8159     *
8160     *   * `E`: element name
8161     *   * `A': attribute
8162     *   * `C`: class
8163     *   * `M`: comment
8164     * @returns {boolean} true if directive was added.
8165     */
8166    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
8167                          endAttrName) {
8168      if (name === ignoreDirective) return null;
8169      var match = null;
8170      if (hasDirectives.hasOwnProperty(name)) {
8171        for (var directive, directives = $injector.get(name + Suffix),
8172            i = 0, ii = directives.length; i < ii; i++) {
8173          try {
8174            directive = directives[i];
8175            if ((maxPriority === undefined || maxPriority > directive.priority) &&
8176                 directive.restrict.indexOf(location) != -1) {
8177              if (startAttrName) {
8178                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
8179              }
8180              tDirectives.push(directive);
8181              match = directive;
8182            }
8183          } catch (e) { $exceptionHandler(e); }
8184        }
8185      }
8186      return match;
8187    }
8188
8189
8190    /**
8191     * looks up the directive and returns true if it is a multi-element directive,
8192     * and therefore requires DOM nodes between -start and -end markers to be grouped
8193     * together.
8194     *
8195     * @param {string} name name of the directive to look up.
8196     * @returns true if directive was registered as multi-element.
8197     */
8198    function directiveIsMultiElement(name) {
8199      if (hasDirectives.hasOwnProperty(name)) {
8200        for (var directive, directives = $injector.get(name + Suffix),
8201            i = 0, ii = directives.length; i < ii; i++) {
8202          directive = directives[i];
8203          if (directive.multiElement) {
8204            return true;
8205          }
8206        }
8207      }
8208      return false;
8209    }
8210
8211    /**
8212     * When the element is replaced with HTML template then the new attributes
8213     * on the template need to be merged with the existing attributes in the DOM.
8214     * The desired effect is to have both of the attributes present.
8215     *
8216     * @param {object} dst destination attributes (original DOM)
8217     * @param {object} src source attributes (from the directive template)
8218     */
8219    function mergeTemplateAttributes(dst, src) {
8220      var srcAttr = src.$attr,
8221          dstAttr = dst.$attr,
8222          $element = dst.$$element;
8223
8224      // reapply the old attributes to the new element
8225      forEach(dst, function(value, key) {
8226        if (key.charAt(0) != '$') {
8227          if (src[key] && src[key] !== value) {
8228            value += (key === 'style' ? ';' : ' ') + src[key];
8229          }
8230          dst.$set(key, value, true, srcAttr[key]);
8231        }
8232      });
8233
8234      // copy the new attributes on the old attrs object
8235      forEach(src, function(value, key) {
8236        if (key == 'class') {
8237          safeAddClass($element, value);
8238          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
8239        } else if (key == 'style') {
8240          $element.attr('style', $element.attr('style') + ';' + value);
8241          dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
8242          // `dst` will never contain hasOwnProperty as DOM parser won't let it.
8243          // You will get an "InvalidCharacterError: DOM Exception 5" error if you
8244          // have an attribute like "has-own-property" or "data-has-own-property", etc.
8245        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
8246          dst[key] = value;
8247          dstAttr[key] = srcAttr[key];
8248        }
8249      });
8250    }
8251
8252
8253    function compileTemplateUrl(directives, $compileNode, tAttrs,
8254        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
8255      var linkQueue = [],
8256          afterTemplateNodeLinkFn,
8257          afterTemplateChildLinkFn,
8258          beforeTemplateCompileNode = $compileNode[0],
8259          origAsyncDirective = directives.shift(),
8260          derivedSyncDirective = inherit(origAsyncDirective, {
8261            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
8262          }),
8263          templateUrl = (isFunction(origAsyncDirective.templateUrl))
8264              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
8265              : origAsyncDirective.templateUrl,
8266          templateNamespace = origAsyncDirective.templateNamespace;
8267
8268      $compileNode.empty();
8269
8270      $templateRequest($sce.getTrustedResourceUrl(templateUrl))
8271        .then(function(content) {
8272          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
8273
8274          content = denormalizeTemplate(content);
8275
8276          if (origAsyncDirective.replace) {
8277            if (jqLiteIsTextNode(content)) {
8278              $template = [];
8279            } else {
8280              $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
8281            }
8282            compileNode = $template[0];
8283
8284            if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
8285              throw $compileMinErr('tplrt',
8286                  "Template for directive '{0}' must have exactly one root element. {1}",
8287                  origAsyncDirective.name, templateUrl);
8288            }
8289
8290            tempTemplateAttrs = {$attr: {}};
8291            replaceWith($rootElement, $compileNode, compileNode);
8292            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8293
8294            if (isObject(origAsyncDirective.scope)) {
8295              markDirectivesAsIsolate(templateDirectives);
8296            }
8297            directives = templateDirectives.concat(directives);
8298            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
8299          } else {
8300            compileNode = beforeTemplateCompileNode;
8301            $compileNode.html(content);
8302          }
8303
8304          directives.unshift(derivedSyncDirective);
8305
8306          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
8307              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
8308              previousCompileContext);
vendor: 11,498 bytes, lines 8309-8578
8309          forEach($rootElement, function(node, i) {
8310            if (node == compileNode) {
8311              $rootElement[i] = $compileNode[0];
8312            }
8313          });
8314          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
8315
8316          while (linkQueue.length) {
8317            var scope = linkQueue.shift(),
8318                beforeTemplateLinkNode = linkQueue.shift(),
8319                linkRootElement = linkQueue.shift(),
8320                boundTranscludeFn = linkQueue.shift(),
8321                linkNode = $compileNode[0];
8322
8323            if (scope.$$destroyed) continue;
8324
8325            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
8326              var oldClasses = beforeTemplateLinkNode.className;
8327
8328              if (!(previousCompileContext.hasElementTranscludeDirective &&
8329                  origAsyncDirective.replace)) {
8330                // it was cloned therefore we have to clone as well.
8331                linkNode = jqLiteClone(compileNode);
8332              }
8333              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
8334
8335              // Copy in CSS classes from original node
8336              safeAddClass(jqLite(linkNode), oldClasses);
8337            }
8338            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8339              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8340            } else {
8341              childBoundTranscludeFn = boundTranscludeFn;
8342            }
8343            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8344              childBoundTranscludeFn, afterTemplateNodeLinkFn);
8345          }
8346          linkQueue = null;
8347        });
8348
8349      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
8350        var childBoundTranscludeFn = boundTranscludeFn;
8351        if (scope.$$destroyed) return;
8352        if (linkQueue) {
8353          linkQueue.push(scope,
8354                         node,
8355                         rootElement,
8356                         childBoundTranscludeFn);
8357        } else {
8358          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8359            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8360          }
8361          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn,
8362                                  afterTemplateNodeLinkFn);
8363        }
8364      };
8365    }
8366
8367
8368    /**
8369     * Sorting function for bound directives.
8370     */
8371    function byPriority(a, b) {
8372      var diff = b.priority - a.priority;
8373      if (diff !== 0) return diff;
8374      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
8375      return a.index - b.index;
8376    }
8377
8378
8379    function assertNoDuplicate(what, previousDirective, directive, element) {
8380      if (previousDirective) {
8381        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
8382            previousDirective.name, directive.name, what, startingTag(element));
8383      }
8384    }
8385
8386
8387    function addTextInterpolateDirective(directives, text) {
8388      var interpolateFn = $interpolate(text, true);
8389      if (interpolateFn) {
8390        directives.push({
8391          priority: 0,
8392          compile: function textInterpolateCompileFn(templateNode) {
8393            var templateNodeParent = templateNode.parent(),
8394                hasCompileParent = !!templateNodeParent.length;
8395
8396            // When transcluding a template that has bindings in the root
8397            // we don't have a parent and thus need to add the class during linking fn.
8398            if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
8399
8400            return function textInterpolateLinkFn(scope, node) {
8401              var parent = node.parent();
8402              if (!hasCompileParent) compile.$$addBindingClass(parent);
8403              compile.$$addBindingInfo(parent, interpolateFn.expressions);
8404              scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
8405                node[0].nodeValue = value;
8406              });
8407            };
8408          }
8409        });
8410      }
8411    }
8412
8413
8414    function wrapTemplate(type, template) {
8415      type = lowercase(type || 'html');
8416      switch (type) {
8417      case 'svg':
8418      case 'math':
8419        var wrapper = document.createElement('div');
8420        wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
8421        return wrapper.childNodes[0].childNodes;
8422      default:
8423        return template;
8424      }
8425    }
8426
8427
8428    function getTrustedContext(node, attrNormalizedName) {
8429      if (attrNormalizedName == "srcdoc") {
8430        return $sce.HTML;
8431      }
8432      var tag = nodeName_(node);
8433      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
8434      if (attrNormalizedName == "xlinkHref" ||
8435          (tag == "form" && attrNormalizedName == "action") ||
8436          (tag != "img" && (attrNormalizedName == "src" ||
8437                            attrNormalizedName == "ngSrc"))) {
8438        return $sce.RESOURCE_URL;
8439      }
8440    }
8441
8442
8443    function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
8444      var trustedContext = getTrustedContext(node, name);
8445      allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
8446
8447      var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
8448
8449      // no interpolation found -> ignore
8450      if (!interpolateFn) return;
8451
8452
8453      if (name === "multiple" && nodeName_(node) === "select") {
8454        throw $compileMinErr("selmulti",
8455            "Binding to the 'multiple' attribute is not supported. Element: {0}",
8456            startingTag(node));
8457      }
8458
8459      directives.push({
8460        priority: 100,
8461        compile: function() {
8462            return {
8463              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
8464                var $$observers = (attr.$$observers || (attr.$$observers = {}));
8465
8466                if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
8467                  throw $compileMinErr('nodomevents',
8468                      "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
8469                          "ng- versions (such as ng-click instead of onclick) instead.");
8470                }
8471
8472                // If the attribute has changed since last $interpolate()ed
8473                var newValue = attr[name];
8474                if (newValue !== value) {
8475                  // we need to interpolate again since the attribute value has been updated
8476                  // (e.g. by another directive's compile function)
8477                  // ensure unset/empty values make interpolateFn falsy
8478                  interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
8479                  value = newValue;
8480                }
8481
8482                // if attribute was updated so that there is no interpolation going on we don't want to
8483                // register any observers
8484                if (!interpolateFn) return;
8485
8486                // initialize attr object so that it's ready in case we need the value for isolate
8487                // scope initialization, otherwise the value would not be available from isolate
8488                // directive's linking fn during linking phase
8489                attr[name] = interpolateFn(scope);
8490
8491                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
8492                (attr.$$observers && attr.$$observers[name].$$scope || scope).
8493                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
8494                    //special case for class attribute addition + removal
8495                    //so that class changes can tap into the animation
8496                    //hooks provided by the $animate service. Be sure to
8497                    //skip animations when the first digest occurs (when
8498                    //both the new and the old values are the same) since
8499                    //the CSS classes are the non-interpolated values
8500                    if (name === 'class' && newValue != oldValue) {
8501                      attr.$updateClass(newValue, oldValue);
8502                    } else {
8503                      attr.$set(name, newValue);
8504                    }
8505                  });
8506              }
8507            };
8508          }
8509      });
8510    }
8511
8512
8513    /**
8514     * This is a special jqLite.replaceWith, which can replace items which
8515     * have no parents, provided that the containing jqLite collection is provided.
8516     *
8517     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
8518     *                               in the root of the tree.
8519     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
8520     *                                  the shell, but replace its DOM node reference.
8521     * @param {Node} newNode The new DOM node.
8522     */
8523    function replaceWith($rootElement, elementsToRemove, newNode) {
8524      var firstElementToRemove = elementsToRemove[0],
8525          removeCount = elementsToRemove.length,
8526          parent = firstElementToRemove.parentNode,
8527          i, ii;
8528
8529      if ($rootElement) {
8530        for (i = 0, ii = $rootElement.length; i < ii; i++) {
8531          if ($rootElement[i] == firstElementToRemove) {
8532            $rootElement[i++] = newNode;
8533            for (var j = i, j2 = j + removeCount - 1,
8534                     jj = $rootElement.length;
8535                 j < jj; j++, j2++) {
8536              if (j2 < jj) {
8537                $rootElement[j] = $rootElement[j2];
8538              } else {
8539                delete $rootElement[j];
8540              }
8541            }
8542            $rootElement.length -= removeCount - 1;
8543
8544            // If the replaced element is also the jQuery .context then replace it
8545            // .context is a deprecated jQuery api, so we should set it only when jQuery set it
8546            // http://api.jquery.com/context/
8547            if ($rootElement.context === firstElementToRemove) {
8548              $rootElement.context = newNode;
8549            }
8550            break;
8551          }
8552        }
8553      }
8554
8555      if (parent) {
8556        parent.replaceChild(newNode, firstElementToRemove);
8557      }
8558
8559      // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
8560      var fragment = document.createDocumentFragment();
8561      fragment.appendChild(firstElementToRemove);
8562
8563      // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8564      // data here because there's no public interface in jQuery to do that and copying over
8565      // event listeners (which is the main use of private data) wouldn't work anyway.
8566      jqLite(newNode).data(jqLite(firstElementToRemove).data());
8567
8568      // Remove data of the replaced element. We cannot just call .remove()
8569      // on the element it since that would deallocate scope that is needed
8570      // for the new node. Instead, remove the data "manually".
8571      if (!jQuery) {
8572        delete jqLite.cache[firstElementToRemove[jqLite.expando]];
8573      } else {
8574        // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
8575        // the replaced element. The cleanData version monkey-patched by Angular would cause
8576        // the scope to be trashed and we do need the very same scope to work with the new
8577        // element. However, we cannot just cache the non-patched version and use it here as
8578        // that would break if another library patches the method after Angular does (one
8579        // example is jQuery UI). Instead, set a flag indicating scope destroying should be
8580        // skipped this one time.
8581        skipDestroyOnNextJQueryCleanData = true;
8582        jQuery.cleanData([firstElementToRemove]);
8583      }
8584
8585      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
8586        var element = elementsToRemove[k];
8587        jqLite(element).remove(); // must do this way to clean up expando
8588        fragment.appendChild(element);
8589        delete elementsToRemove[k];
8590      }
8591
8592      elementsToRemove[0] = newNode;
8593      elementsToRemove.length = 1;
8594    }
8595
8596
8597    function cloneAndAnnotateFn(fn, annotation) {
8598      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
8599    }
8600
8601
8602    function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
8603      try {
8604        linkFn(scope, $element, attrs, controllers, transcludeFn);
8605      } catch (e) {
8606        $exceptionHandler(e, startingTag($element));
8607      }
8608    }
8609
8610
8611    // Set up $watches for isolate scope and controller bindings. This process
8612    // only occurs for isolate scopes and new scopes with controllerAs.
8613    function initializeDirectiveBindings(scope, attrs, destination, bindings,
8614                                         directive, newScope) {
8615      var onNewScopeDestroyed;
8616      forEach(bindings, function(definition, scopeName) {
8617        var attrName = definition.attrName,
8618        optional = definition.optional,
8619        mode = definition.mode, // @, =, or &
8620        lastValue,
8621        parentGet, parentSet, compare;
8622
8623        switch (mode) {
8624
8625          case '@':
8626            attrs.$observe(attrName, function(value) {
8627              destination[scopeName] = value;
8628            });
8629            attrs.$$observers[attrName].$$scope = scope;
8630            if (attrs[attrName]) {
8631              // If the attribute has been provided then we trigger an interpolation to ensure
8632              // the value is there for use in the link fn
8633              destination[scopeName] = $interpolate(attrs[attrName])(scope);
8634            }
8635            break;
8636
8637          case '=':
8638            if (optional && !attrs[attrName]) {
8639              return;
8640            }
8641            parentGet = $parse(attrs[attrName]);
8642            if (parentGet.literal) {
8643              compare = equals;
8644            } else {
8645              compare = function(a, b) { return a === b || (a !== a && b !== b); };
8646            }
8647            parentSet = parentGet.assign || function() {
8648              // reset the change, or we will throw this exception on every $digest
8649              lastValue = destination[scopeName] = parentGet(scope);
8650              throw $compileMinErr('nonassign',
8651                  "Expression '{0}' used with directive '{1}' is non-assignable!",
8652                  attrs[attrName], directive.name);
8653            };
8654            lastValue = destination[scopeName] = parentGet(scope);
8655            var parentValueWatch = function parentValueWatch(parentValue) {
8656              if (!compare(parentValue, destination[scopeName])) {
8657                // we are out of sync and need to copy
8658                if (!compare(parentValue, lastValue)) {
8659                  // parent changed and it has precedence
8660                  destination[scopeName] = parentValue;
8661                } else {
8662                  // if the parent can be assigned then do so
8663                  parentSet(scope, parentValue = destination[scopeName]);
8664                }
8665              }
8666              return lastValue = parentValue;
8667            };
8668            parentValueWatch.$stateful = true;
8669            var unwatch;
8670            if (definition.collection) {
8671              unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8672            } else {
8673              unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8674            }
8675            onNewScopeDestroyed = (onNewScopeDestroyed || []);
8676            onNewScopeDestroyed.push(unwatch);
8677            break;
8678
8679          case '&':
8680            // Don't assign Object.prototype method to scope
8681            if (!attrs.hasOwnProperty(attrName) && optional) break;
8682
8683            parentGet = $parse(attrs[attrName]);
8684
8685            // Don't assign noop to destination if expression is not val
8685id
8686            if (parentGet === noop && optional) break;
8687
8688            destination[scopeName] = function(locals) {
8689              return parentGet(scope, locals);
8690            };
8691            break;
8692        }
8693      });
8694      var destroyBindings = onNewScopeDestroyed ? function destroyBindings() {
8695        for (var i = 0, ii = onNewScopeDestroyed.length; i < ii; ++i) {
8696          onNewScopeDestroyed[i]();
8697        }
8698      } : noop;
8699      if (newScope && destroyBindings !== noop) {
8700        newScope.$on('$destroy', destroyBindings);
8701        return noop;
8702      }
8703      return destroyBindings;
8704    }
8705  }];
8706}
8707
8708var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
8709/**
8710 * Converts all accepted directives format into proper directive name.
8711 * @param name Name to normalize
8712 */
8713function directiveNormalize(name) {
8714  return camelCase(name.replace(PREFIX_REGEXP, ''));
8715}
8716
8717/**
8718 * @ngdoc type
8719 * @name $compile.directive.Attributes
8720 *
8721 * @description
8722 * A shared object between directive compile / linking functions which contains normalized DOM
8723 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
8724 * needed since all of these are treated as equivalent in Angular:
8725 *
8726 * ```
8727 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
8728 * ```
8729 */
8730
8731/**
8732 * @ngdoc property
8733 * @name $compile.directive.Attributes#$attr
8734 *
8735 * @description
8736 * A map of DOM element attribute names to the normalized name. This is
8737 * needed to do reverse lookup from normalized name back to actual name.
8738 */
8739
8740
8741/**
8742 * @ngdoc method
8743 * @name $compile.directive.Attributes#$set
8744 * @kind function
8745 *
8746 * @description
8747 * Set DOM element attribute value.
8748 *
8749 *
8750 * @param {string} name Normalized element attribute name of the property to modify. The name is
8751 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
8752 *          property to the original name.
8753 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
8754 */
8755
8756
8757
8758/**
8759 * Closure compiler type information
8760 */
8761
8762function nodesetLinkingFn(
8763  /* angular.Scope */ scope,
8764  /* NodeList */ nodeList,
8765  /* Element */ rootElement,
8766  /* function(Function) */ boundTranscludeFn
8767) {}
8768
8769function directiveLinkingFn(
8770  /* nodesetLinkingFn */ nodesetLinkingFn,
8771  /* angular.Scope */ scope,
8772  /* Node */ node,
8773  /* Element */ rootElement,
8774  /* function(Function) */ boundTranscludeFn
8775) {}
8776
8777function tokenDifference(str1, str2) {
8778  var values = '',
8779      tokens1 = str1.split(/\s+/),
8780      tokens2 = str2.split(/\s+/);
8781
8782  outer:
8783  for (var i = 0; i < tokens1.length; i++) {
8784    var token = tokens1[i];
8785    for (var j = 0; j < tokens2.length; j++) {
8786      if (token == tokens2[j]) continue outer;
8787    }
8788    values += (values.length > 0 ? ' ' : '') + token;
8789  }
8790  return values;
8791}
8792
8793function removeComments(jqNodes) {
8794  jqNodes = jqLite(jqNodes);
8795  var i = jqNodes.length;
8796
8797  if (i <= 1) {
8798    return jqNodes;
8799  }
8800
8801  while (i--) {
8802    var node = jqNodes[i];
8803    if (node.nodeType === NODE_TYPE_COMMENT) {
8804      splice.call(jqNodes, i, 1);
8805    }
8806  }
8807  return jqNodes;
8808}
8809
8810var $controllerMinErr = minErr('$controller');
8811
8812
8813var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
8814function identifierForController(controller, ident) {
8815  if (ident && isString(ident)) return ident;
8816  if (isString(controller)) {
8817    var match = CNTRL_REG.exec(controller);
8818    if (match) return match[3];
8819  }
8820}
8821
8822
8823/**
8824 * @ngdoc provider
8825 * @name $controllerProvider
8826 * @description
8827 * The {@link ng.$controller $controller service} is used by Angular to create new
8828 * controllers.
8829 *
8830 * This provider allows controller registration via the
8831 * {@link ng.$controllerProvider#register register} method.
8832 */
8833function $ControllerProvider() {
8834  var controllers = {},
8835      globals = false;
8836
8837  /**
8838   * @ngdoc method
8839   * @name $controllerProvider#register
8840   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
8841   *    the names and the values are the constructors.
8842   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
8843   *    annotations in the array notation).
8844   */
8845  this.register = function(name, constructor) {
8846    assertNotHasOwnProperty(name, 'controller');
8847    if (isObject(name)) {
8848      extend(controllers, name);
8849    } else {
8850      controllers[name] = constructor;
8851    }
8852  };
8853
8854  /**
8855   * @ngdoc method
8856   * @name $controllerProvider#allowGlobals
8857   * @description If called, allows `$controller` to find controller constructors on `window`
8858   */
8859  this.allowGlobals = function() {
8860    globals = true;
8861  };
8862
8863
8864  this.$get = ['$injector', '$window', function($injector, $window) {
8865
8866    /**
8867     * @ngdoc service
8868     * @name $controller
8869     * @requires $injector
8870     *
8871     * @param {Function|string} constructor If called with a function then it's considered to be the
8872     *    controller constructor function. Otherwise it's considered to be a string which is used
8873     *    to retrieve the controller constructor using the following steps:
8874     *
8875     *    * check if a controller with given name is registered via `$controllerProvider`
8876     *    * check if evaluating the string on the current scope returns a constructor
8877     *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
8878     *      `window` object (not recommended)
8879     *
8880     *    The string can use the `controller as property` syntax, where the controller instance is published
8881     *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
8882     *    to work correctly.
8883     *
8884     * @param {Object} locals Injection locals for Controller.
8885     * @return {Object} Instance of given controller.
8886     *
vendor: 4,024 bytes, lines 8887-8991
8887     * @description
8888     * `$controller` service is responsible for instantiating controllers.
8889     *
8890     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
8891     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
8892     */
8893    return function(expression, locals, later, ident) {
8894      // PRIVATE API:
8895      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
8896      //                     If true, $controller will allocate the object with the correct
8897      //                     prototype chain, but will not invoke the controller until a returned
8898      //                     callback is invoked.
8899      //   param `ident` --- An optional label which overrides the label parsed from the controller
8900      //                     expression, if any.
8901      var instance, match, constructor, identifier;
8902      later = later === true;
8903      if (ident && isString(ident)) {
8904        identifier = ident;
8905      }
8906
8907      if (isString(expression)) {
8908        match = expression.match(CNTRL_REG);
8909        if (!match) {
8910          throw $controllerMinErr('ctrlfmt',
8911            "Badly formed controller string '{0}'. " +
8912            "Must match `__name__ as __id__` or `__name__`.", expression);
8913        }
8914        constructor = match[1],
8915        identifier = identifier || match[3];
8916        expression = controllers.hasOwnProperty(constructor)
8917            ? controllers[constructor]
8918            : getter(locals.$scope, constructor, true) ||
8919                (globals ? getter($window, constructor, true) : undefined);
8920
8921        assertArgFn(expression, constructor, true);
8922      }
8923
8924      if (later) {
8925        // Instantiate controller later:
8926        // This machinery is used to create an instance of the object before calling the
8927        // controller's constructor itself.
8928        //
8929        // This allows properties to be added to the controller before the constructor is
8930        // invoked. Primarily, this is used for isolate scope bindings in $compile.
8931        //
8932        // This feature is not intended for use by applications, and is thus not documented
8933        // publicly.
8934        // Object creation: http://jsperf.com/create-constructor/2
8935        var controllerPrototype = (isArray(expression) ?
8936          expression[expression.length - 1] : expression).prototype;
8937        instance = Object.create(controllerPrototype || null);
8938
8939        if (identifier) {
8940          addIdentifier(locals, identifier, instance, constructor || expression.name);
8941        }
8942
8943        var instantiate;
8944        return instantiate = extend(function() {
8945          var result = $injector.invoke(expression, instance, locals, constructor);
8946          if (result !== instance && (isObject(result) || isFunction(result))) {
8947            instance = result;
8948            if (identifier) {
8949              // If result changed, re-assign controllerAs value to scope.
8950              addIdentifier(locals, identifier, instance, constructor || expression.name);
8951            }
8952          }
8953          return instance;
8954        }, {
8955          instance: instance,
8956          identifier: identifier
8957        });
8958      }
8959
8960      instance = $injector.instantiate(expression, locals, constructor);
8961
8962      if (identifier) {
8963        addIdentifier(locals, identifier, instance, constructor || expression.name);
8964      }
8965
8966      return instance;
8967    };
8968
8969    function addIdentifier(locals, identifier, instance, name) {
8970      if (!(locals && isObject(locals.$scope))) {
8971        throw minErr('$controller')('noscp',
8972          "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
8973          name, identifier);
8974      }
8975
8976      locals.$scope[identifier] = instance;
8977    }
8978  }];
8979}
8980
8981/**
8982 * @ngdoc service
8983 * @name $document
8984 * @requires $window
8985 *
8986 * @description
8987 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
8988 *
8989 * @example
8990   <example module="documentExample">
8991     <file name="index.html">
8992       <div ng-controller="ExampleController">
8993         <p>$document title: <b ng-bind="title"></b></p>
8994         <p>window.document title: <b ng-bind="windowTitle"></b></p>
8995       </div>
8996     </file>
8997     <file name="script.js">
8998       angular.module('documentExample', [])
8999         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
9000           $scope.title = $document[0].title;
9001           $scope.windowTitle = angular.element(window.document)[0].title;
9002         }]);
9003     </file>
9004   </example>
9005 */
9006function $DocumentProvider() {
9007  this.$get = ['$window', function(window) {
9008    return jqLite(window.document);
9009  }];
9010}
9011
9012/**
9013 * @ngdoc service
9014 * @name $exceptionHandler
9015 * @requires ng.$log
9016 *
9017 * @description
9018 * Any uncaught exception in angular expressions is delegated to this service.
9019 * The default implementation simply delegates to `$log.error` which logs it into
9020 * the browser console.
9021 *
9022 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
9023 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
9024 *
9025 * ## Example:
9026 *
9027 * ```js
9028 *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
9029 *     return function(exception, cause) {
9030 *       exception.message += ' (caused by "' + cause + '")';
9031 *       throw exception;
9032 *     };
9033 *   });
9034 * ```
9035 *
9036 * This example will override the normal action of `$exceptionHandler`, to make angular
9037 * exceptions fail hard when they happen, instead of just logging to the console.
9038 *
9039 * <hr />
9040 * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
9041 * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
9042 * (unless executed during a digest).
9043 *
9044 * If you wish, you can manually delegate exceptions, e.g.
9045 * `try { ... } catch(e) { $exceptionHandler(e); }`
9046 *
9047 * @param {Error} exception Exception associated with the error.
9048 * @param {string=} cause optional information about the context in which
9049 *       the error was thrown.
9050 *
9051 */
9052function $ExceptionHandlerProvider() {
9053  this.$get = ['$log', function($log) {
9054    return function(exception, cause) {
9055      $log.error.apply($log, arguments);
9056    };
9057  }];
9058}
9059
9060var APPLICATION_JSON = 'application/json';
9061var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
9062var JSON_START = /^\[|^\{(?!\{)/;
9063var JSON_ENDS = {
9064  '[': /]$/,
9065  '{': /}$/
9066};
9067var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
9068
9069function serializeValue(v) {
9070  if (isObject(v)) {
9071    return isDate(v) ? v.toISOString() : toJson(v);
9072  }
9073  return v;
9074}
9075
9076
9077function $HttpParamSerializerProvider() {
9078  /**
9079   * @ngdoc service
9080   * @name $httpParamSerializer
9081   * @description
9082   *
9083   * Default $http params serializer that converts objects to a part of a request URL
9084   * according to the following rules:
9085   * * `{'foo': 'bar'}` results in `foo=bar`
9086   * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
9087   * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
9088   * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
9089   * */
9090  this.$get = function() {
9091    return function ngParamSerializer(params) {
9092      if (!params) return '';
9093      var parts = [];
9094      forEachSorted(params, function(value, key) {
9095        if (value === null || isUndefined(value)) return;
9096        if (isArray(value)) {
9097          forEach(value, function(v, k) {
9098            parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
9099          });
9100        } else {
9101          parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
9102        }
9103      });
9104
9105      return parts.join('&');
9106    };
9107  };
9108}
9109
9110function $HttpParamSerializerJQLikeProvider() {
9111  /**
9112   * @ngdoc service
9113   * @name $httpParamSerializerJQLike
9114   * @description
9115   *
9116   * Alternative $http params serializer that follows jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
9117   * */
9118  this.$get = function() {
9119    return function jQueryLikeParamSerializer(params) {
9120      if (!params) return '';
9121      var parts = [];
9122      serialize(params, '', true);
9123      return parts.join('&');
9124
9125      function serialize(toSerialize, prefix, topLevel) {
9126        if (toSerialize === null || isUndefined(toSerialize)) return;
9127        if (isArray(toSerialize)) {
9128          forEach(toSerialize, function(value) {
9129            serialize(value, prefix + '[]');
9130          });
9131        } else if (isObject(toSerialize) && !isDate(toSerialize)) {
9132          forEachSorted(toSerialize, function(value, key) {
9133            serialize(value, prefix +
9134                (topLevel ? '' : '[') +
9135                key +
9136                (topLevel ? '' : ']'));
9137          });
9138        } else {
9139          parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
9140        }
9141      }
9142    };
9143  };
9144}
9145
9146function defaultHttpResponseTransform(data, headers) {
9147  if (isString(data)) {
9148    // Strip json vulnerability protection prefix and trim whitespace
9149    var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
9150
9151    if (tempData) {
9152      var contentType = headers('Content-Type');
9153      if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
9154        data = fromJson(tempData);
9155      }
9156    }
9157  }
9158
9159  return data;
9160}
9161
9162function isJsonLike(str) {
9163    var jsonStart = str.match(JSON_START);
9164    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
9165}
9166
9167/**
9168 * Parse headers into key value object
9169 *
9170 * @param {string} headers Raw headers as a string
9171 * @returns {Object} Parsed headers as key value object
9172 */
9173function parseHeaders(headers) {
9174  var parsed = createMap(), i;
9175
9176  function fillInParsed(key, val) {
9177    if (key) {
9178      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
9179    }
9180  }
9181
9182  if (isString(headers)) {
9183    forEach(headers.split('\n'), function(line) {
9184      i = line.indexOf(':');
vendor: 4,242 bytes, lines 9185-9321
9185      fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
9186    });
9187  } else if (isObject(headers)) {
9188    forEach(headers, function(headerVal, headerKey) {
9189      fillInParsed(lowercase(headerKey), trim(headerVal));
9190    });
9191  }
9192
9193  return parsed;
9194}
9195
9196
9197/**
9198 * Returns a function that provides access to parsed headers.
9199 *
9200 * Headers are lazy parsed when first requested.
9201 * @see parseHeaders
9202 *
9203 * @param {(string|Object)} headers Headers to provide access to.
9204 * @returns {function(string=)} Returns a getter function which if called with:
9205 *
9206 *   - if called with single an argument returns a single header value or null
9207 *   - if called with no arguments returns an object containing all headers.
9208 */
9209function headersGetter(headers) {
9210  var headersObj;
9211
9212  return function(name) {
9213    if (!headersObj) headersObj =  parseHeaders(headers);
9214
9215    if (name) {
9216      var value = headersObj[lowercase(name)];
9217      if (value === void 0) {
9218        value = null;
9219      }
9220      return value;
9221    }
9222
9223    return headersObj;
9224  };
9225}
9226
9227
9228/**
9229 * Chain all given functions
9230 *
9231 * This function is used for both request and response transforming
9232 *
9233 * @param {*} data Data to transform.
9234 * @param {function(string=)} headers HTTP headers getter fn.
9235 * @param {number} status HTTP status code of the response.
9236 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
9237 * @returns {*} Transformed data.
9238 */
9239function transformData(data, headers, status, fns) {
9240  if (isFunction(fns)) {
9241    return fns(data, headers, status);
9242  }
9243
9244  forEach(fns, function(fn) {
9245    data = fn(data, headers, status);
9246  });
9247
9248  return data;
9249}
9250
9251
9252function isSuccess(status) {
9253  return 200 <= status && status < 300;
9254}
9255
9256
9257/**
9258 * @ngdoc provider
9259 * @name $httpProvider
9260 * @description
9261 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
9262 * */
9263function $HttpProvider() {
9264  /**
9265   * @ngdoc property
9266   * @name $httpProvider#defaults
9267   * @description
9268   *
9269   * Object containing default values for all {@link ng.$http $http} requests.
9270   *
9271   * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
9272   * that will provide the cache for all requests who set their `cache` property to `true`.
9273   * If you set the `default.cache = false` then only requests that specify their own custom
9274   * cache object will be cached. See {@link $http#caching $http Caching} for more information.
9275   *
9276   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
9277   * Defaults value is `'XSRF-TOKEN'`.
9278   *
9279   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
9280   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
9281   *
9282   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
9283   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
9284   * setting default headers.
9285   *     - **`defaults.headers.common`**
9286   *     - **`defaults.headers.post`**
9287   *     - **`defaults.headers.put`**
9288   *     - **`defaults.headers.patch`**
9289   *
9290   * - **`defaults.paramSerializer`** - {string|function(Object<string,string>):string} - A function used to prepare string representation
9291   * of request parameters (specified as an object).
9292   * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
9293   * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
9294   *
9295   **/
9296  var defaults = this.defaults = {
9297    // transform incoming response data
9298    transformResponse: [defaultHttpResponseTransform],
9299
9300    // transform outgoing request data
9301    transformRequest: [function(d) {
9302      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
9303    }],
9304
9305    // default headers
9306    headers: {
9307      common: {
9308        'Accept': 'application/json, text/plain, */*'
9309      },
9310      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9311      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
9312      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
9313    },
9314
9315    xsrfCookieName: 'XSRF-TOKEN',
9316    xsrfHeaderName: 'X-XSRF-TOKEN',
9317
9318    paramSerializer: '$httpParamSerializer'
9319  };
9320
9321  var useApplyAsync = false;
9322  /**
9323   * @ngdoc method
9324   * @name $httpProvider#useApplyAsync
9325   * @description
9326   *
9327   * Configure $http service to combine processing of multiple http responses received at around
9328   * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
9329   * significant performance improvement for bigger applications that make many HTTP requests
9330   * concurrently (common during application bootstrap).
9331   *
9332   * Defaults to false. If no value is specified, returns the current configured value.
9333   *
9334   * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
9335   *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
9336   *    to load and share the same digest cycle.
9337   *
9338   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9339   *    otherwise, returns the current configured value.
9340   **/
9341  this.useApplyAsync = function(value) {
9342    if (isDefined(value)) {
9343      useApplyAsync = !!value;
9344      return this;
9345    }
9346    return useApplyAsync;
9347  };
9348
9349  /**
9350   * @ngdoc property
9351   * @name $httpProvider#interceptors
9352   * @description
9353   *
9354   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
9355   * pre-processing of request or postprocessing of responses.
9356   *
9357   * These service factories are ordered by request, i.e. they are applied in the same order as the
9358   * array, on request, but reverse order, on response.
9359   *
9360   * {@link ng.$http#interceptors Interceptors detailed info}
9361   **/
9362  var interceptorFactories = this.interceptors = [];
9363
9364  this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
9365      function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
9366
9367    var defaultCache = $cacheFactory('$http');
9368
9369    /**
9370     * Make sure that default param serializer is exposed as a function
9371     */
9372    defaults.paramSerializer = isString(defaults.paramSerializer) ?
9373      $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
9374
9375    /**
9376     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
9377     * The reversal is needed so that we can build up the interception chain around the
9378     * server request.
9379     */
9380    var reversedInterceptors = [];
9381
9382    forEach(interceptorFactories, function(interceptorFactory) {
9383      reversedInterceptors.unshift(isString(interceptorFactory)
9384          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
9385    });
9386
9387    /**
9388     * @ngdoc service
9389     * @kind function
9390     * @name $http
9391     * @requires ng.$httpBackend
9392     * @requires $cacheFactory
9393     * @requires $rootScope
9394     * @requires $q
9395     * @requires $injector
9396     *
9397     * @description
9398     * The `$http` service is a core Angular service that facilitates communication with the remote
9399     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
9400     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
9401     *
9402     * For unit testing applications that use `$http` service, see
9403     * {@link ngMock.$httpBackend $httpBackend mock}.
9404     *
9405     * For a higher level of abstraction, please check out the {@link ngResource.$resource
9406     * $resource} service.
9407     *
9408     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
9409     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
9410     * it is important to familiarize yourself with these APIs and the guarantees they provide.
9411     *
9412     *
9413     * ## General usage
9414     * The `$http` service is a function which takes a single argument — a configuration object —
9415     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
9416     * with two $http specific methods: `success` and `error`.
9417     *
9418     * ```js
9419     *   // Simple GET request example :
9420     *   $http.get('/someUrl').
9421     *     success(function(data, status, headers, config) {
9422     *       // this callback will be called asynchronously
9423     *       // when the response is available
9424     *     }).
9425     *     error(function(data, status, headers, config) {
9426     *       // called asynchronously if an error occurs
9427     *       // or server returns response with an error status.
9428     *     });
9429     * ```
9430     *
9431     * ```js
9432     *   // Simple POST request example (passing data) :
9433     *   $http.post('/someUrl', {msg:'hello word!'}).
9434     *     success(function(data, status, headers, config) {
9435     *       // this callback will be called asynchronously
9436     *       // when the response is available
9437     *     }).
9438     *     error(function(data, status, headers, config) {
9439     *       // called asynchronously if an error occurs
9440     *       // or server returns response with an error status.
9441     *     });
9442     * ```
9443     *
9444     *
9445     * Since the returned value of calling the $http function is a `promise`, you can also use
9446     * the `then` method to register callbacks, and these callbacks will receive a single argument –
9447     * an object representing the response. See the API signature and type info below for more
9448     * details.
9449     *
9450     * A response status code between 200 and 299 is considered a success status and
9451     * will result in the success callback being called. Note that if the response is a redirect,
9452     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
9453     * called for such responses.
9454     *
9455     * ## Writing Unit Tests that use $http
9456     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
9457     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
9458     * request using trained responses.
9459     *
9460     * ```
9461     * $httpBackend.expectGET(...);
9462     * $http.get(...);
9463     * $httpBackend.flush();
9464     * ```
9465     *
9466     * ## Shortcut methods
9467     *
9468     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
9469     * request data must be passed in for POST/PUT requests.
9470     *
9471     * ```js
9472     *   $http.get('/someUrl').success(successCallback);
9473     *   $http.post('/someUrl', data).success(successCallback);
9474     * ```
9475     *
9476     * Complete list of shortcut methods:
9477     *
9478     * - {@link ng.$http#get $http.get}
9479     * - {@link ng.$http#head $http.head}
9480     * - {@link ng.$http#post $http.post}
9481     * - {@link ng.$http#put $http.put}
9482     * - {@link ng.$http#delete $http.delete}
9483     * - {@link ng.$http#jsonp $http.jsonp}
9484     * - {@link ng.$http#patch $http.patch}
9485     *
9486     *
9487     * ## Setting HTTP Headers
9488     *
9489     * The $http service will automatically add certain HTTP headers to all requests. These defaults
9490     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
9491     * object, which currently contains this default configuration:
9492     *
9493     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
9494     *   - `Accept: application/json, text/plain, * / *`
9495     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
9496     *   - `Content-Type: application/json`
9497     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
9498     *   - `Content-Type: application/json`
9499     *
9500     * To add or overwrite these defaults, simply add or remove a property from these configuration
9501     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
9502     * with the lowercased HTTP method name as the key, e.g.
9503     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
9504     *
9505     * The defaults can also be set at runtime via the `$http.defaults` object in the same
9506     * fashion. For example:
9507     *
9508     * ```
9509     * module.run(function($http) {
9510     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
9511     * });
9512     * ```
9513     *
9514     * In addition, you can supply a `headers` property in the config object passed when
9515     * calling `$http(config)`, which overrides the defaults without changing them globally.
9516     *
9517     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
9518     * Use the `headers` property, setting the desired header to `undefined`. For example:
9519     *
9520     * ```js
9521     * var req = {
9522     *  method: 'POST',
9523     *  url: 'http://example.com',
9524     *  headers: {
9525     *    'Content-Type': undefined
9526     *  },
9527     *  data: { test: 'test' }
9528     * }
9529     *
9530     * $http(req).success(function(){...}).error(function(){...});
9531     * ```
9532     *
9533     * ## Transforming Requests and Responses
9534     *
9535     * Both requests and responses can be transformed using transformation functions: `transformRequest`
9536     * and `transformResponse`. These properties can be a single function that returns
9537     * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
9538     * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
9539     *
9540     * ### Default Transformations
9541     *
9542     * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
9543     * `defaults.transformResponse` properties. If a request does not provide its own transformations
9544     * then these will be applied.
9545     *
9546     * You can augment or replace the default transformations by modifying these properties by adding to or
9547     * replacing the array.
9548     *
9549     * Angular provides the following default transformations:
9550     *
9551     * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
9552     *
9553     * - If the `data` property of the request configuration object contains an object, serialize it
9554     *   into JSON format.
9555     *
9556     * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
9557     *
9558     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
9559     *  - If JSON response is detected, deserialize it using a JSON parser.
9560     *
9561     *
9562     * ### Overriding the Default Transformations Per Request
9563     *
9564     * If you wish override the request/response transformations only for a single request then provide
9565     * `transformRequest` and/or `transformResponse` properties on the configuration object passed
9566     * into `$http`.
9567     *
9568     * Note that if you provide these properties on the config object the default transformations will be
9569     * overwritten. If you wish to augment the default transformations then you must include them in your
9570     * local transformation array.
9571     *
9572     * The following code demonstrates adding a new response transformation to be run after the default response
9573     * transformations have been run.
9574     *
9575     * ```js
9576     * function appendTransform(defaults, transform) {
9577     *
9578     *   // We can't guarantee that the default transformation is an array
9579     *   defaults = angular.isArray(defaults) ? defaults : [defaults];
9580     *
9581     *   // Append the new transformation to the defaults
9582     *   return defaults.concat(transform);
9583     * }
9584     *
9585     * $http({
9586     *   url: '...',
9587     *   method: 'GET',
9588     *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
9589     *     return doTransform(value);
9590     *   })
9591     * });
9592     * ```
9593     *
9594     *
9595     * ## Caching
9596     *
9597     * To enable caching, set the request configuration `cache` property to `true` (to use default
9598     * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
9599     * When the cache is enabled, `$http` stores the response from the server in the specified
9600     * cache. The next time the same request is made, the response is served from the cache without
9601     * sending a request to the server.
9602     *
9603     * Note that even if the response is served from cache, delivery of the data is asynchronous in
9604     * the same way that real requests are.
9605     *
9606     * If there are multiple GET requests for the same URL that should be cached using the same
9607     * cache, but the cache is not populated yet, only one request to the server will be made and
9608     * the remaining requests will be fulfilled using the response from the first request.
9609     *
9610     * You can change the default cache to a new object (built with
9611     * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
9612     * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
9613     * their `cache` property to `true` will now use this cache object.
9614     *
9615     * If you set the default cache to `false` then only requests that specify their own custom
9616     * cache object will be cached.
9617     *
9618     * ## Interceptors
9619     *
9620     * Before you start creating interceptors, be sure to understand the
9621     * {@link ng.$q $q and deferred/promise APIs}.
9622     *
9623     * For purposes of global error handling, authentication, or any kind of synchronous or
9624     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
9625     * able to intercept requests before they are handed to the server and
9626     * responses before they are handed over to the application code that
9627     * initiated these requests. The interceptors leverage the {@link ng.$q
9628     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
9629     *
9630     * The interceptors are service factories that are registered with the `$httpProvider` by
9631     * adding them to the `$httpProvider.interceptors` array. The factory is called and
9632     * injected with dependencies (if specified) and returns the interceptor.
9633     *
9634     * There are two kinds of interceptors (and two kinds of rejection interceptors):
9635     *
9636     *   * `request`: interceptors get called with a http `config` object. The function is free to
9637     *     modify the `config` object or create a new one. The function needs to return the `config`
9638     *     object directly, or a promise containing the `config` or a new `config` object.
9639     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
9640     *     resolved with a rejection.
9641     *   * `response`: interceptors get called with http `response` object. The function is free to
9642     *     modify the `response` object or create a new one. The function needs to return the `response`
9643     *     object directly, or as a promise containing the `response` or a new `response` object.
9644     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
9645     *     resolved with a rejection.
9646     *
9647     *
9648     * ```js
9649     *   // register the interceptor as a service
9650     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
9651     *     return {
9652     *       // optional method
9653     *       'request': function(config) {
9654     *         // do something on success
9655     *         return config;
9656     *       },
9657     *
9658     *       // optional method
9659     *      'requestError': function(rejection) {
9660     *         // do something on error
9661     *         if (canRecover(rejection)) {
9662     *           return responseOrNewPromise
9663     *         }
9664     *         return $q.reject(rejection);
9665     *       },
9666     *
9667     *
9668     *
9669     *       // optional method
9670     *       'response': function(response) {
9671     *         // do something on success
9672     *         return response;
9673     *       },
9674     *
9675     *       // optional method
9676     *      'responseError': function(rejection) {
9677     *         // do something on error
9678     *         if (canRecover(rejection)) {
9679     *           return responseOrNewPromise
9680     *         }
9681     *         return $q.reject(rejection);
9682     *       }
9683     *     };
9684     *   });
9685     *
9686     *   $httpProvider.interceptors.push('myHttpInterceptor');
9687     *
9688     *
9689     *   // alternatively, register the interceptor via an anonymous factory
9690     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
9691     *     return {
9692     *      'request': function(config) {
9693     *          // same as above
9694     *       },
9695     *
9696     *       'response': function(response) {
9697     *          // same as above
9698     *       }
9699     *     };
9700     *   });
9701     * ```
9702     *
9703     * ## Security Considerations
9704     *
9705     * When designing web applications, consider security threats from:
9706     *
9707     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9708     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
9709     *
9710     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
9711     * pre-configured with strategies that address these issues, but for this to work backend server
9712     * cooperation is required.
9713     *
9714     * ### JSON Vulnerability Protection
9715     *
9716     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
9717     * allows third party website to turn your JSON resource URL into
9718     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
9719     * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
9720     * Angular will automatically strip the prefix before processing it as JSON.
9721     *
9722     * For example if your server needs to return:
9723     * ```js
9724     * ['one','two']
9725     * ```
9726     *
9727     * which is vulnerable to attack, your server can return:
9728     * ```js
9729     * )]}',
9730     * ['one','two']
9731     * ```
9732     *
9733     * Angular will strip the prefix, before processing the JSON.
9734     *
9735     *
9736     * ### Cross Site Request Forgery (XSRF) Protection
9737     *
9738     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
9739     * an unauthorized site can gain your user's private data. Angular provides a mechanism
9740     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
9741     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
9742     * JavaScript that runs on your domain could read the cookie, your server can be assured that
9743     * the XHR came from JavaScript running on your domain. The header will not be set for
9744     * cross-domain requests.
9745     *
9746     * To take advantage of this, your server needs to set a token in a JavaScript readable session
9747     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
9748     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
9749     * that only JavaScript running on your domain could have sent the request. The token must be
9750     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
9751     * making up its own tokens). We recommend that the token is a digest of your site's
9752     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
9753     * for added security.
9754     *
9755     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
9756     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
9757     * or the per-request config object.
9758     *
9759     *
9760     * @param {object} config Object describing the request to be made and how it should be
9761     *    processed. The object has following properties:
9762     *
9763     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
9764     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
9765     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
9766     *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
9767     *      JSONified.
9768     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
9769     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
9770     *      HTTP headers to send to the server. If the return value of a function is null, the
9771     *      header will not be sent. Functions accept a config object as an argument.
9772     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
9773     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
9774     *    - **transformRequest** –
9775     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>
9775}` –
9776     *      transform function or an array of such functions. The transform function takes the http
9777     *      request body and headers and returns its transformed (typically serialized) version.
9778     *      See {@link ng.$http#overriding-the-default-transformations-per-request
9779     *      Overriding the Default Transformations}
9780     *    - **transformResponse** –
9781     *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
9782     *      transform function or an array of such functions. The transform function takes the http
9783     *      response body, headers and status and returns its transformed (typically deserialized) version.
9784     *      See {@link ng.$http#overriding-the-default-transformations-per-request
9785     *      Overriding the Default Transformations}
9786     *    - **paramSerializer** - {string|function(Object<string,string>):string} - A function used to prepare string representation
9787     *      of request parameters (specified as an object).
9788     *      Is specified as string, it is interpreted as function registered in with the {$injector}.
9789     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
9790     *      GET request, otherwise if a cache instance built with
9791     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
9792     *      caching.
9793     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
9794     *      that should abort the request when resolved.
9795     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
9796     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
9797     *      for more information.
9798     *    - **responseType** - `{string}` - see
9799     *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
9800     *
9801     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
9802     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
9803     *   method takes two arguments a success and an error callback which will be called with a
9804     *   response object. The `success` and `error` methods take a single argument - a function that
9805     *   will be called when the request succeeds or fails respectively. The arguments passed into
9806     *   these functions are destructured representation of the response object passed into the
9807     *   `then` method. The response object has these properties:
9808     *
9809     *   - **data** – `{string|Object}` – The response body transformed with the transform
9810     *     functions.
9811     *   - **status** – `{number}` – HTTP status code of the response.
9812     *   - **headers** – `{function([headerName])}` – Header getter function.
9813     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
9814     *   - **statusText** – `{string}` – HTTP status text of the response.
9815     *
9816     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
9817     *   requests. This is primarily meant to be used for debugging purposes.
9818     *
9819     *
9820     * @example
9821<example module="httpExample">
9822<file name="index.html">
9823  <div ng-controller="FetchController">
9824    <select ng-model="method" aria-label="Request method">
9825      <option>GET</option>
9826      <option>JSONP</option>
9827    </select>
9828    <input type="text" ng-model="url" size="80" aria-label="URL" />
9829    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
9830    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
9831    <button id="samplejsonpbtn"
9832      ng-click="updateModel('JSONP',
9833                    'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
9834      Sample JSONP
9835    </button>
9836    <button id="invalidjsonpbtn"
9837      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
9838        Invalid JSONP
9839      </button>
9840    <pre>http status code: {{status}}</pre>
9841    <pre>http response data: {{data}}</pre>
9842  </div>
9843</file>
9844<file name="script.js">
9845  angular.module('httpExample', [])
9846    .controller('FetchController', ['$scope', '$http', '$templateCache',
9847      function($scope, $http, $templateCache) {
9848        $scope.method = 'GET';
9849        $scope.url = 'http-hello.html';
9850
9851        $scope.fetch = function() {
9852          $scope.code = null;
9853          $scope.response = null;
9854
9855          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
9856            success(function(data, status) {
9857              $scope.status = status;
9858              $scope.data = data;
9859            }).
9860            error(function(data, status) {
9861              $scope.data = data || "Request failed";
9862              $scope.status = status;
9863          });
9864        };
9865
9866        $scope.updateModel = function(method, url) {
9867          $scope.method = method;
9868          $scope.url = url;
9869        };
9870      }]);
9871</file>
9872<file name="http-hello.html">
9873  Hello, $http!
9874</file>
9875<file name="protractor.js" type="protractor">
9876  var status = element(by.binding('status'));
9877  var data = element(by.binding('data'));
9878  var fetchBtn = element(by.id('fetchbtn'));
9879  var sampleGetBtn = element(by.id('samplegetbtn'));
9880  var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
9881  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
9882
9883  it('should make an xhr GET request', function() {
9884    sampleGetBtn.click();
9885    fetchBtn.click();
9886    expect(status.getText()).toMatch('200');
9887    expect(data.getText()).toMatch(/Hello, \$http!/);
9888  });
9889
9890// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
9891// it('should make a JSONP request to angularjs.org', function() {
9892//   sampleJsonpBtn.click();
9893//   fetchBtn.click();
9894//   expect(status.getText()).toMatch('200');
9895//   expect(data.getText()).toMatch(/Super Hero!/);
9896// });
9897
9898  it('should make JSONP request to invalid URL and invoke the error handler',
9899      function() {
9900    invalidJsonpBtn.click();
9901    fetchBtn.click();
9902    expect(status.getText()).toMatch('0');
9903    expect(data.getText()).toMatch('Request failed');
9904  });
9905</file>
9906</example>
9907     */
9908    function $http(requestConfig) {
9909
9910      if (!angular.isObject(requestConfig)) {
9911        throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
9912      }
9913
9914      var config = extend({
9915        method: 'get',
9916        transformRequest: defaults.transformRequest,
9917        transformResponse: defaults.transformResponse,
9918        paramSerializer: defaults.paramSerializer
9919      }, requestConfig);
9920
9921      config.headers = mergeHeaders(requestConfig);
9922      config.method = uppercase(config.method);
9923      config.paramSerializer = isString(config.paramSerializer) ?
9924        $injector.get(config.paramSerializer) : config.paramSerializer;
9925
9926      var serverRequest = function(config) {
9927        var headers = config.headers;
9928        var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
9929
9930        // strip content-type if data is undefined
9931        if (isUndefined(reqData)) {
9932          forEach(headers, function(value, header) {
9933            if (lowercase(header) === 'content-type') {
9934                delete headers[header];
9935            }
9936          });
9937        }
9938
9939        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
9940          config.withCredentials = defaults.withCredentials;
9941        }
9942
9943        // send request
9944        return sendReq(config, reqData).then(transformResponse, transformResponse);
9945      };
9946
9947      var chain = [serverRequest, undefined];
9948      var promise = $q.when(config);
9949
9950      // apply interceptors
9951      forEach(reversedInterceptors, function(interceptor) {
9952        if (interceptor.request || interceptor.requestError) {
9953          chain.unshift(interceptor.request, interceptor.requestError);
9954        }
9955        if (interceptor.response || interceptor.responseError) {
9956          chain.push(interceptor.response, interceptor.responseError);
9957        }
9958      });
9959
9960      while (chain.length) {
9961        var thenFn = chain.shift();
9962        var rejectFn = chain.shift();
9963
9964        promise = promise.then(thenFn, rejectFn);
9965      }
9966
9967      promise.success = function(fn) {
9968        assertArgFn(fn, 'fn');
9969
9970        promise.then(function(response) {
9971          fn(response.data, response.status, response.headers, config);
9972        });
9973        return promise;
9974      };
9975
9976      promise.error = function(fn) {
9977        assertArgFn(fn, 'fn');
9978
9979        promise.then(null, function(response) {
9980          fn(response.data, response.status, response.headers, config);
9981        });
9982        return promise;
9983      };
9984
9985      return promise;
9986
9987      function transformResponse(response) {
9988        // make a copy since the response must be cacheable
9989        var resp = extend({}, response);
9990        if (!response.data) {
9991          resp.data = response.data;
9992        } else {
9993          resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
9994        }
9995        return (isSuccess(response.status))
9996          ? resp
9997          : $q.reject(resp);
9998      }
9999
10000      function executeHeaderFns(headers, config) {
10001        var headerContent, processedHeaders = {};
10002
10003        forEach(headers, function(headerFn, header) {
10004          if (isFunction(headerFn)) {
10005            headerContent = headerFn(config);
10006            if (headerContent != null) {
10007              processedHeaders[header] = headerContent;
10008            }
10009          } else {
10010            processedHeaders[header] = headerFn;
10011          }
10012        });
10013
10014        return processedHeaders;
10015      }
10016
10017      function mergeHeaders(config) {
10018        var defHeaders = defaults.headers,
10019            reqHeaders = extend({}, config.headers),
10020            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
10021
10022        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
10023
vendor: 4,228 bytes, lines 10024-10163
10024        // using for-in instead of forEach to avoid unecessary iteration after header has been found
10025        defaultHeadersIteration:
10026        for (defHeaderName in defHeaders) {
10027          lowercaseDefHeaderName = lowercase(defHeaderName);
10028
10029          for (reqHeaderName in reqHeaders) {
10030            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
10031              continue defaultHeadersIteration;
10032            }
10033          }
10034
10035          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
10036        }
10037
10038        // execute if header value is a function for merged headers
10039        return executeHeaderFns(reqHeaders, shallowCopy(config));
10040      }
10041    }
10042
10043    $http.pendingRequests = [];
10044
10045    /**
10046     * @ngdoc method
10047     * @name $http#get
10048     *
10049     * @description
10050     * Shortcut method to perform `GET` request.
10051     *
10052     * @param {string} url Relative or absolute URL specifying the destination of the request
10053     * @param {Object=} config Optional configuration object
10054     * @returns {HttpPromise} Future object
10055     */
10056
10057    /**
10058     * @ngdoc method
10059     * @name $http#delete
10060     *
10061     * @description
10062     * Shortcut method to perform `DELETE` request.
10063     *
10064     * @param {string} url Relative or absolute URL specifying the destination of the request
10065     * @param {Object=} config Optional configuration object
10066     * @returns {HttpPromise} Future object
10067     */
10068
10069    /**
10070     * @ngdoc method
10071     * @name $http#head
10072     *
10073     * @description
10074     * Shortcut method to perform `HEAD` request.
10075     *
10076     * @param {string} url Relative or absolute URL specifying the destination of the request
10077     * @param {Object=} config Optional configuration object
10078     * @returns {HttpPromise} Future object
10079     */
10080
10081    /**
10082     * @ngdoc method
10083     * @name $http#jsonp
10084     *
10085     * @description
10086     * Shortcut method to perform `JSONP` request.
10087     *
10088     * @param {string} url Relative or absolute URL specifying the destination of the request.
10089     *                     The name of the callback should be the string `JSON_CALLBACK`.
10090     * @param {Object=} config Optional configuration object
10091     * @returns {HttpPromise} Future object
10092     */
10093    createShortMethods('get', 'delete', 'head', 'jsonp');
10094
10095    /**
10096     * @ngdoc method
10097     * @name $http#post
10098     *
10099     * @description
10100     * Shortcut method to perform `POST` request.
10101     *
10102     * @param {string} url Relative or absolute URL specifying the destination of the request
10103     * @param {*} data Request content
10104     * @param {Object=} config Optional configuration object
10105     * @returns {HttpPromise} Future object
10106     */
10107
10108    /**
10109     * @ngdoc method
10110     * @name $http#put
10111     *
10112     * @description
10113     * Shortcut method to perform `PUT` request.
10114     *
10115     * @param {string} url Relative or absolute URL specifying the destination of the request
10116     * @param {*} data Request content
10117     * @param {Object=} config Optional configuration object
10118     * @returns {HttpPromise} Future object
10119     */
10120
10121     /**
10122      * @ngdoc method
10123      * @name $http#patch
10124      *
10125      * @description
10126      * Shortcut method to perform `PATCH` request.
10127      *
10128      * @param {string} url Relative or absolute URL specifying the destination of the request
10129      * @param {*} data Request content
10130      * @param {Object=} config Optional configuration object
10131      * @returns {HttpPromise} Future object
10132      */
10133    createShortMethodsWithData('post', 'put', 'patch');
10134
10135        /**
10136         * @ngdoc property
10137         * @name $http#defaults
10138         *
10139         * @description
10140         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
10141         * default headers, withCredentials as well as request and response transformations.
10142         *
10143         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
10144         */
10145    $http.defaults = defaults;
10146
10147
10148    return $http;
10149
10150
10151    function createShortMethods(names) {
10152      forEach(arguments, function(name) {
10153        $http[name] = function(url, config) {
10154          return $http(extend({}, config || {}, {
10155            method: name,
10156            url: url
10157          }));
10158        };
10159      });
10160    }
10161
10162
10163    function createShortMethodsWithData(name) {
10164      forEach(arguments, function(name) {
10165        $http[name] = function(url, data, config) {
10166          return $http(extend({}, config || {}, {
10167            method: name,
10168            url: url,
10169            data: data
10170          }));
10171        };
10172      });
10173    }
10174
10175
10176    /**
10177     * Makes the request.
10178     *
10179     * !!! ACCESSES CLOSURE VARS:
10180     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
10181     */
10182    function sendReq(config, reqData) {
10183      var deferred = $q.defer(),
10184          promise = deferred.promise,
10185          cache,
10186          cachedResp,
10187          reqHeaders = config.headers,
10188          url = buildUrl(config.url, config.paramSerializer(config.params));
10189
10190      $http.pendingRequests.push(config);
10191      promise.then(removePendingReq, removePendingReq);
10192
10193
10194      if ((config.cache || defaults.cache) && config.cache !== false &&
10195          (config.method === 'GET' || config.method === 'JSONP')) {
10196        cache = isObject(config.cache) ? config.cache
10197              : isObject(defaults.cache) ? defaults.cache
10198              : defaultCache;
10199      }
10200
10201      if (cache) {
10202        cachedResp = cache.get(url);
10203        if (isDefined(cachedResp)) {
10204          if (isPromiseLike(cachedResp)) {
10205            // cached request has already been sent, but there is no response yet
10206            cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
10207          } else {
10208            // serving from cache
10209            if (isArray(cachedResp)) {
10210              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
10211            } else {
10212              resolvePromise(cachedResp, 200, {}, 'OK');
10213            }
10214          }
10215        } else {
10216          // put the promise for the non-transformed response into cache as a placeholder
10217          cache.put(url, promise);
10218        }
10219      }
10220
10221
10222      // if we won't have the response in cache, set the xsrf headers and
10223      // send the request to the backend
10224      if (isUndefined(cachedResp)) {
10225        var xsrfValue = urlIsSameOrigin(config.url)
10226            ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
10227            : undefined;
10228        if (xsrfValue) {
10229          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
10230        }
10231
10232        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
10233            config.withCredentials, config.responseType);
10234      }
10235
10236      return promise;
10237
10238
10239      /**
10240       * Callback registered to $httpBackend():
10241       *  - caches the response if desired
10242       *  - resolves the raw $http promise
10243       *  - calls $apply
10244       */
10245      function done(status, response, headersString, statusText) {
10246        if (cache) {
10247          if (isSuccess(status)) {
10248            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
10249          } else {
10250            // remove promise from the cache
10251            cache.remove(url);
10252          }
10253        }
10254
10255        function resolveHttpPromise() {
10256          resolvePromise(response, status, headersString, statusText);
10257        }
10258
10259        if (useApplyAsync) {
10260          $rootScope.$applyAsync(resolveHttpPromise);
10261        } else {
10262          resolveHttpPromise();
10263          if (!$rootScope.$$phase) $rootScope.$apply();
10264        }
10265      }
10266
10267
10268      /**
10269       * Resolves the raw $http promise.
10270       */
10271      function resolvePromise(response, status, headers, statusText) {
10272        // normalize internal statuses to 0
10273        status = Math.max(status, 0);
10274
10275        (isSuccess(status) ? deferred.resolve : deferred.reject)({
10276          data: response,
10277          status: status,
10278          headers: headersGetter(headers),
10279          config: config,
10280          statusText: statusText
10281        });
10282      }
10283
10284      function resolvePromiseWithResult(result) {
10285        resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
10286      }
10287
10288      function removePendingReq() {
10289        var idx = $http.pendingRequests.indexOf(config);
10290        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
10291      }
10292    }
10293
10294
10295    function buildUrl(url, serializedParams) {
10296      if (serializedParams.length > 0) {
10297        url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
10298      }
10299      return url;
10300    }
10301  }];
10302}
10303
10304function createXhr() {
10305    return new window.XMLHttpRequest();
10306}
10307
10308/**
10309 * @ngdoc service
10310 * @name $httpBackend
10311 * @requires $window
10312 * @requires $document
10313 *
10314 * @description
10315 * HTTP backend used by the {@link ng.$http service} that delegates to
10316 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
10317 *
10318 * You should never need to use this service directly, instead use the higher-level abstractions:
10319 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
10320 *
10321 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
10322 * $httpBackend} which can be trained with responses.
10323 */
10324function $HttpBackendProvider() {
10325  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
10326    return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
10327  }];
10328}
10329
10330function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
10331  // TODO(vojta): fix the signature
10332  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
10333    $browser.$$incOutstandingRequestCount();
10334    url = url || $browser.url();
10335
10336    if (lowercase(method) == 'jsonp') {
10337      var callbackId = '_' + (callbacks.counter++).toString(36);
10338      callbacks[callbackId] = function(data) {
10339        callbacks[callbackId].data = data;
10340        callbacks[callbackId].called = true;
10341      };
10342
10343      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
10344          callbackId, function(status, text) {
10345        completeRequest(callback, status, callbacks[callbackId].data, "", text);
10346        callbacks[callbackId] = noop;
10347      });
10348    } else {
10349
10350      var xhr = createXhr();
10351
10352      xhr.open(method, url, true);
10353      forEach(headers, function(value, key) {
10354        if (isDefined(value)) {
10355            xhr.setRequestHeader(key, value);
10356        }
10357      });
10358
10359      xhr.onload = function requestLoaded() {
10360        var statusText = xhr.statusText || '';
10361
10362        // responseText is the old-school way of retrieving response (supported by IE8 & 9)
10363        // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
10364        var response = ('response' in xhr) ? xhr.response : xhr.responseText;
10365
10366        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
10367        var status = xhr.status === 1223 ? 204 : xhr.status;
10368
10369        // fix status code when it is 0 (0 status is undocumented).
10370        // Occurs when accessing file resources or on Android 4.1 stock browser
10371        // while retrieving files from application cache.
10372        if (status === 0) {
10373          status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
10374        }
10375
10376        completeRequest(callback,
10377            status,
10378            response,
10379            xhr.getAllResponseHeaders(),
10380            statusText);
10381      };
10382
10383      var requestError = function() {
10384        // The response is always empty
10385        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
10386        completeRequest(callback, -1, null, null, '');
10387      };
10388
10389      xhr.onerror = requestError;
10390      xhr.onabort = requestError;
10391
10392      if (withCredentials) {
10393        xhr.withCredentials = true;
10394      }
10395
10396      if (responseType) {
10397        try {
10398          xhr.responseType = responseType;
10399        } catch (e) {
10400          // WebKit added support for the json responseType value on 09/03/2013
10401          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
10402          // known to throw when setting the value "json" as the response type. Other older
10403          // browsers implementing the responseType
10404          //
10405          // The json response type can be ignored if not supported, because JSON payloads are
10406          // parsed on the client-side regardless.
10407          if (responseType !== 'json') {
10408            throw e;
10409          }
10410        }
10411      }
10412
10413      xhr.send(post);
10414    }
10415
10416    if (timeout > 0) {
10417      var timeoutId = $browserDefer(timeoutRequest, timeout);
10418    } else if (isPromiseLike(timeout)) {
10419      timeout.then(timeoutRequest);
10420    }
10421
10422
10423    function timeoutRequest() {
10424      jsonpDone && jsonpDone();
10425      xhr && xhr.abort();
10426    }
10427
10428    function completeRequest(callback, status, response, headersString, statusText) {
10429      // cancel timeout and subsequent timeout promise resolution
10430      if (timeoutId !== undefined) {
10431        $browserDefer.cancel(timeoutId);
10432      }
10433      jsonpDone = xhr = null;
10434
10435      callback(status, response, headersString, statusText);
10436      $browser.$$completeOutstandingRequest(noop);
10437    }
10438  };
10439
10440  function jsonpReq(url, callbackId, done) {
10441    // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
10442    // - fetches local scripts via XHR and evals them
10443    // - adds and immediately removes script elements from the document
10444    var script = rawDocument.createElement('script'), callback = null;
10445    script.type = "text/javascript";
10446    script.src = url;
10447    script.async = true;
10448
10449    callback = function(event) {
10450      removeEventListenerFn(script, "load", callback);
10451      removeEventListenerFn(script, "error", callback);
10452      rawDocument.body.removeChild(script);
10453      script = null;
10454      var status = -1;
10455      var text = "unknown";
10456
10457      if (event) {
10458        if (event.type === "load" && !callbacks[callbackId].called) {
10459          event = { type: "error" };
10460        }
10461        text = event.type;
10462        status = event.type === "error" ? 404 : 200;
10463      }
10464
10465      if (done) {
10466        done(status, text);
10467      }
10468    };
10469
10470    addEventListenerFn(script, "load", callback);
10471    addEventListenerFn(script, "error", callback);
10472    rawDocument.body.appendChild(script);
10473    return callback;
10474  }
10475}
10476
10477var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
10478$interpolateMinErr.throwNoconcat = function(text) {
10479  throw $interpolateMinErr('noconcat',
10480      "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
10481      "interpolations that concatenate multiple expressions when a trusted value is " +
10482      "required.  See http://docs.angularjs.org/api/ng.$sce", text);
10483};
10484
10485$interpolateMinErr.interr = function(text, err) {
10486  return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
10487};
10488
10489/**
10490 * @ngdoc provider
10491 * @name $interpolateProvider
10492 *
10493 * @description
10494 *
10495 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
10496 *
10497 * @example
10498<example module="customInterpolationApp">
10499<file name="index.html">
10500<script>
10501  var customInterpolationApp = angular.module('customInterpolationApp', []);
10502
10503  customInterpolationApp.config(function($interpolateProvider) {
10504    $interpolateProvider.startSymbol('//');
10505    $interpolateProvider.endSymbol('//');
10506  });
10507
10508
10509  customInterpolationApp.controller('DemoController', function() {
10510      this.label = "This binding is brought you by // interpolation symbols.";
10511  });
10512</script>
10513<div ng-app="App" ng-controller="DemoController as demo">
10514    //demo.label//
10515</div>
10516</file>
10517<file name="protractor.js" type="protractor">
10518  it('should interpolate binding with custom symbols', function() {
10519    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
10520  });
10521</file>
10522</example>
10523 */
10524function $InterpolateProvider() {
10525  var startSymbol = '{{';
10526  var endSymbol = '}}';
10527
10528  /**
10529   * @ngdoc method
10530   * @name $interpolateProvider#startSymbol
10531   * @description
10532   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
10533   *
10534   * @param {string=} value new value to set the starting symbol to.
10535   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10536   */
10537  this.startSymbol = function(value) {
10538    if (value) {
10539      startSymbol = value;
10540      return this;
10541    } else {
10542      return startSymbol;
10543    }
10544  };
10545
10546  /**
10547   * @ngdoc method
10548   * @name $interpolateProvider#endSymbol
10549   * @description
10550   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10551   *
10552   * @param {string=} value new value to set the ending symbol to.
10553   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
10554   */
10555  this.endSymbol = function(value) {
10556    if (value) {
10557      endSymbol = value;
10558      return this;
10559    } else {
10560      return endSymbol;
10561    }
10562  };
10563
10564
10565  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
10566    var startSymbolLength = startSymbol.length,
10567        endSymbolLength = endSymbol.length,
10568        escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
10569        escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
10570
10571    function escape(ch) {
10572      return '\\\\\\' + ch;
10573    }
10574
10575    function unescapeText(text) {
10576      return text.replace(escapedStartRegexp, startSymbol).
10577        replace(escapedEndRegexp, endSymbol);
10578    }
10579
10580    function stringify(value) {
10581      if (value == null) { // null || undefined
10582        return '';
10583      }
10584      switch (typeof value) {
10585        case 'string':
10586          break;
10587        case 'number':
10588          value = '' + value;
10589          break;
10590        default:
10591          value = toJson(value);
10592      }
10593
10594      return value;
10595    }
10596
10597    /**
10598     * @ngdoc service
10599     * @name $interpolate
10600     * @kind function
10601     *
10602     * @requires $parse
10603     * @requires $sce
10604     *
10605     * @description
10606     *
10607     * Compiles a string with markup into an interpolation function. This service is used by the
10608     * HTML {@link ng.$compile $compile} service for data binding. See
10609     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
10610     * interpolation markup.
10611     *
10612     *
10613     * ```js
10614     *   var $interpolate = ...; // injected
10615     *   var exp = $interpolate('Hello {{name | uppercase}}!');
10616     *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
10617     * ```
10618     *
10619     * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
10620     * `true`, the interpolation function will return `undefined` unless all embedded expressions
10621     * evaluate to a value other than `undefined`.
10622     *
10623     * ```js
10624     *   var $interpolate = ...; // injected
10625     *   var context = {greeting: 'Hello', name: undefined };
10626     *
10627     *   // default "forgiving" mode
10628     *   var exp = $interpolate('{{greeting}} {{name}}!');
10629     *   expect(exp(context)).toEqual('Hello !');
10630     *
10631     *   // "allOrNothing" mode
10632     *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
10633     *   expect(exp(context)).toBeUndefined();
10634     *   context.name = 'Angular';
10635     *   expect(exp(context)).toEqual('Hello Angular!');
10636     * ```
10637     *
10638     * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
10639     *
10640     * ####Escaped Interpolation
10641     * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
10642     * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
10643     * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
10644     * or binding.
10645     *
10646     * This enables web-servers to prevent script injection attacks and defacing attacks, to some
10647     * degree, while also enabling code examples to work without relying on the
10648     * {@link ng.directive:ngNonBindable ngNonBindable} directive.
10649     *
10650     * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
10651     * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
10652     * interpolation start/end markers with their escaped counterparts.**
10653     *
10654     * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
10655     * output when the $interpolate service processes the text. So, for HTML elements interpolated
10656     * by {@link ng.$compile $compile}
10656, or otherwise interpolated with the `mustHaveExpression` parameter
10657     * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
10658     * this is typically useful only when user-data is used in rendering a template from the server, or
10659     * when otherwise untrusted data is used by a directive.
10660     *
10661     * <example>
10662     *  <file name="index.html">
10663     *    <div ng-init="username='A user'">
10664     *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
10665     *        </p>
10666     *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
10667     *        application, but fails to accomplish their task, because the server has correctly
10668     *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
10669     *        characters.</p>
10670     *      <p>Instead, the result of the attempted script injection is visible, and can be removed
10671     *        from the database by an administrator.</p>
10672     *    </div>
10673     *  </file>
10674     * </example>
10675     *
10676     * @param {string} text The text with markup to interpolate.
10677     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
10678     *    embedded expression in order to return an interpolation function. Strings with no
10679     *    embedded expression will return null for the interpolation function.
10680     * @param {string=} trustedContext when provided, the returned function passes the interpolated
10681     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
10682     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
10683     *    provides Strict Contextual Escaping for details.
10684     * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
10685     *    unless all embedded expressions evaluate to a value other than `undefined`.
10686     * @returns {function(context)} an interpolation function which is used to compute the
10687     *    interpolated string. The function has these parameters:
10688     *
10689     * - `context`: evaluation context for all expressions embedded in the interpolated text
10690     */
10691    function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
10692      allOrNothing = !!allOrNothing;
10693      var startIndex,
10694          endIndex,
10695          index = 0,
10696          expressions = [],
10697          parseFns = [],
10698          textLength = text.length,
10699          exp,
10700          concat = [],
10701          expressionPositions = [];
10702
10703      while (index < textLength) {
10704        if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
10705             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
10706          if (index !== startIndex) {
10707            concat.push(unescapeText(text.substring(index, startIndex)));
10708          }
10709          exp = text.substring(startIndex + startSymbolLength, endIndex);
10710          expressions.push(exp);
10711          parseFns.push($parse(exp, parseStringifyInterceptor));
10712          index = endIndex + endSymbolLength;
10713          expressionPositions.push(concat.length);
10714          concat.push('');
10715        } else {
10716          // we did not find an interpolation, so we have to add the remainder to the separators array
10717          if (index !== textLength) {
10718            concat.push(unescapeText(text.substring(index)));
10719          }
10720          break;
10721        }
10722      }
10723
10724      // Concatenating expressions makes it hard to reason about whether some combination of
10725      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
10726      // single expression be used for iframe[src], object[src], etc., we ensure that the value
10727      // that's used is assigned or constructed by some JS code somewhere that is more testable or
10728      // make it obvious that you bound the value to some user controlled value.  This helps reduce
10729      // the load when auditing for XSS issues.
10730      if (trustedContext && concat.length > 1) {
10731          $interpolateMinErr.throwNoconcat(text);
10732      }
10733
10734      if (!mustHaveExpression || expressions.length) {
10735        var compute = function(values) {
10736          for (var i = 0, ii = expressions.length; i < ii; i++) {
10737            if (allOrNothing && isUndefined(values[i])) return;
10738            concat[expressionPositions[i]] = values[i];
10739          }
10740          return concat.join('');
10741        };
10742
10743        var getValue = function(value) {
10744          return trustedContext ?
10745            $sce.getTrusted(trustedContext, value) :
10746            $sce.valueOf(value);
10747        };
10748
10749        return extend(function interpolationFn(context) {
10750            var i = 0;
10751            var ii = expressions.length;
10752            var values = new Array(ii);
10753
10754            try {
10755              for (; i < ii; i++) {
10756                values[i] = parseFns[i](context);
10757              }
10758
10759              return compute(values);
10760            } catch (err) {
10761              $exceptionHandler($interpolateMinErr.interr(text, err));
10762            }
10763
10764          }, {
10765          // all of these properties are undocumented for now
10766          exp: text, //just for compatibility with regular watchers created via $watch
10767          expressions: expressions,
10768          $$watchDelegate: function(scope, listener) {
10769            var lastValue;
10770            return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
10771              var currValue = compute(values);
10772              if (isFunction(listener)) {
10773                listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
10774              }
10775              lastValue = currValue;
10776            });
10777          }
10778        });
10779      }
10780
10781      function parseStringifyInterceptor(value) {
10782        try {
10783          value = getValue(value);
10784          return allOrNothing && !isDefined(value) ? value : stringify(value);
10785        } catch (err) {
10786          $exceptionHandler($interpolateMinErr.interr(text, err));
10787        }
10788      }
10789    }
10790
10791
10792    /**
10793     * @ngdoc method
10794     * @name $interpolate#startSymbol
10795     * @description
10796     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
10797     *
10798     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
10799     * the symbol.
10800     *
10801     * @returns {string} start symbol.
10802     */
10803    $interpolate.startSymbol = function() {
10804      return startSymbol;
10805    };
10806
10807
10808    /**
10809     * @ngdoc method
10810     * @name $interpolate#endSymbol
10811     * @description
10812     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
10813     *
10814     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
10815     * the symbol.
10816     *
10817     * @returns {string} end symbol.
10818     */
10819    $interpolate.endSymbol = function() {
10820      return endSymbol;
10821    };
10822
10823    return $interpolate;
10824  }];
10825}
10826
10827function $IntervalProvider() {
10828  this.$get = ['$rootScope', '$window', '$q', '$$q',
10829       function($rootScope,   $window,   $q,   $$q) {
10830    var intervals = {};
10831
10832
10833     /**
10834      * @ngdoc service
10835      * @name $interval
10836      *
10837      * @description
10838      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
10839      * milliseconds.
10840      *
10841      * The return value of registering an interval function is a promise. This promise will be
10842      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
10843      * run indefinitely if `count` is not defined. The value of the notification will be the
10844      * number of iterations that have run.
10845      * To cancel an interval, call `$interval.cancel(promise)`.
10846      *
10847      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
10848      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
10849      * time.
10850      *
10851      * <div class="alert alert-warning">
10852      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
10853      * with them.  In particular they are not automatically destroyed when a controller's scope or a
10854      * directive's element are destroyed.
10855      * You should take this into consideration and make sure to always cancel the interval at the
10856      * appropriate moment.  See the example below for more details on how and when to do this.
10857      * </div>
10858      *
10859      * @param {function()} fn A function that should be called repeatedly.
10860      * @param {number} delay Number of milliseconds between each function call.
10861      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
10862      *   indefinitely.
10863      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
10864      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
10865      * @param {...*=} Pass additional parameters to the executed function.
10866      * @returns {promise} A promise which will be notified on each iteration.
10867      *
10868      * @example
10869      * <example module="intervalExample">
10870      * <file name="index.html">
10871      *   <script>
10872      *     angular.module('intervalExample', [])
10873      *       .controller('ExampleController', ['$scope', '$interval',
10874      *         function($scope, $interval) {
10875      *           $scope.format = 'M/d/yy h:mm:ss a';
10876      *           $scope.blood_1 = 100;
10877      *           $scope.blood_2 = 120;
10878      *
10879      *           var stop;
10880      *           $scope.fight = function() {
10881      *             // Don't start a new fight if we are already fighting
10882      *             if ( angular.isDefined(stop) ) return;
10883      *
10884      *             stop = $interval(function() {
10885      *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
10886      *                 $scope.blood_1 = $scope.blood_1 - 3;
10887      *                 $scope.blood_2 = $scope.blood_2 - 4;
10888      *               } else {
10889      *                 $scope.stopFight();
10890      *               }
10891      *             }, 100);
10892      *           };
10893      *
10894      *           $scope.stopFight = function() {
10895      *             if (angular.isDefined(stop)) {
10896      *               $interval.cancel(stop);
10897      *               stop = undefined;
10898      *             }
10899      *           };
10900      *
10901      *           $scope.resetFight = function() {
10902      *             $scope.blood_1 = 100;
10903      *             $scope.blood_2 = 120;
10904      *           };
10905      *
10906      *           $scope.$on('$destroy', function() {
10907      *             // Make sure that the interval is destroyed too
10908      *             $scope.stopFight();
10909      *           });
10910      *         }])
10911      *       // Register the 'myCurrentTime' directive factory method.
10912      *       // We inject $interval and dateFilter service since the factory method is DI.
10913      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
10914      *         function($interval, dateFilter) {
10915      *           // return the directive link function. (compile function not needed)
10916      *           return function(scope, element, attrs) {
10917      *             var format,  // date format
10918      *                 stopTime; // so that we can cancel the time updates
10919      *
10920      *             // used to update the UI
10921      *             function updateTime() {
10922      *               element.text(dateFilter(new Date(), format));
10923      *             }
10924      *
10925      *             // watch the expression, and update the UI on change.
10926      *             scope.$watch(attrs.myCurrentTime, function(value) {
10927      *               format = value;
10928      *               updateTime();
10929      *             });
10930      *
10931      *             stopTime = $interval(updateTime, 1000);
10932      *
10933      *             // listen on DOM destroy (removal) event, and cancel the next UI update
10934      *             // to prevent updating time after the DOM element was removed.
10935      *             element.on('$destroy', function() {
10936      *               $interval.cancel(stopTime);
10937      *             });
10938      *           }
10939      *         }]);
10940      *   </script>
10941      *
10942      *   <div>
10943      *     <div ng-controller="ExampleController">
10944      *       <label>Date format: <input ng-model="format"></label> <hr/>
10945      *       Current time is: <span my-current-time="format"></span>
10946      *       <hr/>
10947      *       Blood 1 : <font color='red'>{{blood_1}}</font>
10948      *       Blood 2 : <font color='red'>{{blood_2}}</font>
10949      *       <button type="button" data-ng-click="fight()">Fight</button>
10950      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
10951      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
10952      *     </div>
10953      *   </div>
10954      *
10955      * </file>
10956      * </example>
10957      */
10958    function interval(fn, delay, count, invokeApply) {
10959      var hasParams = arguments.length > 4,
10960          args = hasParams ? sliceArgs(arguments, 4) : [],
10961          setInterval = $window.setInterval,
10962          clearInterval = $window.clearInterval,
10963          iteration = 0,
10964          skipApply = (isDefined(invokeApply) && !invokeApply),
10965          deferred = (skipApply ? $$q : $q).defer(),
10966          promise = deferred.promise;
10967
10968      count = isDefined(count) ? count : 0;
10969
10970      promise.then(null, null, (!hasParams) ? fn : function() {
10971        fn.apply(null, args);
10972      });
10973
10974      promise.$$intervalId = setInterval(function tick() {
10975        deferred.notify(iteration++);
10976
10977        if (count > 0 && iteration >= count) {
10978          deferred.resolve(iteration);
10979          clearInterval(promise.$$intervalId);
10980          delete intervals[promise.$$intervalId];
10981        }
10982
10983        if (!skipApply) $rootScope.$apply();
10984
10985      }, delay);
10986
10987      intervals[promise.$$intervalId] = deferred;
10988
10989      return promise;
10990    }
10991
10992
10993     /**
10994      * @ngdoc method
10995      * @name $interval#cancel
10996      *
10997      * @description
10998      * Cancels a task associated with the `promise`.
10999      *
11000      * @param {promise} promise returned by the `$interval` function.
11001      * @returns {boolean} Returns `true` if the task was successfully canceled.
11002      */
11003    interval.cancel = function(promise) {
11004      if (promise && promise.$$intervalId in intervals) {
11005        intervals[promise.$$intervalId].reject('canceled');
11006        $window.clearInterval(promise.$$intervalId);
11007        delete intervals[promise.$$intervalId];
11008        return true;
11009      }
11010      return false;
11011    };
11012
11013    return interval;
11014  }];
11015}
11016
11017/**
11018 * @ngdoc service
11019 * @name $locale
11020 *
11021 * @description
11022 * $locale service provides localization rules for various Angular components. As of right now the
11023 * only public api is:
11024 *
11025 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
11026 */
11027function $LocaleProvider() {
11028  this.$get = function() {
11029    return {
11030      id: 'en-us',
11031
11032      NUMBER_FORMATS: {
11033        DECIMAL_SEP: '.',
11034        GROUP_SEP: ',',
11035        PATTERNS: [
11036          { // Decimal Pattern
11037            minInt: 1,
11038            minFrac: 0,
11039            maxFrac: 3,
11040            posPre: '',
11041            posSuf: '',
11042            negPre: '-',
11043            negSuf: '',
11044            gSize: 3,
11045            lgSize: 3
11046          },{ //Currency Pattern
11047            minInt: 1,
11048            minFrac: 2,
11049            maxFrac: 2,
11050            posPre: '\u00A4',
11051            posSuf: '',
11052            negPre: '(\u00A4',
11053            negSuf: ')',
11054            gSize: 3,
11055            lgSize: 3
11056          }
11057        ],
11058        CURRENCY_SYM: '$'
11059      },
11060
11061      DATETIME_FORMATS: {
11062        MONTH:
11063            'January,February,March,April,May,June,July,August,September,October,November,December'
11064            .split(','),
11065        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
11066        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
11067        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
11068        AMPMS: ['AM','PM'],
11069        medium: 'MMM d, y h:mm:ss a',
11070        'short': 'M/d/yy h:mm a',
11071        fullDate: 'EEEE, MMMM d, y',
11072        longDate: 'MMMM d, y',
11073        mediumDate: 'MMM d, y',
11074        shortDate: 'M/d/yy',
11075        mediumTime: 'h:mm:ss a',
11076        shortTime: 'h:mm a',
11077        ERANAMES: [
11078          "Before Christ",
11079          "Anno Domini"
11080        ],
11081        ERAS: [
11082          "BC",
11083          "AD"
11084        ]
11085      },
11086
11087      pluralCat: function(num) {
11088        if (num === 1) {
11089          return 'one';
11090        }
11091        return 'other';
11092      }
11093    };
11094  };
11095}
11096
11097var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
11098    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
11099var $locationMinErr = minErr('$location');
11100
11101
11102/**
11103 * Encode path using encodeUriSegment, ignoring forward slashes
11104 *
11105 * @param {string} path Path to encode
11106 * @returns {string}
11107 */
11108function encodePath(path) {
11109  var segments = path.split('/'),
11110      i = segments.length;
11111
11112  while (i--) {
11113    segments[i] = encodeUriSegment(segments[i]);
11114  }
11115
11116  return segments.join('/');
11117}
11118
11119function parseAbsoluteUrl(absoluteUrl, locationObj) {
11120  var parsedUrl = urlResolve(absoluteUrl);
11121
11122  locationObj.$$protocol = parsedUrl.protocol;
11123  locationObj.$$host = parsedUrl.hostname;
11124  locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
11125}
11126
11127
11128function parseAppUrl(relativeUrl, locationObj) {
11129  var prefixed = (relativeUrl.charAt(0) !== '/');
11130  if (prefixed) {
11131    relativeUrl = '/' + relativeUrl;
11132  }
11133  var match = urlResolve(relativeUrl);
11134  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
11135      match.pathname.substring(1) : match.pathname);
11136  locationObj.$$search = parseKeyValue(match.search);
11137  locationObj.$$hash = decodeURIComponent(match.hash);
11138
11139  // make sure path starts with '/';
11140  if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
11141    locationObj.$$path = '/' + locationObj.$$path;
11142  }
11143}
11144
11145
11146/**
11147 *
11148 * @param {string} begin
11149 * @param {string} whole
11150 * @returns {string} returns text from whole after begin or undefined if it does not begin with
11151 *                   expected string.
11152 */
11153function beginsWith(begin, whole) {
11154  if (whole.indexOf(begin) === 0) {
11155    return whole.substr(begin.length);
11156  }
11157}
11158
11159
11160function stripHash(url) {
11161  var index = url.indexOf('#');
11162  return index == -1 ? url : url.substr(0, index);
11163}
11164
11165function trimEmptyHash(url) {
11166  return url.replace(/(#.+)|#$/, '$1');
11167}
11168
11169
11170function stripFile(url) {
11171  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
11172}
11173
11174/* return the server only (scheme://host:port) */
11175function serverBase(url) {
11176  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
11177}
11178
11179
11180/**
11181 * LocationHtml5Url represents an url
11182 * This object is exposed as $location service when HTML5 mode is enabled and supported
11183 *
11184 * @constructor
11185 * @param {string} appBase application base URL
11186 * @param {string} basePrefix url path prefix
11187 */
11188function LocationHtml5Url(appBase, basePrefix) {
11189  this.$$html5 = true;
11190  basePrefix = basePrefix || '';
11191  var appBaseNoFile = stripFile(appBase);
11192  parseAbsoluteUrl(appBase, this);
11193
11194
11195  /**
11196   * Parse given html5 (regular) url string into properties
11197   * @param {string} url HTML5 url
11198   * @private
11199   */
11200  this.$$parse = function(url) {
11201    var pathUrl = beginsWith(appBaseNoFile, url);
11202    if (!isString(pathUrl)) {
11203      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
11204          appBaseNoFile);
11205    }
11206
11207    parseAppUrl(pathUrl, this);
11208
11209    if (!this.$$path) {
11210      this.$$path = '/';
11211    }
11212
11213    this.$$compose();
11214  };
11215
11216  /**
11217   * Compose url and update `absUrl` property
11218   * @private
11219   */
11220  this.$$compose = function() {
11221    var search = toKeyValue(this.$$search),
11222        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11223
11224    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11225    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
11226  };
11227
11228  this.$$parseLinkUrl = function(url, relHref) {
11229    if (relHref && relHref[0] === '#') {
11230      // special case for links to hash fragments:
11231      // keep the old url and only replace the hash fragment
11232      this.hash(relHref.slice(1));
11233      return true;
11234    }
11235    var appUrl, prevAppUrl;
11236    var rewrittenUrl;
11237
11238    if ((appUrl = beginsWith(appBase, url)) !== undefined) {
11239      prevAppUrl = appUrl;
11240      if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
11241        rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
11242      } else {
11243        rewrittenUrl = appBase + prevAppUrl;
11244      }
11245    } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
11246      rewrittenUrl = appBaseNoFile + appUrl;
11247    } else if (appBaseNoFile == url + '/') {
11248      rewrittenUrl = appBaseNoFile;
11249    }
11250    if (rewrittenUrl) {
11251      this.$$parse(rewrittenUrl);
11252    }
11253    return !!rewrittenUrl;
11254  };
11255}
11256
11257
11258/**
11259 * LocationHashbangUrl represents url
11260 * This object is exposed as $location service when developer doesn't opt into html5 mode.
11261 * It also serves as the base class for html5 mode fallback on legacy browsers.
11262 *
11263 * @constructor
11264 * @param {string} appBase application base URL
11265 * @param {string} hashPrefix hashbang prefix
11266 */
11267function LocationHashbangUrl(appBase, hashPrefix) {
11268  var appBaseNoFile = stripFile(appBase);
11269
11270  parseAbsoluteUrl(appBase, this);
11271
11272
11273  /**
11274   * Parse given hashbang url into properties
11275   * @param {string} url Hashbang url
11276   * @private
11277   */
11278  this.$$parse = function(url) {
11279    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
11280    var withoutHashUrl;
11281
11282    if (withoutBaseUrl.charAt(0) === '#') {
11283
11284      // The rest of the url starts with a hash so we have
11285      // got either a hashbang path or a plain hash fragment
11286      withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
11287      if (isUndefined(withoutHashUrl)) {
11288        // There was no hashbang prefix so we just have a hash fragment
11289        withoutHashUrl = withoutBaseUrl;
11290      }
11291
11292    } else {
11293      // There was no hashbang path nor hash fragment:
11294      // If we are in HTML5 mode we use what is left as the path;
11295      // Otherwise we ignore what is left
11296      withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
11297    }
11298
11299    parseAppUrl(withoutHashUrl, this);
11300
11301    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
11302
11303    this.$$compose();
11304
11305    /*
11306     * In Windows, on an anchor node on documents loaded from
11307     * the filesystem, the browser will return a pathname
11308     * prefixed with the drive name ('/C:/path') when a
11309     * pathname without a drive is set:
11310     *  * a.setAttribute('href', '/foo')
11311     *   * a.pathname === '/C:/foo' //true
11312     *
11313     * Inside of Angular, we're always using pathnames that
11314     * do not include drive names for routing.
11315     */
11316    function removeWindowsDriveName(path, url, base) {
11317      /*
11318      Matches paths for file protocol on windows,
11319      such as /C:/foo/bar, and captures only /foo/bar.
11320      */
11321      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
11322
11323      var firstPathSegmentMatch;
11324
11325      //Get the relative path from the input URL.
11326      if (url.indexOf(base) === 0) {
11327        url = url.replace(base, '');
11328      }
11329
11330      // The input URL intentionally contains a first path segment that ends with a colon.
11331      if (windowsFilePathExp.exec(url)) {
11332        return path;
11333      }
11334
11335      firstPathSegmentMatch = windowsFilePathExp.exec(path);
11336      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
11337    }
11338  };
11339
11340  /**
11341   * Compose hashbang url and update `absUrl` property
11342   * @private
11343   */
11344  this.$$compose = function() {
11345    var search = toKeyValue(this.$$search),
11346        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11347
11348    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11349    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
11350  };
11351
11352  this.$$parseLinkUrl = function(url, relHref) {
11353    if (stripHash(appBase) == stripHash(url)) {
11354      this.$$parse(url);
11355      return true;
11356    }
11357    return false;
11358  };
11359}
11360
11361
11362/**
11363 * LocationHashbangUrl represents url
11364 * This object is exposed as $location service when html5 history api is enabled but the browser
11365 * does not support it.
11366 *
11367 * @constructor
11368 * @param {string} appBase application base URL
11369 * @param {string} hashPrefix hashbang prefix
11370 */
11371function LocationHashbangInHtml5Url(appBase, hashPrefix) {
11372  this.$$html5 = true;
11373  LocationHashbangUrl.apply(this, arguments);
11374
11375  var appBaseNoFile = stripFile(appBase);
11376
11377  this.$$parseLinkUrl = function(url, relHref) {
11378    if (relHref && relHref[0] === '#') {
11379      // special case for links to hash fragments:
11380      // keep the old url and only replace the hash fragment
11381      this.hash(relHref.slice(1));
11382      return true;
11383    }
11384
11385    var rewrittenUrl;
11386    var appUrl;
11387
11388    if (appBase == stripHash(url)) {
11389      rewrittenUrl = url;
11390    } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
11391      rewrittenUrl = appBase + hashPrefix + appUrl;
11392    } else if (appBaseNoFile === url + '/') {
11393      rewrittenUrl = appBaseNoFile;
11394    }
11395    if (rewrittenUrl) {
11396      this.$$parse(rewrittenUrl);
11397    }
11398    return !!rewrittenUrl;
11399  };
11400
11401  this.$$compose = function() {
11402    var search = toKeyValue(this.$$search),
11403        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
11404
11405    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
11406    // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
11407    this.$$absUrl = appBase + hashPrefix + this.$$url;
11408  };
11409
11410}
11411
11412
11413var locationPrototype = {
11414
11415  /**
11416   * Are we in html5 mode?
11417   * @private
11418   */
11419  $$html5: false,
11420
11421  /**
11422   * Has any change been replacing?
11423   * @private
11424   */
11425  $$replace: false,
11426
11427  /**
11428   * @ngdoc method
11429   * @name $location#absUrl
11430   *
11431   * @description
11432   * This method is getter only.
11433   *
11434   * Return full url representation with all segments encoded according to rules specified in
11435   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
11436   *
11437   *
11438   * ```js
11439   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11440   * var absUrl = $location.absUrl();
11441   * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
11442   * ```
11443   *
11444   * @return {string} full url
11445   */
11446  absUrl: locationGetter('$$absUrl'),
11447
11448  /**
11449   * @ngdoc method
11450   * @name $location#url
11451   *
11452   * @description
11453   * This method is getter / setter.
11454   *
11455   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
11456   *
11457   * Change path, search and hash, when called with parameter and return `$location`.
11458   *
11459   *
11460   * ```js
11461   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11462   * var url = $location.url();
11463   * // => "/some/path?foo=bar&baz=xoxo"
11464   * ```
11465   *
11466   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
11467   * @return {string} url
11468   */
11469  url: function(url) {
11470    if (isUndefined(url)) {
11471      return this.$$url;
11472    }
11473
11474    var match = PATH_MATCH.exec(url);
11475    if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
11476    if (match[2] || match[1] || url === '') this.search(match[3] || '');
11477    this.hash(match[5] || '');
11478
11479    return this;
11480  },
11481
11482  /**
11483   * @ngdoc method
11484   * @name $location#protocol
11485   *
11486   * @description
11487   * This method is getter only.
11488   *
11489   * Return protocol of current url.
11490   *
11491   *
11492   * ```js
11493   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11494   * var protocol = $location.protocol();
11495   * // => "http"
11496   * ```
11497   *
11498   * @return {string} protocol of current url
11499   */
11500  protocol: locationGetter('$$protocol'),
11501
11502  /**
11503   * @ngdoc method
11504   * @name $location#host
11505   *
11506   * @description
11507   * This method is getter only.
11508   *
11509   * Return host of current url.
11510   *
11511   * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
11512   *
11513   *
11514   * ```js
11515   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11516   * var host = $location.host();
11517   * // => "example.com"
11518   *
11519   * // given url http://user:[email protected]:8080/#/some/path?foo=bar&baz=xoxo
11520   * host = $location.host();
11521   * // => "example.com"
11522   * host = location.host;
11523   * // => "example.com:8080"
11524   * ```
11525   *
11526   * @return {string} host of current url.
11527   */
11528  host: locationGetter('$$host'),
11529
11530  /**
11531   * @ngdoc method
11532   * @name $location#port
11533   *
11534   * @description
11535   * This method is getter only.
11536   *
11537   * Return port of current url.
11538   *
11539   *
11540   * ```js
11541   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11542   * var port = $location.port();
11543   * // => 80
11544   * ```
11545   *
11546   * @return {Number} port
11547   */
11548  port: locationGetter('$$port'),
11549
11550  /**
11551   * @ngdoc method
11552   * @name $location#path
11553   *
11554   * @description
11555   * This method is getter / setter.
11556   *
11557   * Return path of current url when called without any parameter.
11558   *
11559   * Change path when called with parameter and return `$location`.
11560   *
11561   * Note: Path should always begin with forward slash (/), this method will add the forward slash
11562   * if it is missing.
11563   *
11564   *
11565   * ```js
11566   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11567   * var path = $location.path();
11568   * // => "/some/path"
11569   * ```
11570   *
11571   * @param {(string|number)=} path New path
11572   * @return {string} path
11573   */
11574  path: locationGetterSetter('$$path', function(path) {
11575    path = path !== null ? path.toString() : '';
11576    return path.charAt(0) == '/' ? path : '/' + path;
11577  }),
11578
11579  /**
11580   * @ngdoc method
11581   * @name $location#search
11582   *
11583   * @description
11584   * This method is getter / setter.
11585   *
11586   * Return search part (as object) of current url when called without any parameter.
11587   *
11588   * Change search part when called with parameter and return `$location`.
11589   *
11590   *
11591   * ```js
11592   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
11593   * var searchObject = $location.search();
11594   * // => {foo: 'bar', baz: 'xoxo'}
11595   *
11596   * // set foo to 'yipee'
11597   * $location.search('foo', 'yipee');
11598   * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
11599   * ```
11600   *
11601   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
11602   * hash object.
11603   *
11604   * When called with a single argument the method acts as a setter, setting the `search` component
11605   * of `$location` to the specified value.
11606   *
11607   * If the argument is a hash object containing an array of values, these values will be encoded
11608   * as duplicate search parameters in the url.
11609   *
11610   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
11611   * will override only a single search property.
11612   *
11613   * If `paramValue` is an array, it will override the property of the `search` component of
11614   * `$location` specified via the first argument.
11615   *
11616   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
11617   *
11618   * If `paramValue` is `true`, the property specified via the first argument will be added with 
vendor: 18,948 bytes, lines 11618-12207
11618no
11619   * value nor trailing equal sign.
11620   *
11621   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
11622   * one or more arguments returns `$location` object itself.
11623   */
11624  search: function(search, paramValue) {
11625    switch (arguments.length) {
11626      case 0:
11627        return this.$$search;
11628      case 1:
11629        if (isString(search) || isNumber(search)) {
11630          search = search.toString();
11631          this.$$search = parseKeyValue(search);
11632        } else if (isObject(search)) {
11633          search = copy(search, {});
11634          // remove object undefined or null properties
11635          forEach(search, function(value, key) {
11636            if (value == null) delete search[key];
11637          });
11638
11639          this.$$search = search;
11640        } else {
11641          throw $locationMinErr('isrcharg',
11642              'The first argument of the `$location#search()` call must be a string or an object.');
11643        }
11644        break;
11645      default:
11646        if (isUndefined(paramValue) || paramValue === null) {
11647          delete this.$$search[search];
11648        } else {
11649          this.$$search[search] = paramValue;
11650        }
11651    }
11652
11653    this.$$compose();
11654    return this;
11655  },
11656
11657  /**
11658   * @ngdoc method
11659   * @name $location#hash
11660   *
11661   * @description
11662   * This method is getter / setter.
11663   *
11664   * Return hash fragment when called without any parameter.
11665   *
11666   * Change hash fragment when called with parameter and return `$location`.
11667   *
11668   *
11669   * ```js
11670   * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
11671   * var hash = $location.hash();
11672   * // => "hashValue"
11673   * ```
11674   *
11675   * @param {(string|number)=} hash New hash fragment
11676   * @return {string} hash
11677   */
11678  hash: locationGetterSetter('$$hash', function(hash) {
11679    return hash !== null ? hash.toString() : '';
11680  }),
11681
11682  /**
11683   * @ngdoc method
11684   * @name $location#replace
11685   *
11686   * @description
11687   * If called, all changes to $location during current `$digest` will be replacing current history
11688   * record, instead of adding new one.
11689   */
11690  replace: function() {
11691    this.$$replace = true;
11692    return this;
11693  }
11694};
11695
11696forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
11697  Location.prototype = Object.create(locationPrototype);
11698
11699  /**
11700   * @ngdoc method
11701   * @name $location#state
11702   *
11703   * @description
11704   * This method is getter / setter.
11705   *
11706   * Return the history state object when called without any parameter.
11707   *
11708   * Change the history state object when called with one parameter and return `$location`.
11709   * The state object is later passed to `pushState` or `replaceState`.
11710   *
11711   * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
11712   * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
11713   * older browsers (like IE9 or Android < 4.0), don't use this method.
11714   *
11715   * @param {object=} state State object for pushState or replaceState
11716   * @return {object} state
11717   */
11718  Location.prototype.state = function(state) {
11719    if (!arguments.length) {
11720      return this.$$state;
11721    }
11722
11723    if (Location !== LocationHtml5Url || !this.$$html5) {
11724      throw $locationMinErr('nostate', 'History API state support is available only ' +
11725        'in HTML5 mode and only in browsers supporting HTML5 History API');
11726    }
11727    // The user might modify `stateObject` after invoking `$location.state(stateObject)`
11728    // but we're changing the $$state reference to $browser.state() during the $digest
11729    // so the modification window is narrow.
11730    this.$$state = isUndefined(state) ? null : state;
11731
11732    return this;
11733  };
11734});
11735
11736
11737function locationGetter(property) {
11738  return function() {
11739    return this[property];
11740  };
11741}
11742
11743
11744function locationGetterSetter(property, preprocess) {
11745  return function(value) {
11746    if (isUndefined(value)) {
11747      return this[property];
11748    }
11749
11750    this[property] = preprocess(value);
11751    this.$$compose();
11752
11753    return this;
11754  };
11755}
11756
11757
11758/**
11759 * @ngdoc service
11760 * @name $location
11761 *
11762 * @requires $rootElement
11763 *
11764 * @description
11765 * The $location service parses the URL in the browser address bar (based on the
11766 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
11767 * available to your application. Changes to the URL in the address bar are reflected into
11768 * $location service and changes to $location are reflected into the browser address bar.
11769 *
11770 * **The $location service:**
11771 *
11772 * - Exposes the current URL in the browser address bar, so you can
11773 *   - Watch and observe the URL.
11774 *   - Change the URL.
11775 * - Synchronizes the URL with the browser when the user
11776 *   - Changes the address bar.
11777 *   - Clicks the back or forward button (or clicks a History link).
11778 *   - Clicks on a link.
11779 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
11780 *
11781 * For more information see {@link guide/$location Developer Guide: Using $location}
11782 */
11783
11784/**
11785 * @ngdoc provider
11786 * @name $locationProvider
11787 * @description
11788 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
11789 */
11790function $LocationProvider() {
11791  var hashPrefix = '',
11792      html5Mode = {
11793        enabled: false,
11794        requireBase: true,
11795        rewriteLinks: true
11796      };
11797
11798  /**
11799   * @ngdoc method
11800   * @name $locationProvider#hashPrefix
11801   * @description
11802   * @param {string=} prefix Prefix for hash part (containing path and search)
11803   * @returns {*} current value if used as getter or itself (chaining) if used as setter
11804   */
11805  this.hashPrefix = function(prefix) {
11806    if (isDefined(prefix)) {
11807      hashPrefix = prefix;
11808      return this;
11809    } else {
11810      return hashPrefix;
11811    }
11812  };
11813
11814  /**
11815   * @ngdoc method
11816   * @name $locationProvider#html5Mode
11817   * @description
11818   * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
11819   *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
11820   *   properties:
11821   *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
11822   *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
11823   *     support `pushState`.
11824   *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
11825   *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
11826   *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
11827   *     See the {@link guide/$location $location guide for more information}
11828   *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
11829   *     enables/disables url rewriting for relative links.
11830   *
11831   * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
11832   */
11833  this.html5Mode = function(mode) {
11834    if (isBoolean(mode)) {
11835      html5Mode.enabled = mode;
11836      return this;
11837    } else if (isObject(mode)) {
11838
11839      if (isBoolean(mode.enabled)) {
11840        html5Mode.enabled = mode.enabled;
11841      }
11842
11843      if (isBoolean(mode.requireBase)) {
11844        html5Mode.requireBase = mode.requireBase;
11845      }
11846
11847      if (isBoolean(mode.rewriteLinks)) {
11848        html5Mode.rewriteLinks = mode.rewriteLinks;
11849      }
11850
11851      return this;
11852    } else {
11853      return html5Mode;
11854    }
11855  };
11856
11857  /**
11858   * @ngdoc event
11859   * @name $location#$locationChangeStart
11860   * @eventType broadcast on root scope
11861   * @description
11862   * Broadcasted before a URL will change.
11863   *
11864   * This change can be prevented by calling
11865   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
11866   * details about event object. Upon successful change
11867   * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
11868   *
11869   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11870   * the browser supports the HTML5 History API.
11871   *
11872   * @param {Object} angularEvent Synthetic event object.
11873   * @param {string} newUrl New URL
11874   * @param {string=} oldUrl URL that was before it was changed.
11875   * @param {string=} newState New history state object
11876   * @param {string=} oldState History state object that was before it was changed.
11877   */
11878
11879  /**
11880   * @ngdoc event
11881   * @name $location#$locationChangeSuccess
11882   * @eventType broadcast on root scope
11883   * @description
11884   * Broadcasted after a URL was changed.
11885   *
11886   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
11887   * the browser supports the HTML5 History API.
11888   *
11889   * @param {Object} angularEvent Synthetic event object.
11890   * @param {string} newUrl New URL
11891   * @param {string=} oldUrl URL that was before it was changed.
11892   * @param {string=} newState New history state object
11893   * @param {string=} oldState History state object that was before it was changed.
11894   */
11895
11896  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
11897      function($rootScope, $browser, $sniffer, $rootElement, $window) {
11898    var $location,
11899        LocationMode,
11900        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
11901        initialUrl = $browser.url(),
11902        appBase;
11903
11904    if (html5Mode.enabled) {
11905      if (!baseHref && html5Mode.requireBase) {
11906        throw $locationMinErr('nobase',
11907          "$location in HTML5 mode requires a <base> tag to be present!");
11908      }
11909      appBase = serverBase(initialUrl) + (baseHref || '/');
11910      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
11911    } else {
11912      appBase = stripHash(initialUrl);
11913      LocationMode = LocationHashbangUrl;
11914    }
11915    $location = new LocationMode(appBase, '#' + hashPrefix);
11916    $location.$$parseLinkUrl(initialUrl, initialUrl);
11917
11918    $location.$$state = $browser.state();
11919
11920    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
11921
11922    function setBrowserUrlWithFallback(url, replace, state) {
11923      var oldUrl = $location.url();
11924      var oldState = $location.$$state;
11925      try {
11926        $browser.url(url, replace, state);
11927
11928        // Make sure $location.state() returns referentially identical (not just deeply equal)
11929        // state object; this makes possible quick checking if the state changed in the digest
11930        // loop. Checking deep equality would be too expensive.
11931        $location.$$state = $browser.state();
11932      } catch (e) {
11933        // Restore old values if pushState fails
11934        $location.url(oldUrl);
11935        $location.$$state = oldState;
11936
11937        throw e;
11938      }
11939    }
11940
11941    $rootElement.on('click', function(event) {
11942      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
11943      // currently we open nice url link and redirect then
11944
11945      if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
11946
11947      var elm = jqLite(event.target);
11948
11949      // traverse the DOM up to find first A tag
11950      while (nodeName_(elm[0]) !== 'a') {
11951        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
11952        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
11953      }
11954
11955      var absHref = elm.prop('href');
11956      // get the actual href attribute - see
11957      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
11958      var relHref = elm.attr('href') || elm.attr('xlink:href');
11959
11960      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
11961        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
11962        // an animation.
11963        absHref = urlResolve(absHref.animVal).href;
11964      }
11965
11966      // Ignore when url is started with javascript: or mailto:
11967      if (IGNORE_URI_REGEXP.test(absHref)) return;
11968
11969      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
11970        if ($location.$$parseLinkUrl(absHref, relHref)) {
11971          // We do a preventDefault for all urls that are part of the angular application,
11972          // in html5mode and also without, so that we are able to abort navigation without
11973          // getting double entries in the location history.
11974          event.preventDefault();
11975          // update location manually
11976          if ($location.absUrl() != $browser.url()) {
11977            $rootScope.$apply();
11978            // hack to work around FF6 bug 684208 when scenario runner clicks on links
11979            $window.angular['ff-684208-preventDefault'] = true;
11980          }
11981        }
11982      }
11983    });
11984
11985
11986    // rewrite hashbang url <> html5 url
11987    if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
11988      $browser.url($location.absUrl(), true);
11989    }
11990
11991    var initializing = true;
11992
11993    // update $location when $browser url changes
11994    $browser.onUrlChange(function(newUrl, newState) {
11995      $rootScope.$evalAsync(function() {
11996        var oldUrl = $location.absUrl();
11997        var oldState = $location.$$state;
11998        var defaultPrevented;
11999
12000        $location.$$parse(newUrl);
12001        $location.$$state = newState;
12002
12003        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12004            newState, oldState).defaultPrevented;
12005
12006        // if the location was changed by a `$locationChangeStart` handler then stop
12007        // processing this location change
12008        if ($location.absUrl() !== newUrl) return;
12009
12010        if (defaultPrevented) {
12011          $location.$$parse(oldUrl);
12012          $location.$$state = oldState;
12013          setBrowserUrlWithFallback(oldUrl, false, oldState);
12014        } else {
12015          initializing = false;
12016          afterLocationChange(oldUrl, oldState);
12017        }
12018      });
12019      if (!$rootScope.$$phase) $rootScope.$digest();
12020    });
12021
12022    // update browser
12023    $rootScope.$watch(function $locationWatch() {
12024      var oldUrl = trimEmptyHash($browser.url());
12025      var newUrl = trimEmptyHash($location.absUrl());
12026      var oldState = $browser.state();
12027      var currentReplace = $location.$$replace;
12028      var urlOrStateChanged = oldUrl !== newUrl ||
12029        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
12030
12031      if (initializing || urlOrStateChanged) {
12032        initializing = false;
12033
12034        $rootScope.$evalAsync(function() {
12035          var newUrl = $location.absUrl();
12036          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
12037              $location.$$state, oldState).defaultPrevented;
12038
12039          // if the location was changed by a `$locationChangeStart` handler then stop
12040          // processing this location change
12041          if ($location.absUrl() !== newUrl) return;
12042
12043          if (defaultPrevented) {
12044            $location.$$parse(oldUrl);
12045            $location.$$state = oldState;
12046          } else {
12047            if (urlOrStateChanged) {
12048              setBrowserUrlWithFallback(newUrl, currentReplace,
12049                                        oldState === $location.$$state ? null : $location.$$state);
12050            }
12051            afterLocationChange(oldUrl, oldState);
12052          }
12053        });
12054      }
12055
12056      $location.$$replace = false;
12057
12058      // we don't need to return anything because $evalAsync will make the digest loop dirty when
12059      // there is a change
12060    });
12061
12062    return $location;
12063
12064    function afterLocationChange(oldUrl, oldState) {
12065      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
12066        $location.$$state, oldState);
12067    }
12068}];
12069}
12070
12071/**
12072 * @ngdoc service
12073 * @name $log
12074 * @requires $window
12075 *
12076 * @description
12077 * Simple service for logging. Default implementation safely writes the message
12078 * into the browser's console (if present).
12079 *
12080 * The main purpose of this service is to simplify debugging and troubleshooting.
12081 *
12082 * The default is to log `debug` messages. You can use
12083 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
12084 *
12085 * @example
12086   <example module="logExample">
12087     <file name="script.js">
12088       angular.module('logExample', [])
12089         .controller('LogController', ['$scope', '$log', function($scope, $log) {
12090           $scope.$log = $log;
12091           $scope.message = 'Hello World!';
12092         }]);
12093     </file>
12094     <file name="index.html">
12095       <div ng-controller="LogController">
12096         <p>Reload this page with open console, enter text and hit the log button...</p>
12097         <label>Message:
12098         <input type="text" ng-model="message" /></label>
12099         <button ng-click="$log.log(message)">log</button>
12100         <button ng-click="$log.warn(message)">warn</button>
12101         <button ng-click="$log.info(message)">info</button>
12102         <button ng-click="$log.error(message)">error</button>
12103         <button ng-click="$log.debug(message)">debug</button>
12104       </div>
12105     </file>
12106   </example>
12107 */
12108
12109/**
12110 * @ngdoc provider
12111 * @name $logProvider
12112 * @description
12113 * Use the `$logProvider` to configure how the application logs messages
12114 */
12115function $LogProvider() {
12116  var debug = true,
12117      self = this;
12118
12119  /**
12120   * @ngdoc method
12121   * @name $logProvider#debugEnabled
12122   * @description
12123   * @param {boolean=} flag enable or disable debug level messages
12124   * @returns {*} current value if used as getter or itself (chaining) if used as setter
12125   */
12126  this.debugEnabled = function(flag) {
12127    if (isDefined(flag)) {
12128      debug = flag;
12129    return this;
12130    } else {
12131      return debug;
12132    }
12133  };
12134
12135  this.$get = ['$window', function($window) {
12136    return {
12137      /**
12138       * @ngdoc method
12139       * @name $log#log
12140       *
12141       * @description
12142       * Write a log message
12143       */
12144      log: consoleLog('log'),
12145
12146      /**
12147       * @ngdoc method
12148       * @name $log#info
12149       *
12150       * @description
12151       * Write an information message
12152       */
12153      info: consoleLog('info'),
12154
12155      /**
12156       * @ngdoc method
12157       * @name $log#warn
12158       *
12159       * @description
12160       * Write a warning message
12161       */
12162      warn: consoleLog('warn'),
12163
12164      /**
12165       * @ngdoc method
12166       * @name $log#error
12167       *
12168       * @description
12169       * Write an error message
12170       */
12171      error: consoleLog('error'),
12172
12173      /**
12174       * @ngdoc method
12175       * @name $log#debug
12176       *
12177       * @description
12178       * Write a debug message
12179       */
12180      debug: (function() {
12181        var fn = consoleLog('debug');
12182
12183        return function() {
12184          if (debug) {
12185            fn.apply(self, arguments);
12186          }
12187        };
12188      }())
12189    };
12190
12191    function formatError(arg) {
12192      if (arg instanceof Error) {
12193        if (arg.stack) {
12194          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
12195              ? 'Error: ' + arg.message + '\n' + arg.stack
12196              : arg.stack;
12197        } else if (arg.sourceURL) {
12198          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
12199        }
12200      }
12201      return arg;
12202    }
12203
12204    function consoleLog(type) {
12205      var console = $window.console || {},
12206          logFn = console[type] || console.log || noop,
12207          hasApply = false;
12208
12209      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
12210      // The reason behind this is that console.log has type "object" in IE8...
12211      try {
12212        hasApply = !!logFn.apply;
12213      } catch (e) {}
12214
12215      if (hasApply) {
12216        return function() {
12217          var args = [];
12218          forEach(arguments, function(arg) {
12219            args.push(formatError(arg));
12220          });
12221          return logFn.apply(console, args);
12222        };
12223      }
12224
12225      // we are IE which either doesn't have window.console => this is noop and we do nothing,
12226      // or we are IE where console.log doesn't have apply so we log at least first 2 args
12227      return function(arg1, arg2) {
12228        logFn(arg1, arg2 == null ? '' : arg2);
12229      };
12230    }
12231  }];
12232}
12233
12234/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
12235 *     Any commits to this file should be reviewed with security in mind.  *
12236 *   Changes to this file can potentially create security vulnerabilities. *
12237 *          An approval from 2 Core members with history of modifying      *
12238 *                         this file is required.                          *
12239 *                                                                         *
12240 *  Does the change somehow allow for arbitrary javascript to be executed? *
12241 *    Or allows for someone to change the prototype of built-in objects?   *
12242 *     Or gives undesired access to variables likes document or window?    *
12243 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12244
12245var $parseMinErr = minErr('$parse');
12246
12247// Sandboxing Angular Expressions
12248// ------------------------------
12249// Angular expressions are generally considered safe because these expressions only have direct
12250// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
12251// obtaining a reference to native JS functions such as the Function constructor.
12252//
12253// As an example, consider the following Angular expression:
12254//
12255//   {}.toString.constructor('alert("evil JS code")')
12256//
12257// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
12258// against the expression language, but not to prevent exploits that were enabled by exposing
12259// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
12260// practice and therefore we are not even trying to protect against interaction with an object
12261// explicitly exposed in this way.
12262//
12263// In general, it is not possible to access a Window object from an angular expression unless a
12264// window or some DOM object that has a reference to window is published onto a Scope.
12265// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
12266// native objects.
12267//
12268// See https://docs.angularjs.org/guide/security
12269
12270
12271function ensureSafeMemberName(name, fullExpression) {
12272  if (name === "__defineGetter__" || name === "__defineSetter__"
12273      || name === "__lookupGetter__" || name === "__lookupSetter__"
12274      || name === "__proto__") {
12275    throw $parseMinErr('isecfld',
12276        'Attempting to access a disallowed field in Angular expressions! '
12277        + 'Expression: {0}', fullExpression);
12278  }
12279  return name;
12280}
12281
12282function ensureSafeObject(obj, fullExpression) {
12283  // nifty check if obj is Function that is fast and works across iframes and other contexts
12284  if (obj) {
12285    if (obj.constructor === obj) {
12286      throw $parseMinErr('isecfn',
12287          'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12288          fullExpression);
12289    } else if (// isWindow(obj)
12290        obj.window === obj) {
12291      throw $parseMinErr('isecwindow',
12292          'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
12293          fullExpression);
12294    } else if (// isElement(obj)
12295        obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
12296      throw $parseMinErr('isecdom',
12297          'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
12298          fullExpression);
12299    } else if (// block Object so that we can't get hold of dangerous Object.* methods
12300        obj === Object) {
12301      throw $parseMinErr('isecobj',
12302          'Referencing Object in Angular expressions is disallowed! Expression: {0}',
12303          fullExpression);
12304    }
12305  }
12306  return obj;
12307}
12308
12309var CALL = Function.prototype.call;
12310var APPLY = Function.prototype.apply;
12311var BIND = Function.prototype.bind;
12312
12313function ensureSafeFunction(obj, fullExpression) {
12314  if (obj) {
12315    if (obj.constructor === obj) {
12316      throw $parseMinErr('isecfn',
12317        'Referencing Function in Angular expressions is disallowed! Expression: {0}',
12318        fullExpression);
12319    } else if (obj === CALL || obj === APPLY || obj === BIND) {
12320      throw $parseMinErr('isecff',
12321        'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
12322        fullExpression);
12323    }
12324  }
12325}
12326
12327var OPERATORS = createMap();
12328forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
12329var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
12330
12331
vendor: 47,060 bytes, lines 12332-13813
12332/////////////////////////////////////////
12333
12334
12335/**
12336 * @constructor
12337 */
12338var Lexer = function(options) {
12339  this.options = options;
12340};
12341
12342Lexer.prototype = {
12343  constructor: Lexer,
12344
12345  lex: function(text) {
12346    this.text = text;
12347    this.index = 0;
12348    this.tokens = [];
12349
12350    while (this.index < this.text.length) {
12351      var ch = this.text.charAt(this.index);
12352      if (ch === '"' || ch === "'") {
12353        this.readString(ch);
12354      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
12355        this.readNumber();
12356      } else if (this.isIdent(ch)) {
12357        this.readIdent();
12358      } else if (this.is(ch, '(){}[].,;:?')) {
12359        this.tokens.push({index: this.index, text: ch});
12360        this.index++;
12361      } else if (this.isWhitespace(ch)) {
12362        this.index++;
12363      } else {
12364        var ch2 = ch + this.peek();
12365        var ch3 = ch2 + this.peek(2);
12366        var op1 = OPERATORS[ch];
12367        var op2 = OPERATORS[ch2];
12368        var op3 = OPERATORS[ch3];
12369        if (op1 || op2 || op3) {
12370          var token = op3 ? ch3 : (op2 ? ch2 : ch);
12371          this.tokens.push({index: this.index, text: token, operator: true});
12372          this.index += token.length;
12373        } else {
12374          this.throwError('Unexpected next character ', this.index, this.index + 1);
12375        }
12376      }
12377    }
12378    return this.tokens;
12379  },
12380
12381  is: function(ch, chars) {
12382    return chars.indexOf(ch) !== -1;
12383  },
12384
12385  peek: function(i) {
12386    var num = i || 1;
12387    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
12388  },
12389
12390  isNumber: function(ch) {
12391    return ('0' <= ch && ch <= '9') && typeof ch === "string";
12392  },
12393
12394  isWhitespace: function(ch) {
12395    // IE treats non-breaking space as \u00A0
12396    return (ch === ' ' || ch === '\r' || ch === '\t' ||
12397            ch === '\n' || ch === '\v' || ch === '\u00A0');
12398  },
12399
12400  isIdent: function(ch) {
12401    return ('a' <= ch && ch <= 'z' ||
12402            'A' <= ch && ch <= 'Z' ||
12403            '_' === ch || ch === '$');
12404  },
12405
12406  isExpOperator: function(ch) {
12407    return (ch === '-' || ch === '+' || this.isNumber(ch));
12408  },
12409
12410  throwError: function(error, start, end) {
12411    end = end || this.index;
12412    var colStr = (isDefined(start)
12413            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
12414            : ' ' + end);
12415    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
12416        error, colStr, this.text);
12417  },
12418
12419  readNumber: function() {
12420    var number = '';
12421    var start = this.index;
12422    while (this.index < this.text.length) {
12423      var ch = lowercase(this.text.charAt(this.index));
12424      if (ch == '.' || this.isNumber(ch)) {
12425        number += ch;
12426      } else {
12427        var peekCh = this.peek();
12428        if (ch == 'e' && this.isExpOperator(peekCh)) {
12429          number += ch;
12430        } else if (this.isExpOperator(ch) &&
12431            peekCh && this.isNumber(peekCh) &&
12432            number.charAt(number.length - 1) == 'e') {
12433          number += ch;
12434        } else if (this.isExpOperator(ch) &&
12435            (!peekCh || !this.isNumber(peekCh)) &&
12436            number.charAt(number.length - 1) == 'e') {
12437          this.throwError('Invalid exponent');
12438        } else {
12439          break;
12440        }
12441      }
12442      this.index++;
12443    }
12444    this.tokens.push({
12445      index: start,
12446      text: number,
12447      constant: true,
12448      value: Number(number)
12449    });
12450  },
12451
12452  readIdent: function() {
12453    var start = this.index;
12454    while (this.index < this.text.length) {
12455      var ch = this.text.charAt(this.index);
12456      if (!(this.isIdent(ch) || this.isNumber(ch))) {
12457        break;
12458      }
12459      this.index++;
12460    }
12461    this.tokens.push({
12462      index: start,
12463      text: this.text.slice(start, this.index),
12464      identifier: true
12465    });
12466  },
12467
12468  readString: function(quote) {
12469    var start = this.index;
12470    this.index++;
12471    var string = '';
12472    var rawString = quote;
12473    var escape = false;
12474    while (this.index < this.text.length) {
12475      var ch = this.text.charAt(this.index);
12476      rawString += ch;
12477      if (escape) {
12478        if (ch === 'u') {
12479          var hex = this.text.substring(this.index + 1, this.index + 5);
12480          if (!hex.match(/[\da-f]{4}/i)) {
12481            this.throwError('Invalid unicode escape [\\u' + hex + ']');
12482          }
12483          this.index += 4;
12484          string += String.fromCharCode(parseInt(hex, 16));
12485        } else {
12486          var rep = ESCAPE[ch];
12487          string = string + (rep || ch);
12488        }
12489        escape = false;
12490      } else if (ch === '\\') {
12491        escape = true;
12492      } else if (ch === quote) {
12493        this.index++;
12494        this.tokens.push({
12495          index: start,
12496          text: rawString,
12497          constant: true,
12498          value: string
12499        });
12500        return;
12501      } else {
12502        string += ch;
12503      }
12504      this.index++;
12505    }
12506    this.throwError('Unterminated quote', start);
12507  }
12508};
12509
12510var AST = function(lexer, options) {
12511  this.lexer = lexer;
12512  this.options = options;
12513};
12514
12515AST.Program = 'Program';
12516AST.ExpressionStatement = 'ExpressionStatement';
12517AST.AssignmentExpression = 'AssignmentExpression';
12518AST.ConditionalExpression = 'ConditionalExpression';
12519AST.LogicalExpression = 'LogicalExpression';
12520AST.BinaryExpression = 'BinaryExpression';
12521AST.UnaryExpression = 'UnaryExpression';
12522AST.CallExpression = 'CallExpression';
12523AST.MemberExpression = 'MemberExpression';
12524AST.Identifier = 'Identifier';
12525AST.Literal = 'Literal';
12526AST.ArrayExpression = 'ArrayExpression';
12527AST.Property = 'Property';
12528AST.ObjectExpression = 'ObjectExpression';
12529AST.ThisExpression = 'ThisExpression';
12530
12531// Internal use only
12532AST.NGValueParameter = 'NGValueParameter';
12533
12534AST.prototype = {
12535  ast: function(text) {
12536    this.text = text;
12537    this.tokens = this.lexer.lex(text);
12538
12539    var value = this.program();
12540
12541    if (this.tokens.length !== 0) {
12542      this.throwError('is an unexpected token', this.tokens[0]);
12543    }
12544
12545    return value;
12546  },
12547
12548  program: function() {
12549    var body = [];
12550    while (true) {
12551      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
12552        body.push(this.expressionStatement());
12553      if (!this.expect(';')) {
12554        return { type: AST.Program, body: body};
12555      }
12556    }
12557  },
12558
12559  expressionStatement: function() {
12560    return { type: AST.ExpressionStatement, expression: this.filterChain() };
12561  },
12562
12563  filterChain: function() {
12564    var left = this.expression();
12565    var token;
12566    while ((token = this.expect('|'))) {
12567      left = this.filter(left);
12568    }
12569    return left;
12570  },
12571
12572  expression: function() {
12573    return this.assignment();
12574  },
12575
12576  assignment: function() {
12577    var result = this.ternary();
12578    if (this.expect('=')) {
12579      result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
12580    }
12581    return result;
12582  },
12583
12584  ternary: function() {
12585    var test = this.logicalOR();
12586    var alternate;
12587    var consequent;
12588    if (this.expect('?')) {
12589      alternate = this.expression();
12590      if (this.consume(':')) {
12591        consequent = this.expression();
12592        return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
12593      }
12594    }
12595    return test;
12596  },
12597
12598  logicalOR: function() {
12599    var left = this.logicalAND();
12600    while (this.expect('||')) {
12601      left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
12602    }
12603    return left;
12604  },
12605
12606  logicalAND: function() {
12607    var left = this.equality();
12608    while (this.expect('&&')) {
12609      left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
12610    }
12611    return left;
12612  },
12613
12614  equality: function() {
12615    var left = this.relational();
12616    var token;
12617    while ((token = this.expect('==','!=','===','!=='))) {
12618      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
12619    }
12620    return left;
12621  },
12622
12623  relational: function() {
12624    var left = this.additive();
12625    var token;
12626    while ((token = this.expect('<', '>', '<=', '>='))) {
12627      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
12628    }
12629    return left;
12630  },
12631
12632  additive: function() {
12633    var left = this.multiplicative();
12634    var token;
12635    while ((token = this.expect('+','-'))) {
12636      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
12637    }
12638    return left;
12639  },
12640
12641  multiplicative: function() {
12642    var left = this.unary();
12643    var token;
12644    while ((token = this.expect('*','/','%'))) {
12645      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
12646    }
12647    return left;
12648  },
12649
12650  unary: function() {
12651    var token;
12652    if ((token = this.expect('+', '-', '!'))) {
12653      return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
12654    } else {
12655      return this.primary();
12656    }
12657  },
12658
12659  primary: function() {
12660    var primary;
12661    if (this.expect('(')) {
12662      primary = this.filterChain();
12663      this.consume(')');
12664    } else if (this.expect('[')) {
12665      primary = this.arrayDeclaration();
12666    } else if (this.expect('{')) {
12667      primary = this.object();
12668    } else if (this.constants.hasOwnProperty(this.peek().text)) {
12669      primary = copy(this.constants[this.consume().text]);
12670    } else if (this.peek().identifier) {
12671      primary = this.identifier();
12672    } else if (this.peek().constant) {
12673      primary = this.constant();
12674    } else {
12675      this.throwError('not a primary expression', this.peek());
12676    }
12677
12678    var next;
12679    while ((next = this.expect('(', '[', '.'))) {
12680      if (next.text === '(') {
12681        primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
12682        this.consume(')');
12683      } else if (next.text === '[') {
12684        primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
12685        this.consume(']');
12686      } else if (next.text === '.') {
12687        primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
12688      } else {
12689        this.throwError('IMPOSSIBLE');
12690      }
12691    }
12692    return primary;
12693  },
12694
12695  filter: function(baseExpression) {
12696    var args = [baseExpression];
12697    var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
12698
12699    while (this.expect(':')) {
12700      args.push(this.expression());
12701    }
12702
12703    return result;
12704  },
12705
12706  parseArguments: function() {
12707    var args = [];
12708    if (this.peekToken().text !== ')') {
12709      do {
12710        args.push(this.expression());
12711      } while (this.expect(','));
12712    }
12713    return args;
12714  },
12715
12716  identifier: function() {
12717    var token = this.consume();
12718    if (!token.identifier) {
12719      this.throwError('is not a valid identifier', token);
12720    }
12721    return { type: AST.Identifier, name: token.text };
12722  },
12723
12724  constant: function() {
12725    // TODO check that it is a constant
12726    return { type: AST.Literal, value: this.consume().value };
12727  },
12728
12729  arrayDeclaration: function() {
12730    var elements = [];
12731    if (this.peekToken().text !== ']') {
12732      do {
12733        if (this.peek(']')) {
12734          // Support trailing commas per ES5.1.
12735          break;
12736        }
12737        elements.push(this.expression());
12738      } while (this.expect(','));
12739    }
12740    this.consume(']');
12741
12742    return { type: AST.ArrayExpression, elements: elements };
12743  },
12744
12745  object: function() {
12746    var properties = [], property;
12747    if (this.peekToken().text !== '}') {
12748      do {
12749        if (this.peek('}')) {
12750          // Support trailing commas per ES5.1.
12751          break;
12752        }
12753        property = {type: AST.Property, kind: 'init'};
12754        if (this.peek().constant) {
12755          property.key = this.constant();
12756        } else if (this.peek().identifier) {
12757          property.key = this.identifier();
12758        } else {
12759          this.throwError("invalid key", this.peek());
12760        }
12761        this.consume(':');
12762        property.value = this.expression();
12763        properties.push(property);
12764      } while (this.expect(','));
12765    }
12766    this.consume('}');
12767
12768    return {type: AST.ObjectExpression, properties: properties };
12769  },
12770
12771  throwError: function(msg, token) {
12772    throw $parseMinErr('syntax',
12773        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
12774          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
12775  },
12776
12777  consume: function(e1) {
12778    if (this.tokens.length === 0) {
12779      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12780    }
12781
12782    var token = this.expect(e1);
12783    if (!token) {
12784      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
12785    }
12786    return token;
12787  },
12788
12789  peekToken: function() {
12790    if (this.tokens.length === 0) {
12791      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
12792    }
12793    return this.tokens[0];
12794  },
12795
12796  peek: function(e1, e2, e3, e4) {
12797    return this.peekAhead(0, e1, e2, e3, e4);
12798  },
12799
12800  peekAhead: function(i, e1, e2, e3, e4) {
12801    if (this.tokens.length > i) {
12802      var token = this.tokens[i];
12803      var t = token.text;
12804      if (t === e1 || t === e2 || t === e3 || t === e4 ||
12805          (!e1 && !e2 && !e3 && !e4)) {
12806        return token;
12807      }
12808    }
12809    return false;
12810  },
12811
12812  expect: function(e1, e2, e3, e4) {
12813    var token = this.peek(e1, e2, e3, e4);
12814    if (token) {
12815      this.tokens.shift();
12816      return token;
12817    }
12818    return false;
12819  },
12820
12821
12822  /* `undefined` is not a constant, it is an identifier,
12823   * but using it as an identifier is not supported
12824   */
12825  constants: {
12826    'true': { type: AST.Literal, value: true },
12827    'false': { type: AST.Literal, value: false },
12828    'null': { type: AST.Literal, value: null },
12829    'undefined': {type: AST.Literal, value: undefined },
12830    'this': {type: AST.ThisExpression }
12831  }
12832};
12833
12834function ifDefined(v, d) {
12835  return typeof v !== 'undefined' ? v : d;
12836}
12837
12838function plusFn(l, r) {
12839  if (typeof l === 'undefined') return r;
12840  if (typeof r === 'undefined') return l;
12841  return l + r;
12842}
12843
12844function isStateless($filter, filterName) {
12845  var fn = $filter(filterName);
12846  return !fn.$stateful;
12847}
12848
12849function findConstantAndWatchExpressions(ast, $filter) {
12850  var allConstants;
12851  var argsToWatch;
12852  switch (ast.type) {
12853  case AST.Program:
12854    allConstants = true;
12855    forEach(ast.body, function(expr) {
12856      findConstantAndWatchExpressions(expr.expression, $filter);
12857      allConstants = allConstants && expr.expression.constant;
12858    });
12859    ast.constant = allConstants;
12860    break;
12861  case AST.Literal:
12862    ast.constant = true;
12863    ast.toWatch = [];
12864    break;
12865  case AST.UnaryExpression:
12866    findConstantAndWatchExpressions(ast.argument, $filter);
12867    ast.constant = ast.argument.constant;
12868    ast.toWatch = ast.argument.toWatch;
12869    break;
12870  case AST.BinaryExpression:
12871    findConstantAndWatchExpressions(ast.left, $filter);
12872    findConstantAndWatchExpressions(ast.right, $filter);
12873    ast.constant = ast.left.constant && ast.right.constant;
12874    ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
12875    break;
12876  case AST.LogicalExpression:
12877    findConstantAndWatchExpressions(ast.left, $filter);
12878    findConstantAndWatchExpressions(ast.right, $filter);
12879    ast.constant = ast.left.constant && ast.right.constant;
12880    ast.toWatch = ast.constant ? [] : [ast];
12881    break;
12882  case AST.ConditionalExpression:
12883    findConstantAndWatchExpressions(ast.test, $filter);
12884    findConstantAndWatchExpressions(ast.alternate, $filter);
12885    findConstantAndWatchExpressions(ast.consequent, $filter);
12886    ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
12887    ast.toWatch = ast.constant ? [] : [ast];
12888    break;
12889  case AST.Identifier:
12890    ast.constant = false;
12891    ast.toWatch = [ast];
12892    break;
12893  case AST.MemberExpression:
12894    findConstantAndWatchExpressions(ast.object, $filter);
12895    if (ast.computed) {
12896      findConstantAndWatchExpressions(ast.property, $filter);
12897    }
12898    ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
12899    ast.toWatch = [ast];
12900    break;
12901  case AST.CallExpression:
12902    allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
12903    argsToWatch = [];
12904    forEach(ast.arguments, function(expr) {
12905      findConstantAndWatchExpressions(expr, $filter);
12906      allConstants = allConstants && expr.constant;
12907      if (!expr.constant) {
12908        argsToWatch.push.apply(argsToWatch, expr.toWatch);
12909      }
12910    });
12911    ast.constant = allConstants;
12912    ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
12913    break;
12914  case AST.AssignmentExpression:
12915    findConstantAndWatchExpressions(ast.left, $filter);
12916    findConstantAndWatchExpressions(ast.right, $filter);
12917    ast.constant = ast.left.constant && ast.right.constant;
12918    ast.toWatch = [ast];
12919    break;
12920  case AST.ArrayExpression:
12921    allConstants = true;
12922    argsToWatch = [];
12923    forEach(ast.elements, function(expr) {
12924      findConstantAndWatchExpressions(expr, $filter);
12925      allConstants = allConstants && expr.constant;
12926      if (!expr.constant) {
12927        argsToWatch.push.apply(argsToWatch, expr.toWatch);
12928      }
12929    });
12930    ast.constant = allConstants;
12931    ast.toWatch = argsToWatch;
12932    break;
12933  case AST.ObjectExpression:
12934    allConstants = true;
12935    argsToWatch = [];
12936    forEach(ast.properties, function(property) {
12937      findConstantAndWatchExpressions(property.value, $filter);
12938      allConstants = allConstants && property.value.constant;
12939      if (!property.value.constant) {
12940        argsToWatch.push.apply(argsToWatch, property.value.toWatch);
12941      }
12942    });
12943    ast.constant = allConstants;
12944    ast.toWatch = argsToWatch;
12945    break;
12946  case AST.ThisExpression:
12947    ast.constant = false;
12948    ast.toWatch = [];
12949    break;
12950  }
12951}
12952
12953function getInputs(body) {
12954  if (body.length != 1) return;
12955  var lastExpression = body[0].expression;
12956  var candidate = lastExpression.toWatch;
12957  if (candidate.length !== 1) return candidate;
12958  return candidate[0] !== lastExpression ? candidate : undefined;
12959}
12960
12961function isAssignable(ast) {
12962  return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
12963}
12964
12965function assignableAST(ast) {
12966  if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
12967    return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
12968  }
12969}
12970
12971function isLiteral(ast) {
12972  return ast.body.length === 0 ||
12973      ast.body.length === 1 && (
12974      ast.body[0].expression.type === AST.Literal ||
12975      ast.body[0].expression.type === AST.ArrayExpression ||
12976      ast.body[0].expression.type === AST.ObjectExpression);
12977}
12978
12979function isConstant(ast) {
12980  return ast.constant;
12981}
12982
12983function ASTCompiler(astBuilder, $filter) {
12984  this.astBuilder = astBuilder;
12985  this.$filter = $filter;
12986}
12987
12988ASTCompiler.prototype = {
12989  compile: function(expression, expensiveChecks) {
12990    var self = this;
12991    var ast = this.astBuilder.ast(expression);
12992    this.state = {
12993      nextId: 0,
12994      filters: {},
12995      expensiveChecks: expensiveChecks,
12996      fn: {vars: [], body: [], own: {}},
12997      assign: {vars: [], body: [], own: {}},
12998      inputs: []
12999    };
13000    findConstantAndWatchExpressions(ast, self.$filter);
13001    var extra = '';
13002    var assignable;
13003    this.stage = 'assign';
13004    if ((assignable = assignableAST(ast))) {
13005      this.state.computing = 'assign';
13006      var result = this.nextId();
13007      this.recurse(assignable, result);
13008      extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
13009    }
13010    var toWatch = getInputs(ast.body);
13011    self.stage = 'inputs';
13012    forEach(toWatch, function(watch, key) {
13013      var fnKey = 'fn' + key;
13014      self.state[fnKey] = {vars: [], body: [], own: {}};
13015      self.state.computing = fnKey;
13016      var intoId = self.nextId();
13017      self.recurse(watch, intoId);
13018      self.return_(intoId);
13019      self.state.inputs.push(fnKey);
13020      watch.watchId = key;
13021    });
13022    this.state.computing = 'fn';
13023    this.stage = 'main';
13024    this.recurse(ast);
13025    var fnString =
13026      // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
13027      // This is a workaround for this until we do a better job at only removing the prefix only when we should.
13028      '"' + this.USE + ' ' + this.STRICT + '";\n' +
13029      this.filterPrefix() +
13030      'var fn=' + this.generateFunction('fn', 's,l,a,i') +
13031      extra +
13032      this.watchFns() +
13033      'return fn;';
13034
13035    /* jshint -W054 */
13036    var fn = (new Function('$filter',
13037        'ensureSafeMemberName',
13038        'ensureSafeObject',
13039        'ensureSafeFunction',
13040        'ifDefined',
13041        'plus',
13042        'text',
13043        fnString))(
13044          this.$filter,
13045          ensureSafeMemberName,
13046          ensureSafeObject,
13047          ensureSafeFunction,
13048          ifDefined,
13049          plusFn,
13050          expression);
13051    /* jshint +W054 */
13052    this.state = this.stage = undefined;
13053    fn.literal = isLiteral(ast);
13054    fn.constant = isConstant(ast);
13055    return fn;
13056  },
13057
13058  USE: 'use',
13059
13060  STRICT: 'strict',
13061
13062  watchFns: function() {
13063    var result = [];
13064    var fns = this.state.inputs;
13065    var self = this;
13066    forEach(fns, function(name) {
13067      result.push('var ' + name + '=' + self.generateFunction(name, 's'));
13068    });
13069    if (fns.length) {
13070      result.push('fn.inputs=[' + fns.join(',') + '];');
13071    }
13072    return result.join('');
13073  },
13074
13075  generateFunction: function(name, params) {
13076    return 'function(' + params + '){' +
13077        this.varsPrefix(name) +
13078        this.body(name) +
13079        '};';
13080  },
13081
13082  filterPrefix: function() {
13083    var parts = [];
13084    var self = this;
13085    forEach(this.state.filters, function(id, filter) {
13086      parts.push(id + '=$filter(' + self.escape(filter) + ')');
13087    });
13088    if (parts.length) return 'var ' + parts.join(',') + ';';
13089    return '';
13090  },
13091
13092  varsPrefix: function(section) {
13093    return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
13094  },
13095
13096  body: function(section) {
13097    return this.state[section].body.join('');
13098  },
13099
13100  recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13101    var left, right, self = this, args, expression;
13102    recursionFn = recursionFn || noop;
13103    if (!skipWatchIdCheck && isDefined(ast.watchId)) {
13104      intoId = intoId || this.nextId();
13105      this.if_('i',
13106        this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
13107        this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
13108      );
13109      return;
13110    }
13111    switch (ast.type) {
13112    case AST.Program:
13113      forEach(ast.body, function(expression, pos) {
13114        self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
13115        if (pos !== ast.body.length - 1) {
13116          self.current().body.push(right, ';');
13117        } else {
13118          self.return_(right);
13119        }
13120      });
13121      break;
13122    case AST.Literal:
13123      expression = this.escape(ast.value);
13124      this.assign(intoId, expression);
13125      recursionFn(expression);
13126      break;
13127    case AST.UnaryExpression:
13128      this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
13129      expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
13130      this.assign(intoId, expression);
13131      recursionFn(expression);
13132      break;
13133    case AST.BinaryExpression:
13134      this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
13135      this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
13136      if (ast.operator === '+') {
13137        expression = this.plus(left, right);
13138      } else if (ast.operator === '-') {
13139        expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
13140      } else {
13141        expression = '(' + left + ')' + ast.operator + '(' + right + ')';
13142      }
13143      this.assign(intoId, expression);
13144      recursionFn(expression);
13145      break;
13146    case AST.LogicalExpression:
13147      intoId = intoId || this.nextId();
13148      self.recurse(ast.left, intoId);
13149      self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
13150      recursionFn(intoId);
13151      break;
13152    case AST.ConditionalExpression:
13153      intoId = intoId || this.nextId();
13154      self.recurse(ast.test, intoId);
13155      self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
13156      recursionFn(intoId);
13157      break;
13158    case AST.Identifier:
13159      intoId = intoId || this.nextId();
13160      if (nameId) {
13161        nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
13162        nameId.computed = false;
13163        nameId.name = ast.name;
13164      }
13165      ensureSafeMemberName(ast.name);
13166      self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
13167        function() {
13168          self.if_(self.stage === 'inputs' || 's', function() {
13169            if (create && create !== 1) {
13170              self.if_(
13171                self.not(self.nonComputedMember('s', ast.name)),
13172                self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
13173            }
13174            self.assign(intoId, self.nonComputedMember('s', ast.name));
13175          });
13176        }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
13177        );
13178      if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
13179        self.addEnsureSafeObject(intoId);
13180      }
13181      recursionFn(intoId);
13182      break;
13183    case AST.MemberExpression:
13184      left = nameId && (nameId.context = this.nextId()) || this.nextId();
13185      intoId = intoId || this.nextId();
13186      self.recurse(ast.object, left, undefined, function() {
13187        self.if_(self.notNull(left), function() {
13188          if (ast.computed) {
13189            right = self.nextId();
13190            self.recurse(ast.property, right);
13191            self.addEnsureSafeMemberName(right);
13192            if (create && create !== 1) {
13193              self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
13194            }
13195            expression = self.ensureSafeObject(self.computedMember(left, right));
13196            self.assign(intoId, expression);
13197            if (nameId) {
13198              nameId.computed = true;
13199              nameId.name = right;
13200            }
13201          } else {
13202            ensureSafeMemberName(ast.property.name);
13203            if (create && create !== 1) {
13204              self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
13205            }
13206            expression = self.nonComputedMember(left, ast.property.name);
13207            if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
13208              expression = self.ensureSafeObject(expression);
13209            }
13210            self.assign(intoId, expression);
13211            if (nameId) {
13212              nameId.computed = false;
13213              nameId.name = ast.property.name;
13214            }
13215          }
13216          recursionFn(intoId);
13217        });
13218      }, !!create);
13219      break;
13220    case AST.CallExpression:
13221      intoId = intoId || this.nextId();
13222      if (ast.filter) {
13223        right = self.filter(ast.callee.name);
13224        args = [];
13225        forEach(ast.arguments, function(expr) {
13226          var argument = self.nextId();
13227          self.recurse(expr, argument);
13228          args.push(argument);
13229        });
13230        expression = right + '(' + args.join(',') + ')';
13231        self.assign(intoId, expression);
13232        recursionFn(intoId);
13233      } else {
13234        right = self.nextId();
13235        left = {};
13236        args = [];
13237        self.recurse(ast.callee, right, left, function() {
13238          self.if_(self.notNull(right), function() {
13239            self.addEnsureSafeFunction(right);
13240            forEach(ast.arguments, function(expr) {
13241              self.recurse(expr, self.nextId(), undefined, function(argument) {
13242                args.push(self.ensureSafeObject(argument));
13243              });
13244            });
13245            if (left.name) {
13246              if (!self.state.expensiveChecks) {
13247                self.addEnsureSafeObject(left.context);
13248              }
13249              expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
13250            } else {
13251              expression = right + '(' + args.join(',') + ')';
13252            }
13253            expression = self.ensureSafeObject(expression);
13254            self.assign(intoId, expression);
13255            recursionFn(intoId);
13256          });
13257        });
13258      }
13259      break;
13260    case AST.AssignmentExpression:
13261      right = this.nextId();
13262      left = {};
13263      if (!isAssignable(ast.left)) {
13264        throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
13265      }
13266      this.recurse(ast.left, undefined, left, function() {
13267        self.if_(self.notNull(left.context), function() {
13268          self.recurse(ast.right, right);
13269          self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
13270          expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
13271          self.assign(intoId, expression);
13272          recursionFn(intoId || expression);
13273        });
13274      }, 1);
13275      break;
13276    case AST.ArrayExpression:
13277      args = [];
13278      forEach(ast.elements, function(expr) {
13279        self.recurse(expr, self.nextId(), undefined, function(argument) {
13280          args.push(argument);
13281        });
13282      });
13283      expression = '[' + args.join(',') + ']';
13284      this.assign(intoId, expression);
13285      recursionFn(expression);
13286      break;
13287    case AST.ObjectExpression:
13288      args = [];
13289      forEach(ast.properties, function(property) {
13290        self.recurse(property.value, self.nextId(), undefined, function(expr) {
13291          args.push(self.escape(
13292              property.key.type === AST.Identifier ? property.key.name :
13293                ('' + property.key.value)) +
13294              ':' + expr);
13295        });
13296      });
13297      expression = '{' + args.join(',') + '}';
13298      this.assign(intoId, expression);
13299      recursionFn(expression);
13300      break;
13301    case AST.ThisExpression:
13302      this.assign(intoId, 's');
13303      recursionFn('s');
13304      break;
13305    case AST.NGValueParameter:
13306      this.assign(intoId, 'v');
13307      recursionFn('v');
13308      break;
13309    }
13310  },
13311
13312  getHasOwnProperty: function(element, property) {
13313    var key = element + '.' + property;
13314    var own = this.current().own;
13315    if (!own.hasOwnProperty(key)) {
13316      own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
13317    }
13318    return own[key];
13319  },
13320
13321  assign: function(id, value) {
13322    if (!id) return;
13323    this.current().body.push(id, '=', value, ';');
13324    return id;
13325  },
13326
13327  filter: function(filterName) {
13328    if (!this.state.filters.hasOwnProperty(filterName)) {
13329      this.state.filters[filterName] = this.nextId(true);
13330    }
13331    return this.state.filters[filterName];
13332  },
13333
13334  ifDefined: function(id, defaultValue) {
13335    return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
13336  },
13337
13338  plus: function(left, right) {
13339    return 'plus(' + left + ',' + right + ')';
13340  },
13341
13342  return_: function(id) {
13343    this.current().body.push('return ', id, ';');
13344  },
13345
13346  if_: function(test, alternate, consequent) {
13347    if (test === true) {
13348      alternate();
13349    } else {
13350      var body = this.current().body;
13351      body.push('if(', test, '){');
13352      alternate();
13353      body.push('}');
13354      if (consequent) {
13355        body.push('else{');
13356        consequent();
13357        body.push('}');
13358      }
13359    }
13360  },
13361
13362  not: function(expression) {
13363    return '!(' + expression + ')';
13364  },
13365
13366  notNull: function(expression) {
13367    return expression + '!=null';
13368  },
13369
13370  nonComputedMember: function(left, right) {
13371    return left + '.' + right;
13372  },
13373
13374  computedMember: function(left, right) {
13375    return left + '[' + right + ']';
13376  },
13377
13378  member: function(left, right, computed) {
13379    if (computed) return this.computedMember(left, right);
13380    return this.nonComputedMember(left, right);
13381  },
13382
13383  addEnsureSafeObject: function(item) {
13384    this.current().body.push(this.ensureSafeObject(item), ';');
13385  },
13386
13387  addEnsureSafeMemberName: function(item) {
13388    this.current().body.push(this.ensureSafeMemberName(item), ';');
13389  },
13390
13391  addEnsureSafeFunction: function(item) {
13392    this.current().body.push(this.ensureSafeFunction(item), ';');
13393  },
13394
13395  ensureSafeObject: function(item) {
13396    return 'ensureSafeObject(' + item + ',text)';
13397  },
13398
13399  ensureSafeMemberName: function(item) {
13400    return 'ensureSafeMemberName(' + item + ',text)';
13401  },
13402
13403  ensureSafeFunction: function(item) {
13404    return 'ensureSafeFunction(' + item + ',text)';
13405  },
13406
13407  lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
13408    var self = this;
13409    return function() {
13410      self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
13411    };
13412  },
13413
13414  lazyAssign: function(id, value) {
13415    var self = this;
13416    return function() {
13417      self.assign(id, value);
13418    };
13419  },
13420
13421  stringEscapeRegex: /[^ a-zA-Z0-9]/g,
13422
13423  stringEscapeFn: function(c) {
13424    return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
13425  },
13426
13427  escape: function(value) {
13428    if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
13429    if (isNumber(value)) return value.toString();
13430    if (value === true) return 'true';
13431    if (value === false) return 'false';
13432    if (value === null) return 'null';
13433    if (typeof value === 'undefined') return 'undefined';
13434
13435    throw $parseMinErr('esc', 'IMPOSSIBLE');
13436  },
13437
13438  nextId: function(skip, init) {
13439    var id = 'v' + (this.state.nextId++);
13440    if (!skip) {
13441      this.current().vars.push(id + (init ? '=' + init : ''));
13442    }
13443    return id;
13444  },
13445
13446  current: function() {
13447    return this.state[this.state.computing];
13448  }
13449};
13450
13451
13452function ASTInterpreter(astBuilder, $filter) {
13453  this.astBuilder = astBuilder;
13454  this.$filter = $filter;
13455}
13456
13457ASTInterpreter.prototype = {
13458  compile: function(expression, expensiveChecks) {
13459    var self = this;
13460    var ast = this.astBuilder.ast(expression);
13461    this.expression = expression;
13462    this.expensiveChecks = expensiveChecks;
13463    findConstantAndWatchExpressions(ast, self.$filter);
13464    var assignable;
13465    var assign;
13466    if ((assignable = assignableAST(ast))) {
13467      assign = this.recurse(assignable);
13468    }
13469    var toWatch = getInputs(ast.body);
13470    var inputs;
13471    if (toWatch) {
13472      inputs = [];
13473      forEach(toWatch, function(watch, key) {
13474        var input = self.recurse(watch);
13475        watch.input = input;
13476        inputs.push(input);
13477        watch.watchId = key;
13478      });
13479    }
13480    var expressions = [];
13481    forEach(ast.body, function(expression) {
13482      expressions.push(self.recurse(expression.expression));
13483    });
13484    var fn = ast.body.length === 0 ? function() {} :
13485             ast.body.length === 1 ? expressions[0] :
13486             function(scope, locals) {
13487               var lastValue;
13488               forEach(expressions, function(exp) {
13489                 lastValue = exp(scope, locals);
13490               });
13491               return lastValue;
13492             };
13493    if (assign) {
13494      fn.assign = function(scope, value, locals) {
13495        return assign(scope, locals, value);
13496      };
13497    }
13498    if (inputs) {
13499      fn.inputs = inputs;
13500    }
13501    fn.literal = isLiteral(ast);
13502    fn.constant = isConstant(ast);
13503    return fn;
13504  },
13505
13506  recurse: function(ast, context, create) {
13507    var left, right, self = this, args, expression;
13508    if (ast.input) {
13509      return this.inputs(ast.input, ast.watchId);
13510    }
13511    switch (ast.type) {
13512    case AST.Literal:
13513      return this.value(ast.value, context);
13514    case AST.UnaryExpression:
13515      right = this.recurse(ast.argument);
13516      return this['unary' + ast.operator](right, context);
13517    case AST.BinaryExpression:
13518      left = this.recurse(ast.left);
13519      right = this.recurse(ast.right);
13520      return this['binary' + ast.operator](left, right, context);
13521    case AST.LogicalExpression:
13522      left = this.recurse(ast.left);
13523      right = this.recurse(ast.right);
13524      return this['binary' + ast.operator](left, right, context);
13525    case AST.ConditionalExpression:
13526      return this['ternary?:'](
13527        this.recurse(ast.test),
13528        this.recurse(ast.alternate),
13529        this.recurse(ast.consequent),
13530        context
13531      );
13532    case AST.Identifier:
13533      ensureSafeMemberName(ast.name, self.expression);
13534      return self.identifier(ast.name,
13535                             self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
13536                             context, create, self.expression);
13537    case AST.MemberExpression:
13538      left = this.recurse(ast.object, false, !!create);
13539      if (!ast.computed) {
13540        ensureSafeMemberName(ast.property.name, self.expression);
13541        right = ast.property.name;
13542      }
13543      if (ast.computed) right = this.recurse(ast.property);
13544      return ast.computed ?
13545        this.computedMember(left, right, context, create, self.expression) :
13546        this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
13547    case AST.CallExpression:
13548      args = [];
13549      forEach(ast.arguments, function(expr) {
13550        args.push(self.recurse(expr));
13551      });
13552      if (ast.filter) right = this.$filter(ast.callee.name);
13553      if (!ast.filter) right = this.recurse(ast.callee, true);
13554      return ast.filter ?
13555        function(scope, locals, assign, inputs) {
13556          var values = [];
13557          for (var i = 0; i < args.length; ++i) {
13558            values.push(args[i](scope, locals, assign, inputs));
13559          }
13560          var value = right.apply(undefined, values, inputs);
13561          return context ? {context: undefined, name: undefined, value: value} : value;
13562        } :
13563        function(scope, locals, assign, inputs) {
13564          var rhs = right(scope, locals, assign, inputs);
13565          var value;
13566          if (rhs.value != null) {
13567            ensureSafeObject(rhs.context, self.expression);
13568            ensureSafeFunction(rhs.value, self.expression);
13569            var values = [];
13570            for (var i = 0; i < args.length; ++i) {
13571              values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
13572            }
13573            value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
13574          }
13575          return context ? {value: value} : value;
13576        };
13577    case AST.AssignmentExpression:
13578      left = this.recurse(ast.left, true, 1);
13579      right = this.recurse(ast.right);
13580      return function(scope, locals, assign, inputs) {
13581        var lhs = left(scope, locals, assign, inputs);
13582        var rhs = right(scope, locals, assign, inputs);
13583        ensureSafeObject(lhs.value, self.expression);
13584        lhs.context[lhs.name] = rhs;
13585        return context ? {value: rhs} : rhs;
13586      };
13587    case AST.ArrayExpression:
13588      args = [];
13589      forEach(ast.elements, function(expr) {
13590        args.push(self.recurse(expr));
13591      });
13592      return function(scope, locals, assign, inputs) {
13593        var value = [];
13594        for (var i = 0; i < args.length; ++i) {
13595          value.push(args[i](scope, locals, assign, inputs));
13596        }
13597        return context ? {value: value} : value;
13598      };
13599    case AST.ObjectExpression:
13600      args = [];
13601      forEach(ast.properties, function(property) {
13602        args.push({key: property.key.type === AST.Identifier ?
13603                        property.key.name :
13604                        ('' + property.key.value),
13605                   value: self.recurse(property.value)
13606        });
13607      });
13608      return function(scope, locals, assign, inputs) {
13609        var value = {};
13610        for (var i = 0; i < args.length; ++i) {
13611          value[args[i].key] = args[i].value(scope, locals, assign, inputs);
13612        }
13613        return context ? {value: value} : value;
13614      };
13615    case AST.ThisExpression:
13616      return function(scope) {
13617        return context ? {value: scope} : scope;
13618      };
13619    case AST.NGValueParameter:
13620      return function(scope, locals, assign, inputs) {
13621        return context ? {value: assign} : assign;
13622      };
13623    }
13624  },
13625
13626  'unary+': function(argument, context) {
13627    return function(scope, locals, assign, inputs) {
13628      var arg = argument(scope, locals, assign, inputs);
13629      if (isDefined(arg)) {
13630        arg = +arg;
13631      } else {
13632        arg = 0;
13633      }
13634      return context ? {value: arg} : arg;
13635    };
13636  },
13637  'unary-': function(argument, context) {
13638    return function(scope, locals, assign, inputs) {
13639      var arg = argument(scope, locals, assign, inputs);
13640      if (isDefined(arg)) {
13641        arg = -arg;
13642      } else {
13643        arg = 0;
13644      }
13645      return context ? {value: arg} : arg;
13646    };
13647  },
13648  'unary!': function(argument, context) {
13649    return function(scope, locals, assign, inputs) {
13650      var arg = !argument(scope, locals, assign, inputs);
13651      return context ? {value: arg} : arg;
13652    };
13653  },
13654  'binary+': function(left, right, context) {
13655    return function(scope, locals, assign, inputs) {
13656      var lhs = left(scope, locals, assign, inputs);
13657      var rhs = right(scope, locals, assign, inputs);
13658      var arg = plusFn(lhs, rhs);
13659      return context ? {value: arg} : arg;
13660    };
13661  },
13662  'binary-': function(left, right, context) {
13663    return function(scope, locals, assign, inputs) {
13664      var lhs = left(scope, locals, assign, inputs);
13665      var rhs = right(scope, locals, assign, inputs);
13666      var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
13667      return context ? {value: arg} : arg;
13668    };
13669  },
13670  'binary*': function(left, right, context) {
13671    return function(scope, locals, assign, inputs) {
13672      var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
13673      return context ? {value: arg} : arg;
13674    };
13675  },
13676  'binary/': function(left, right, context) {
13677    return function(scope, locals, assign, inputs) {
13678      var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
13679      return context ? {value: arg} : arg;
13680    };
13681  },
13682  'binary%': function(left, right, context) {
13683    return function(scope, locals, assign, inputs) {
13684      var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
13685      return context ? {value: arg} : arg;
13686    };
13687  },
13688  'binary===': function(left, right, context) {
13689    return function(scope, locals, assign, inputs) {
13690      var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
13691      return context ? {value: arg} : arg;
13692    };
13693  },
13694  'binary!==': function(left, right, context) {
13695    return function(scope, locals, assign, inputs) {
13696      var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
13697      return context ? {value: arg} : arg;
13698    };
13699  },
13700  'binary==': function(left, right, context) {
13701    return function(scope, locals, assign, inputs) {
13702      var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
13703      return context ? {value: arg} : arg;
13704    };
13705  },
13706  'binary!=': function(left, right, context) {
13707    return function(scope, locals, assign, inputs) {
13708      var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
13709      return context ? {value: arg} : arg;
13710    };
13711  },
13712  'binary<': function(left, right, context) {
13713    return function(scope, locals, assign, inputs) {
13714      var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
13715      return context ? {value: arg} : arg;
13716    };
13717  },
13718  'binary>': function(left, right, context) {
13719    return function(scope, locals, assign, inputs) {
13720      var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
13721      return context ? {value: arg} : arg;
13722    };
13723  },
13724  'binary<=': function(left, right, context) {
13725    return function(scope, locals, assign, inputs) {
13726      var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
13727      return context ? {value: arg} : arg;
13728    };
13729  },
13730  'binary>=': function(left, right, context) {
13731    return function(scope, locals, assign, inputs) {
13732      var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
13733      return context ? {value: arg} : arg;
13734    };
13735  },
13736  'binary&&': function(left, right, context) {
13737    return function(scope, locals, assign, inputs) {
13738      var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
13739      return context ? {value: arg} : arg;
13740    };
13741  },
13742  'binary||': function(left, right, context) {
13743    return function(scope, locals, assign, inputs) {
13744      var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
13745      return context ? {value: arg} : arg;
13746    };
13747  },
13748  'ternary?:': function(test, alternate, consequent, context) {
13749    return function(scope, locals, assign, inputs) {
13750      var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
13751      return context ? {value: arg} : arg;
13752    };
13753  },
13754  value: function(value, context) {
13755    return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
13756  },
13757  identifier: function(name, expensiveChecks, context, create, expression) {
13758    return function(scope, locals, assign, inputs) {
13759      var base = locals && (name in locals) ? locals : scope;
13760      if (create && create !== 1 && base && !(base[name])) {
13761        base[name] = {};
13762      }
13763      var value = base ? base[name] : undefined;
13764      if (expensiveChecks) {
13765        ensureSafeObject(value, expression);
13766      }
13767      if (context) {
13768        return {context: base, name: name, value: value};
13769      } else {
13770        return value;
13771      }
13772    };
13773  },
13774  computedMember: function(left, right, context, create, expression) {
13775    return function(scope, locals, assign, inputs) {
13776      var lhs = left(scope, locals, assign, inputs);
13777      var rhs;
13778      var value;
13779      if (lhs != null) {
13780        rhs = right(scope, locals, assign, inputs);
13781        ensureSafeMemberName(rhs, expression);
13782        if (create && create !== 1 && lhs && !(lhs[rhs])) {
13783          lhs[rhs] = {};
13784        }
13785        value = lhs[rhs];
13786        ensureSafeObject(value, expression);
13787      }
13788      if (context) {
13789        return {context: lhs, name: rhs, value: value};
13790      } else {
13791        return value;
13792      }
13793    };
13794  },
13795  nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
13796    return function(scope, locals, assign, inputs) {
13797      var lhs = left(scope, locals, assign, inputs);
13798      if (create && create !== 1 && lhs && !(lhs[right])) {
13799        lhs[right] = {};
13800      }
13801      var value = lhs != null ? lhs[right] : undefined;
13802      if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
13803        ensureSafeObject(value, expression);
13804      }
13805      if (context) {
13806        return {context: lhs, name: right, value: value};
13807      } else {
13808        return value;
13809      }
13810    };
13811  },
13812  inputs: function(input, watchId) {
13813    return function(scope, value, locals, inputs) {
13814      if (inputs) return inputs[watchId];
13815      return input(scope, value, locals);
13816    };
13817  }
13818};
13819
13820/**
13821 * @constructor
13822 */
13823var Parser = function(lexer, $filter, options) {
13824  this.lexer = lexer;
13825  this.$filter = $filter;
13826  this.options = options;
13827  this.ast = new AST(this.lexer);
13828  this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
13829                                   new ASTCompiler(this.ast, $filter);
13830};
13831
13832Parser.prototype = {
13833  constructor: Parser,
13834
13835  parse: function(text) {
13836    return this.astCompiler.compile(text, this.options.expensiveChecks);
13837  }
13838};
13839
13840//////////////////////////////////////////////////
13841// Parser helper functions
13842//////////////////////////////////////////////////
13843
13844function setter(obj, path, setValue, fullExp) {
13845  ensureSafeObject(obj, fullExp);
13846
13847  var element = path.split('.'), key;
13848  for (var i = 0; element.length > 1; i++) {
13849    key = ensureSafeMemberName(element.shift(), fullExp);
13850    var propertyObj = ensureSafeObject(obj[key], fullExp);
13851    if (!propertyObj) {
13852      propertyObj = {};
13853      obj[key] = propertyObj;
13854    }
13855    obj = propertyObj;
13856  }
13857  key = ensureSafeMemberName(element.shift(), fullExp);
13858  ensureSafeObject(obj[key], fullExp);
13859  obj[key] = setValue;
13860  return setValue;
13861}
13862
13863var getterFnCacheDefault = createMap();
13864var getterFnCacheExpensive = createMap();
13865
13866function isPossiblyDangerousMemberName(name) {
13867  return name == 'constructor';
13868}
13869
13870var objectValueOf = Object.prototype.valueOf;
13871
13872function getValueOf(value) {
13873  return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
13874}
13875
13876///////////////////////////////////
13877
13878/**
13879 * @ngdoc service
13880 * @name $parse
13881 * @kind function
13882 *
13883 * @description
13884 *
13885 * Converts Angular {@link guide/expression expression} into a function.
13886 *
13887 * ```js
13888 *   var getter = $parse('user.name');
13889 *   var setter = getter.assign;
13890 *   var context = {user:{name:'angular'}};
13891 *   var locals = {user:{name:'local'}};
13892 *
13893 *   expect(getter(context)).toEqual('angular');
13894 *   setter(context, 'newValue');
13895 *   expect(context.user.name).toEqual('newValue');
13896 *   expect(getter(context, locals)).toEqual('local');
13897 * ```
13898 *
13899 *
13900 * @param {string} expression String expression to compile.
13901 * @returns {function(context, locals)} a function which represents the compiled expression:
13902 *
13903 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13904 *      are evaluated against (typically a scope object).
13905 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13906 *      `context`.
13907 *
13908 *    The returned function also has the following properties:
13909 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
13910 *        literal.
13911 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
13912 *        constant literals.
13913 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
13914 *        set to a function to change its value on the given context.
13915 *
13916 */
13917
13918
13919/**
13920 * @ngdoc provider
13921 * @name $parseProvider
13922 *
13923 * @description
13924 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
13925 *  service.
13926 */
13927function $ParseProvider() {
13928  var cacheDefault = createMap();
13929  var cacheExpensive = createMap();
13930
13931  this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
13932    var $parseOptions = {
13933          csp: $sniffer.csp,
13934          expensiveChecks: false
13935        },
13936        $parseOptionsExpensive = {
13937          csp: $sniffer.csp,
13938          expensiveChecks: true
13939        };
13940
13941    return function $parse(exp, interceptorFn, expensiveChecks) {
13942      var parsedExpression, oneTime, cacheKey;
13943
13944      switch (typeof exp) {
13945        case 'string':
13946          exp = exp.trim();
13947          cacheKey = exp;
13948
13949          var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
13950          parsedExpression = cache[cacheKey];
13951
13952          if (!parsedExpression) {
13953            if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
13954              oneTime = true;
13955              exp = exp.substring(2);
13956            }
13957            var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
13958            var lexer = new Lexer(parseOptions);
13959            var parser = new Parser(lexer, $filter, parseOptions);
13960            parsedExpression = parser.parse(exp);
13961            if (parsedExpression.constant) {
13962              parsedExpression.$$watchDelegate = constantWatchDelegate;
13963            } else if (oneTime) {
13964              parsedExpression.$$watchDelegate = parsedExpression.literal ?
13965                  oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
13966            } else if (parsedExpression.inputs) {
13967              parsedExpression.$$watchDelegate = inputsWatchDelegate;
13968            }
13969            cache[cacheKey] = parsedExpression;
13970          }
13971          return addInterceptor(parsedExpression, interceptorFn);
13972
13973        case 'function':
13974          return addInterceptor(exp, interceptorFn);
13975
13976        default:
13977          return noop;
13978      }
13979    };
13980
13981    function expressionInputDirtyCheck(newValue, oldValueOfValue) {
13982
13983      if (newValue == null || oldValueOfValue == null) { // null/undefined
13984        return newValue === oldValueOfValue;
13985      }
13986
13987      if (typeof newValue === 'object') {
13988
13989        // attempt to convert the value to a primitive type
13990        // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
13991        //             be cheaply dirty-checked
13992        newValue = getValueOf(newValue);
13993
13994        if (typeof newValue === 'object') {
13995          // objects/arrays are not supported - deep-watching them would be too expensive
13996          return false;
13997        }
13998
13999        // fall-through to the primitive equality check
14000      }
14001
14002      //Primitive or NaN
14003      return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
14004    }
14005
14006    function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
14007      var inputExpressions = parsedExpression.inputs;
14008      var lastResult;
14009
14010      if (inputExpressions.length === 1) {
14011        var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
14012        inputExpressions = inputExpressions[0];
14013        return scope.$watch(function expressionInputWatch(scope) {
14014          var newInputValue = inputExpressions(scope);
14015          if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
14016            lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
14017            oldInputValueOf = newInputValue && getValueOf(newInputValue);
14018          }
14019          return lastResult;
14020        }, listener, objectEquality, prettyPrintExpression);
14021      }
14022
14023      var oldInputValueOfValues = [];
14024      var oldInputValues = [];
14025      for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14026        oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
14027        oldInputValues[i] = null;
14028      }
14029
14030      return scope.$watch(function expressionInputsWatch(scope) {
14031        var changed = false;
14032
14033        for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
14034          var newInputValue = inputExpressions[i](scope);
14035          if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
14036            oldInputValues[i] = newInputValue;
14037            oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
14038          }
14039        }
14040
14041        if (changed) {
14042          lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
14043        }
14044
14045        return lastResult;
14046      }, listener, objectEquality, prettyPrintExpression);
14047    }
14048
14049    function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14050      var unwatch, lastValue;
14051      return unwatch = scope.$watch(function oneTimeWatch(scope) {
14052        return parsedExpression(scope);
14053      }, function oneTimeListener(value, old, scope) {
14054        lastValue = value;
14055        if (isFunction(listener)) {
14056          listener.apply(this, arguments);
14057        }
14058        if (isDefined(value)) {
14059          scope.$$postDigest(function() {
14060            if (isDefined(lastValue)) {
14061              unwatch();
14062            }
14063          });
14064        }
14065      }, objectEquality);
14066    }
14067
14068    function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14069      var unwatch, lastValue;
14070      return unwatch = scope.$watch(function oneTimeWatch(scope) {
14071        return parsedExpression(scope);
14072      }, function oneTimeListener(value, old, scope) {
14073        lastValue = value;
14074        if (isFunction(listener)) {
14075          listener.call(this, value, old, scope);
14076        }
14077        if (isAllDefined(value)) {
14078          scope.$$postDigest(function() {
14079            if (isAllDefined(lastValue)) unwatch();
14080          });
14081        }
14082      }, objectEquality);
14083
14084      function isAllDefined(value) {
14085        var allDefined = true;
14086        forEach(value, function(val) {
14087          if (!isDefined(val)) allDefined = false;
14088        });
14089        return allDefined;
14090      }
14091    }
14092
14093    function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
14094      var unwatch;
14095      return unwatch = scope.$watch(function constantWatch(scope) {
14096        return parsedExpression(scope);
14097      }, function constantListener(value, old, scope) {
14098        if (isFunction(listener)) {
14099          listener.apply(this, arguments);
14100        }
14101        unwatch();
14102      }, objectEquality);
14103    }
14104
14105    function addInterceptor(parsedExpression, interceptorFn) {
14106      if (!interceptorFn) return parsedExpression;
14107      var watchDelegate = parsedExpression.$$watchDelegate;
14108
14109      var regularWatch =
14110          watchDelegate !== oneTimeLiteralWatchDelegate &&
14111          watchDelegate !== oneTimeWatchDelegate;
14112
14113      var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14114        var value = parsedExpression(scope, locals, assign, inputs);
14115        return interceptorFn(value, scope, locals);
14116      } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14117        var value = parsedExpression(scope, locals, assign, inputs);
14118        var result = interceptorFn(value, scope, locals);
14119        // we only return the interceptor's result if the
14120        // initial value is defined (for bind-once)
14121        return isDefined(value) ? result : value;
14122      };
14123
14124      // Propagate $$watchDelegates other then inputsWatchDelegate
14125      if (parsedExpression.$$watchDelegate &&
14126          parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
14127        fn.$$watchDelegate = parsedExpression.$$watchDelegate;
14128      } else if (!interceptorFn.$stateful) {
14129        // If there is an interceptor, but no watchDelegate then treat the interceptor like
14130        // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14131        fn.$$watchDelegate = inputsWatchDelegate;
14132        fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14133      }
14134
14135      return fn;
14136    }
14137  }];
14138}
14139
14140/**
14141 * @ngdoc service
14142 * @name $q
14143 * @requires $rootScope
14144 *
14145 * @description
14146 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
14147 * when they are done processing.
14148 *
14149 * This is an implementation of promises/deferred objects inspired by
14150 * [Kris Kowal's Q](https://github.com/kriskowal/q).
14151 *
14152 * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
14153 * implementations, and the other which resembles ES6 promises to some degree.
14154 *
14155 * # $q constructor
14156 *
14157 * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
14158 * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
14159 * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
14160 *
14161 * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
14162 * available yet.
14163 *
14164 * It can be used like so:
14165 *
14166 * ```js
14167 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14168 *   // are available in the current lexical scope (they could have been injected or passed in).
14169 *
14170 *   function asyncGreet(name) {
14171 *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
14172 *     return $q(function(resolve, reject) {
14173 *       setTimeout(function() {
14174 *         if (okToGreet(name)) {
14175 *           resolve('Hello, ' + name + '!');
14176 *         } else {
14177 *           reject('Greeting ' + name + ' is not allowed.');
14178 *         }
14179 *       }, 1000);
14180 *     });
14181 *   }
14182 *
14183 *   var promise = asyncGreet('Robin Hood');
14184 *   promise.then(function(greeting) {
14185 *     alert('Success: ' + greeting);
14186 *   }, function(reason) {
14187 *     alert('Failed: ' + reason);
14188 *   });
14189 * ```
14190 *
14191 * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14192 *
14193 * However, the more traditional CommonJS-style usage is still available, and documented below.
14194 *
14195 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
14196 * interface for interacting with an object that represents the result of an action that is
14197 * performed asynchronously, and may or may not be finished at any given point in time.
14198 *
14199 * From the perspective of dealing with error handling, deferred and promise APIs are to
14200 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
14201 *
14202 * ```js
14203 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
14204 *   // are available in the current lexical scope (they could have been injected or passed in).
14205 *
14206 *   function asyncGreet(name) {
14207 *     var deferred = $q.defer();
14208 *
14209 *     setTimeout(function() {
14210 *       deferred.notify('About to greet ' + name + '.');
14211 *
14212 *       if (okToGreet(name)) {
14213 *         deferred.resolve('Hello, ' + name + '!');
14214 *       } else {
14215 *         deferred.reject('Greeting ' + name + ' is not allowed.');
14216 *       }
14217 *     }, 1000);
14218 *
14219 *     return deferred.promise;
14220 *   }
14221 *
14222 *   var promise = asyncGreet('Robin Hood');
14223 *   promise.then(function(greeting) {
14224 *     alert('Success: ' + greeting);
14225 *   }, function(reason) {
14226 *     alert('Failed: ' + reason);
14227 *   }, function(update) {
14228 *     alert('Got notification: ' + update);
14229 *   });
14230 * ```
14231 *
14232 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
14233 * comes in the way of guarantees that promise and deferred APIs make, see
14234 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
14235 *
14236 * Additionally the promise api allows for composition that is very hard to do with the
14237 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
14238 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
14239 * section on serial or parallel joining of promises.
14240 *
14241 * # The Deferred API
14242 *
14243 * A new instance of deferred is constructed by calling `$q.defer()`.
14244 *
14245 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
14246 * that can be used for signaling the successful or unsuccessful completion, as well as the status
14247 * of the task.
14248 *
14249 * **Methods**
14250 *
14251 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
14252 *   constructed via `$q.reject`, the promise will be rejected instead.
14253 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
14254 *   resolving it with a rejection constructed via `$q.reject`.
14255 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
14256 *   multiple times before the promise is either resolved or rejected.
14257 *
14258 * **Properties**
14259 *
14260 * - promise – `{Promise}` – promise object associated with this deferred.
14261 *
14262 *
14263 * # The Promise API
14264 *
14265 * A new promise instance is created when a deferred instance is created and can be retrieved by
14266 * calling `deferred.promise`.
14267 *
14268 * The purpose of the promise object is to allow for interested parties to get access to the result
14269 * of the deferred task when it completes.
14270 *
14271 * **Methods**
14272 *
14273 * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
14274 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
14275 *   as soon as the result is available. The callbacks are called with a single argument: the result
14276 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
14277 *   provide a progress indication, before the promise is resolved or rejected.
14278 *
14279 *   This method *returns a new promise* which is resolved or rejected via the return value of the
14280 *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
14281 *   with the value which is resolved in that promise using
14282 *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
14283 *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
14284 *   resolved or rejected from the notifyCallback method.
14285 *
14286 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
14287 *
14288 * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
14289 *   but to do so without modifying the final value. This is useful to release resources or do some
14290 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
14291 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
14292 *   more information.
14293 *
14294 * # Chaining promises
14295 *
14296 * Because calling the `then` method of a promise returns a new derived promise, it is easily
14297 * possible to create a chain of promises:
14298 *
14299 * ```js
14300 *   promiseB = promiseA.then(function(result) {
14301 *     return result + 1;
14302 *   });
14303 *
14304 *   // promiseB will be resolved immediately after promiseA is resolved and its value
14305 *   // will be the result of promiseA incremented by 1
14306 * ```
14307 *
14308 * It is possible to create chains of any length and since a promise can be resolved with another
14309 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
14310 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
14311 * $http's response interceptors.
14312 *
14313 *
14314 * # Differences between Kris Kowal's Q and $q
14315 *
14316 *  There are two main differences:
14317 *
14318 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
14319 *   mechanism in angular, which means faster propagation of resolution or rejection into your
14320 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
14321 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
14322 *   all the important functionality needed for common async tasks.
14323 *
14324 *  # Testing
14325 *
14326 *  ```js
14327 *    it('should simulate promise', inject(function($q, $rootScope) {
14328 *      var deferred = $q.defer();
14329 *      var promise = deferred.promise;
14330 *      var resolvedValue;
14331 *
14332 *      promise.then(function(value) { resolvedValue = value; });
14333 *      expect(resolvedValue).toBeUndefined();
14334 *
14335 *      // Simulate resolving of promise
14336 *      deferred.resolve(123);
14337 *      // Note that the 'then' function does not get called synchronously.
14338 *      // This is because we want the promise API to always be async, whether or not
14339 *      // it got called synchronously or asynchronously.
14340 *      expect(resolvedValue).toBeUndefined();
14341 *
14342 *      // Propagate promise resolution to 'then' functions using $apply().
14343 *      $rootScope.$apply();
14344 *      expect(resolvedValue).toEqual(123);
14345 *    }));
14346 *  ```
14347 *
14348 * @param {function(function, function)} resolver Function which is responsible for resolving or
14349 *   rejecting the newly created promise. The first parameter is a function which resolves the
14350 *   promise, the second parameter is a function which rejects the promise.
14351 *
14352 * @returns {Promise} The newly created promise.
14353 */
14354function $QProvider() {
14355
14356  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
14357    return qFactory(function(callback) {
14358      $rootScope.$evalAsync(callback);
14359    }, $exceptionHandler);
14360  }];
14361}
14362
14363function $$QProvider() {
14364  this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
14365    return qFactory(function(callback) {
14366      $browser.defer(callback);
14367    }, $exceptionHandler);
14368  }];
14369}
14370
14371/**
14372 * Constructs a promise manager.
14373 *
14374 * @param {function(function)} nextTick Function for executing functions in the next turn.
14375 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
14376 *     debugging purposes.
14377 * @returns {object} Promise manager.
14378 */
14379function qFactory(nextTick, exceptionHandler) {
14380  var $qMinErr = minErr('$q', TypeError);
14381  function callOnce(self, resolveFn, rejectFn) {
14382    var called = false;
14383    function wrap(fn) {
14384      return function(value) {
14385        if (called) return;
14386        called = true;
14387        fn.call(self, value);
14388      };
14389    }
14390
14391    return [wrap(resolveFn), wrap(rejectFn)];
14392  }
14393
14394  /**
14395   * @ngdoc method
14396   * @name ng.$q#defer
14397   * @kind function
14398   *
14399   * @description
14400   * Creates a `Deferred` object which represents a task which will finish in the future.
14401   *
14402   * @returns {Deferred} Returns a new instance of deferred.
14403   */
14404  var defer = function() {
14405    return new Deferred();
14406  };
14407
14408  function Promise() {
14409    this.$$state = { status: 0 };
14410  }
14411
14412  Promise.prototype = {
14413    then: function(onFulfilled, onRejected, progressBack) {
14414      var result = new Deferred();
14415
14416      this.$$state.pending = this.$$state.pending || [];
14417      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
14418      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
14419
14420      return result.promise;
14421    },
14422
14423    "catch": function(callback) {
14424      return this.then(null, callback);
14425    },
14426
14427    "finally": function(callback, progressBack) {
14428      return this.then(function(value) {
14429        return handleCallback(value, true, callback);
14430      }, function(error) {
14431        return handleCallback(error, false, callback);
14432      }, progressBack);
14433    }
14434  };
14435
14436  //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
14437  function simpleBind(context, fn) {
14438    return function(value) {
14439      fn.call(context, value);
14440    };
14441  }
14442
14443  function processQueue(state) {
14444    var fn, deferred, pending;
14445
14446    pending = state.pending;
14447    state.processScheduled = false;
14448    state.pending = undefined;
14449    for (var i = 0, ii = pending.length; i < ii; ++i) {
14450      deferred = pending[i][0];
14451      fn = pending[i][state.status];
14452      try {
14453        if (isFunction(fn)) {
14454          deferred.resolve(fn(state.value));
14455        } else if (state.status === 1) {
14456          deferred.resolve(state.value);
14457        } else {
14458          deferred.reject(state.value);
14459        }
14460      } catch (e) {
14461        deferred.reject(e);
14462        exceptionHandler(e);
14463      }
14464    }
14465  }
14466
14467  function scheduleProcessQueue(state) {
14468    if (state.processScheduled || !state.pending) return;
14469    state.processScheduled = true;
14470    nextTick(function() { processQueue(state); });
14471  }
14472
14473  function Deferred() {
14474    this.promise = new Promise();
14475    //Necessary to support unbound execution :/
14476    this.resolve = simpleBind(this, this.resolve);
14477    this.reject = simpleBind(this, this.reject);
14478    this.notify = simpleBind(this, this.notify);
14479  }
14480
14481  Deferred.prototype = {
14482    resolve: function(val) {
14483      if (this.promise.$$state.status) return;
14484      if (val === this.promise) {
14485        this.$$reject($qMinErr(
14486          'qcycle',
14487          "Expected promise to be resolved with value other than 
14487itself '{0}'",
14488          val));
14489      } else {
14490        this.$$resolve(val);
14491      }
14492
14493    },
14494
14495    $$resolve: function(val) {
14496      var then, fns;
14497
14498      fns = callOnce(this, this.$$resolve, this.$$reject);
14499      try {
14500        if ((isObject(val) || isFunction(val))) then = val && val.then;
14501        if (isFunction(then)) {
14502          this.promise.$$state.status = -1;
14503          then.call(val, fns[0], fns[1], this.notify);
14504        } else {
14505          this.promise.$$state.value = val;
14506          this.promise.$$state.status = 1;
14507          scheduleProcessQueue(this.promise.$$state);
14508        }
14509      } catch (e) {
14510        fns[1](e);
14511        exceptionHandler(e);
14512      }
14513    },
14514
14515    reject: function(reason) {
14516      if (this.promise.$$state.status) return;
14517      this.$$reject(reason);
14518    },
14519
14520    $$reject: function(reason) {
14521      this.promise.$$state.value = reason;
14522      this.promise.$$state.status = 2;
14523      scheduleProcessQueue(this.promise.$$state);
14524    },
14525
14526    notify: function(progress) {
14527      var callbacks = this.promise.$$state.pending;
14528
14529      if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
14530        nextTick(function() {
14531          var callback, result;
14532          for (var i = 0, ii = callbacks.length; i < ii; i++) {
14533            result = callbacks[i][0];
14534            callback = callbacks[i][3];
14535            try {
14536              result.notify(isFunction(callback) ? callback(progress) : progress);
14537            } catch (e) {
14538              exceptionHandler(e);
14539            }
14540          }
14541        });
14542      }
14543    }
14544  };
14545
14546  /**
14547   * @ngdoc method
14548   * @name $q#reject
14549   * @kind function
14550   *
14551   * @description
14552   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
14553   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
14554   * a promise chain, you don't need to worry about it.
14555   *
14556   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
14557   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
14558   * a promise error callback and you want to forward the error to the promise derived from the
14559   * current promise, you have to "rethrow" the error by returning a rejection constructed via
14560   * `reject`.
14561   *
14562   * ```js
14563   *   promiseB = promiseA.then(function(result) {
14564   *     // success: do something and resolve promiseB
14565   *     //          with the old or a new result
14566   *     return result;
14567   *   }, function(reason) {
14568   *     // error: handle the error if possible and
14569   *     //        resolve promiseB with newPromiseOrValue,
14570   *     //        otherwise forward the rejection to promiseB
14571   *     if (canHandle(reason)) {
14572   *      // handle the error and recover
14573   *      return newPromiseOrValue;
14574   *     }
14575   *     return $q.reject(reason);
14576   *   });
14577   * ```
14578   *
14579   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
14580   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
14581   */
14582  var reject = function(reason) {
14583    var result = new Deferred();
14584    result.reject(reason);
14585    return result.promise;
14586  };
14587
14588  var makePromise = function makePromise(value, resolved) {
14589    var result = new Deferred();
14590    if (resolved) {
14591      result.resolve(value);
14592    } else {
14593      result.reject(value);
14594    }
14595    return result.promise;
14596  };
14597
14598  var handleCallback = function handleCallback(value, isResolved, callback) {
14599    var callbackOutput = null;
14600    try {
14601      if (isFunction(callback)) callbackOutput = callback();
14602    } catch (e) {
14603      return makePromise(e, false);
14604    }
14605    if (isPromiseLike(callbackOutput)) {
14606      return callbackOutput.then(function() {
14607        return makePromise(value, isResolved);
14608      }, function(error) {
14609        return makePromise(error, false);
14610      });
14611    } else {
14612      return makePromise(value, isResolved);
14613    }
14614  };
14615
14616  /**
14617   * @ngdoc method
14618   * @name $q#when
14619   * @kind function
14620   *
14621   * @description
14622   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
14623   * This is useful when you are dealing with an object that might or might not be a promise, or if
14624   * the promise comes from a source that can't be trusted.
14625   *
14626   * @param {*} value Value or a promise
14627   * @returns {Promise} Returns a promise of the passed value or promise
14628   */
14629
14630
14631  var when = function(value, callback, errback, progressBack) {
14632    var result = new Deferred();
14633    result.resolve(value);
14634    return result.promise.then(callback, errback, progressBack);
14635  };
14636
14637  /**
14638   * @ngdoc method
14639   * @name $q#all
14640   * @kind function
14641   *
14642   * @description
14643   * Combines multiple promises into a single promise that is resolved when all of the input
14644   * promises are resolved.
14645   *
14646   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
14647   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
14648   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
14649   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
14650   *   with the same rejection value.
14651   */
14652
14653  function all(promises) {
14654    var deferred = new Deferred(),
14655        counter = 0,
14656        results = isArray(promises) ? [] : {};
14657
14658    forEach(promises, function(promise, key) {
14659      counter++;
14660      when(promise).then(function(value) {
14661        if (results.hasOwnProperty(key)) return;
14662        results[key] = value;
14663        if (!(--counter)) deferred.resolve(results);
14664      }, function(reason) {
14665        if (results.hasOwnProperty(key)) return;
14666        deferred.reject(reason);
14667      });
14668    });
14669
14670    if (counter === 0) {
14671      deferred.resolve(results);
14672    }
14673
14674    return deferred.promise;
14675  }
14676
14677  var $Q = function Q(resolver) {
14678    if (!isFunction(resolver)) {
14679      throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
14680    }
14681
14682    if (!(this instanceof Q)) {
14683      // More useful when $Q is the Promise itself.
14684      return new Q(resolver);
14685    }
14686
14687    var deferred = new Deferred();
14688
14689    function resolveFn(value) {
14690      deferred.resolve(value);
14691    }
14692
14693    function rejectFn(reason) {
14694      deferred.reject(reason);
14695    }
14696
14697    resolver(resolveFn, rejectFn);
14698
14699    return deferred.promise;
14700  };
14701
14702  $Q.defer = defer;
14703  $Q.reject = reject;
14704  $Q.when = when;
14705  $Q.all = all;
14706
14707  return $Q;
14708}
14709
14710function $$RAFProvider() { //rAF
14711  this.$get = ['$window', '$timeout', function($window, $timeout) {
14712    var requestAnimationFrame = $window.requestAnimationFrame ||
14713                                $window.webkitRequestAnimationFrame;
14714
14715    var cancelAnimationFrame = $window.cancelAnimationFrame ||
14716                               $window.webkitCancelAnimationFrame ||
14717                               $window.webkitCancelRequestAnimationFrame;
14718
14719    var rafSupported = !!requestAnimationFrame;
14720    var rafFn = rafSupported
14721      ? function(fn) {
14722          var id = requestAnimationFrame(fn);
14723          return function() {
14724            cancelAnimationFrame(id);
14725          };
14726        }
14727      : function(fn) {
14728          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
14729          return function() {
14730            $timeout.cancel(timer);
14731          };
14732        };
14733
14734    queueFn.supported = rafSupported;
14735
14736    var cancelLastRAF;
14737    var taskCount = 0;
14738    var taskQueue = [];
14739    return queueFn;
14740
14741    function flush() {
14742      for (var i = 0; i < taskQueue.length; i++) {
14743        var task = taskQueue[i];
14744        if (task) {
14745          taskQueue[i] = null;
14746          task();
14747        }
14748      }
14749      taskCount = taskQueue.length = 0;
14750    }
14751
14752    function queueFn(asyncFn) {
14753      var index = taskQueue.length;
14754
14755      taskCount++;
14756      taskQueue.push(asyncFn);
14757
14758      if (index === 0) {
14759        cancelLastRAF = rafFn(flush);
14760      }
14761
14762      return function cancelQueueFn() {
14763        if (index >= 0) {
14764          taskQueue[index] = null;
14765          index = null;
14766
14767          if (--taskCount === 0 && cancelLastRAF) {
14768            cancelLastRAF();
14769            cancelLastRAF = null;
14770            taskQueue.length = 0;
14771          }
14772        }
14773      };
14774    }
14775  }];
14776}
14777
14778/**
14779 * DESIGN NOTES
14780 *
14781 * The design decisions behind the scope are heavily favored for speed and memory consumption.
14782 *
14783 * The typical use of scope is to watch the expressions, which most of the time return the same
14784 * value as last time so we optimize the operation.
14785 *
14786 * Closures construction is expensive in terms of speed as well as memory:
14787 *   - No closures, instead use prototypical inheritance for API
14788 *   - Internal state needs to be stored on scope directly, which means that private state is
14789 *     exposed as $$____ properties
14790 *
14791 * Loop operations are optimized by using while(count--) { ... }
14792 *   - this means that in order to keep the same order of execution as addition we have to add
14793 *     items to the array at the beginning (unshift) instead of at the end (push)
14794 *
14795 * Child scopes are created and removed often
14796 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
14797 *
14798 * There are few watches then a lot of observers. This is why you don't want the observer to be
14799 * implemented in the same way as watch. Watch requires return of initialization function which
14800 * are expensive to construct.
14801 */
14802
14803
14804/**
14805 * @ngdoc provider
14806 * @name $rootScopeProvider
14807 * @description
14808 *
14809 * Provider for the $rootScope service.
14810 */
14811
14812/**
14813 * @ngdoc method
14814 * @name $rootScopeProvider#digestTtl
14815 * @description
14816 *
14817 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
14818 * assuming that the model is unstable.
14819 *
14820 * The current default is 10 iterations.
14821 *
14822 * In complex applications it's possible that the dependencies between `$watch`s will result in
14823 * several digest iterations. However if an application needs more than the default 10 digest
14824 * iterations for its model to stabilize then you should investigate what is causing the model to
14825 * continuously change during the digest.
14826 *
14827 * Increasing the TTL could have performance implications, so you should not change it without
14828 * proper justification.
14829 *
14830 * @param {number} limit The number of digest iterations.
14831 */
14832
14833
14834/**
14835 * @ngdoc service
14836 * @name $rootScope
14837 * @description
14838 *
14839 * Every application has a single root {@link ng.$rootScope.Scope scope}.
14840 * All other scopes are descendant scopes of the root scope. Scopes provide separation
14841 * between the model and the view, via a mechanism for watching the model for changes.
14842 * They also provide an event emission/broadcast and subscription facility. See the
14843 * {@link guide/scope developer guide on scopes}.
14844 */
14845function $RootScopeProvider() {
14846  var TTL = 10;
14847  var $rootScopeMinErr = minErr('$rootScope');
14848  var lastDirtyWatch = null;
14849  var applyAsyncId = null;
14850
14851  this.digestTtl = function(value) {
14852    if (arguments.length) {
14853      TTL = value;
14854    }
14855    return TTL;
14856  };
14857
14858  function createChildScopeClass(parent) {
14859    function ChildScope() {
vendor: 4,153 bytes, lines 14860-14976
14860      this.$$watchers = this.$$nextSibling =
14861          this.$$childHead = this.$$childTail = null;
14862      this.$$listeners = {};
14863      this.$$listenerCount = {};
14864      this.$$watchersCount = 0;
14865      this.$id = nextUid();
14866      this.$$ChildScope = null;
14867    }
14868    ChildScope.prototype = parent;
14869    return ChildScope;
14870  }
14871
14872  this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
14873      function($injector, $exceptionHandler, $parse, $browser) {
14874
14875    function destroyChildScope($event) {
14876        $event.currentScope.$$destroyed = true;
14877    }
14878
14879    /**
14880     * @ngdoc type
14881     * @name $rootScope.Scope
14882     *
14883     * @description
14884     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
14885     * {@link auto.$injector $injector}. Child scopes are created using the
14886     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
14887     * compiled HTML template is executed.)
14888     *
14889     * Here is a simple scope snippet to show how you can interact with the scope.
14890     * ```html
14891     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
14892     * ```
14893     *
14894     * # Inheritance
14895     * A scope can inherit from a parent scope, as in this example:
14896     * ```js
14897         var parent = $rootScope;
14898         var child = parent.$new();
14899
14900         parent.salutation = "Hello";
14901         expect(child.salutation).toEqual('Hello');
14902
14903         child.salutation = "Welcome";
14904         expect(child.salutation).toEqual('Welcome');
14905         expect(parent.salutation).toEqual('Hello');
14906     * ```
14907     *
14908     * When interacting with `Scope` in tests, additional helper methods are available on the
14909     * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
14910     * details.
14911     *
14912     *
14913     * @param {Object.<string, function()>=} providers Map of service factory which need to be
14914     *                                       provided for the current scope. Defaults to {@link ng}.
14915     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
14916     *                              append/override services provided by `providers`. This is handy
14917     *                              when unit-testing and having the need to override a default
14918     *                              service.
14919     * @returns {Object} Newly created scope.
14920     *
14921     */
14922    function Scope() {
14923      this.$id = nextUid();
14924      this.$$phase = this.$parent = this.$$watchers =
14925                     this.$$nextSibling = this.$$prevSibling =
14926                     this.$$childHead = this.$$childTail = null;
14927      this.$root = this;
14928      this.$$destroyed = false;
14929      this.$$listeners = {};
14930      this.$$listenerCount = {};
14931      this.$$watchersCount = 0;
14932      this.$$isolateBindings = null;
14933    }
14934
14935    /**
14936     * @ngdoc property
14937     * @name $rootScope.Scope#$id
14938     *
14939     * @description
14940     * Unique scope ID (monotonically increasing) useful for debugging.
14941     */
14942
14943     /**
14944      * @ngdoc property
14945      * @name $rootScope.Scope#$parent
14946      *
14947      * @description
14948      * Reference to the parent scope.
14949      */
14950
14951      /**
14952       * @ngdoc property
14953       * @name $rootScope.Scope#$root
14954       *
14955       * @description
14956       * Reference to the root scope.
14957       */
14958
14959    Scope.prototype = {
14960      constructor: Scope,
14961      /**
14962       * @ngdoc method
14963       * @name $rootScope.Scope#$new
14964       * @kind function
14965       *
14966       * @description
14967       * Creates a new child {@link ng.$rootScope.Scope scope}.
14968       *
14969       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
14970       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
14971       *
14972       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
14973       * desired for the scope and its child scopes to be permanently detached from the parent and
14974       * thus stop participating in model change detection and listener notification by invoking.
14975       *
14976       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
14977       *         parent scope. The scope is isolated, as it can not see parent scope properties.
14978       *         When creating widgets, it is useful for the widget to not accidentally read parent
14979       *         state.
14980       *
14981       * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
14982       *                              of the newly created scope. Defaults to `this` scope if not provided.
14983       *                              This is used when creating a transclude scope to correctly place it
14984       *                              in the scope hierarchy while maintaining the correct prototypical
14985       *                              inheritance.
14986       *
14987       * @returns {Object} The newly created child scope.
14988       *
14989       */
14990      $new: function(isolate, parent) {
14991        var child;
14992
14993        parent = parent || this;
14994
14995        if (isolate) {
14996          child = new Scope();
14997          child.$root = this.$root;
14998        } else {
14999          // Only create a child scope class if somebody asks for one,
15000          // but cache it to allow the VM to optimize lookups.
15001          if (!this.$$ChildScope) {
15002            this.$$ChildScope = createChildScopeClass(this);
15003          }
15004          child = new this.$$ChildScope();
15005        }
15006        child.$parent = parent;
15007        child.$$prevSibling = parent.$$childTail;
15008        if (parent.$$childHead) {
15009          parent.$$childTail.$$nextSibling = child;
15010          parent.$$childTail = child;
15011        } else {
15012          parent.$$childHead = parent.$$childTail = child;
15013        }
15014
15015        // When the new scope is not isolated or we inherit from `this`, and
15016        // the parent scope is destroyed, the property `$$destroyed` is inherited
15017        // prototypically. In all other cases, this property needs to be set
15018        // when the parent scope is destroyed.
15019        // The listener needs to be added after the parent is set
15020        if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
15021
15022        return child;
15023      },
15024
15025      /**
15026       * @ngdoc method
15027       * @name $rootScope.Scope#$watch
15028       * @kind function
15029       *
15030       * @description
15031       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
15032       *
15033       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
15034       *   $digest()} and should return the value that will be watched. (Since
15035       *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
15036       *   `watchExpression` can execute multiple times per
15037       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
15038       * - The `listener` is called only when the value from the current `watchExpression` and the
15039       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
15040       *   see below). Inequality is determined according to reference inequality,
15041       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
15042       *    via the `!==` Javascript operator, unless `objectEquality == true`
15043       *   (see next point)
15044       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
15045       *   according to the {@link angular.equals} function. To save the value of the object for
15046       *   later comparison, the {@link angular.copy} function is used. This therefore means that
15047       *   watching complex objects will have adverse memory and performance implications.
15048       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
15049       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
15050       *   iteration limit is 10 to prevent an infinite loop deadlock.
15051       *
15052       *
15053       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
15054       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
15055       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
15056       * change is detected, be prepared for multiple calls to your listener.)
15057       *
15058       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
15059       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
15060       * watcher. In rare cases, this is undesirable because the listener is called when the result
15061       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
15062       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
15063       * listener was called due to initialization.
15064       *
15065       *
15066       *
15067       * # Example
15068       * ```js
15069           // let's assume that scope was dependency injected as the $rootScope
15070           var scope = $rootScope;
15071           scope.name = 'misko';
15072           scope.counter = 0;
15073
15074           expect(scope.counter).toEqual(0);
15075           scope.$watch('name', function(newValue, oldValue) {
15076             scope.counter = scope.counter + 1;
15077           });
15078           expect(scope.counter).toEqual(0);
15079
15080           scope.$digest();
15081           // the listener is always called during the first $digest loop after it was registered
15082           expect(scope.counter).toEqual(1);
15083
15084           scope.$digest();
15085           // but now it will not be called unless the value changes
15086           expect(scope.counter).toEqual(1);
15087
15088           scope.name = 'adam';
15089           scope.$digest();
15090           expect(scope.counter).toEqual(2);
15091
15092
15093
15094           // Using a function as a watchExpression
15095           var food;
15096           scope.foodCounter = 0;
15097           expect(scope.foodCounter).toEqual(0);
15098           scope.$watch(
15099             // This function returns the value being watched. It is called for each turn of the $digest loop
15100             function() { return food; },
15101             // This is the change listener, called when the value returned from the above function changes
15102             function(newValue, oldValue) {
15103               if ( newValue !== oldValue ) {
15104                 // Only increment the counter if the value changed
15105                 scope.foodCounter = scope.foodCounter + 1;
15106               }
15107             }
15108           );
15109           // No digest has been run so the counter will be zero
15110           expect(scope.foodCounter).toEqual(0);
15111
15112           // Run the digest but since food has not changed count will still be zero
15113           scope.$digest();
15114           expect(scope.foodCounter).toEqual(0);
15115
15116           // Update food and run digest.  Now the counter will increment
15117           food = 'cheeseburger';
15118           scope.$digest();
15119           expect(scope.foodCounter).toEqual(1);
15120
15121       * ```
15122       *
15123       *
15124       *
15125       * @param {(function()|string)} watchExpression Expression that is evaluated on each
15126       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
15127       *    a call to the `listener`.
15128       *
15129       *    - `string`: Evaluated as {@link guide/expression expression}
15130       *    - `function(scope)`: called with current `scope` as a parameter.
15131       * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
15132       *    of `watchExpression` changes.
15133       *
15134       *    - `newVal` contains the current value of the `watchExpression`
15135       *    - `oldVal` contains the previous value of the `watchExpression`
15136       *    - `scope` refers to the current scope
15137       * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
15138       *     comparing for reference equality.
15139       * @returns {function()} Returns a deregistration function for this listener.
15140       */
15141      $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
15142        var get = $parse(watchExp);
15143
15144        if (get.$$watchDelegate) {
15145          return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
15146        }
15147        var scope = this,
15148            array = scope.$$watchers,
15149            watcher = {
15150              fn: listener,
15151              last: initWatchVal,
15152              get: get,
15153              exp: prettyPrintExpression || watchExp,
15154              eq: !!objectEquality
15155            };
15156
15157        lastDirtyWatch = null;
15158
15159        if (!isFunction(listener)) {
15160          watcher.fn = noop;
15161        }
15162
15163        if (!array) {
15164          array = scope.$$watchers = [];
15165        }
15166        // we use unshift since we use a while loop in $digest for speed.
15167        // the while loop reads in reverse order.
15168        array.unshift(watcher);
15169        incrementWatchersCount(this, 1);
15170
15171        return function deregisterWatch() {
15172          if (arrayRemove(array, watcher) >= 0) {
15173            incrementWatchersCount(scope, -1);
15174          }
15175          lastDirtyWatch = null;
15176        };
15177      },
15178
15179      /**
15180       * @ngdoc method
15181       * @name $rootScope.Scope#$watchGroup
15182       * @kind function
15183       *
15184       * @description
15185       * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
15186       * If any one expression in the collection changes the `listener` is executed.
15187       *
15188       * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
15189       *   call to $digest() to see if any items changes.
15190       * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
15191       *
15192       * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
15193       * watched using {@link ng.$rootScope.Scope#$watch $watch()}
15194       *
15195       * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
15196       *    expression in `watchExpressions` changes
15197       *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
15198       *    those of `watchExpression`
15199       *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
15200       *    those of `watchExpression`
15201       *    The `scope` refers to the current scope.
15202       * @returns {function()} Returns a de-registration function for all listeners.
15203       */
15204      $watchGroup: function(watchExpressions, listener) {
15205        var oldValues = new Array(watchExpressions.length);
15206        var newValues = new Array(watchExpressions.length);
15207        var deregisterFns = [];
15208        var self = this;
15209        var changeReactionScheduled = false;
vendor: 10,180 bytes, lines 15210-15472
15210        var firstRun = true;
15211
15212        if (!watchExpressions.length) {
15213          // No expressions means we call the listener ASAP
15214          var shouldCall = true;
15215          self.$evalAsync(function() {
15216            if (shouldCall) listener(newValues, newValues, self);
15217          });
15218          return function deregisterWatchGroup() {
15219            shouldCall = false;
15220          };
15221        }
15222
15223        if (watchExpressions.length === 1) {
15224          // Special case size of one
15225          return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
15226            newValues[0] = value;
15227            oldValues[0] = oldValue;
15228            listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
15229          });
15230        }
15231
15232        forEach(watchExpressions, function(expr, i) {
15233          var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
15234            newValues[i] = value;
15235            oldValues[i] = oldValue;
15236            if (!changeReactionScheduled) {
15237              changeReactionScheduled = true;
15238              self.$evalAsync(watchGroupAction);
15239            }
15240          });
15241          deregisterFns.push(unwatchFn);
15242        });
15243
15244        function watchGroupAction() {
15245          changeReactionScheduled = false;
15246
15247          if (firstRun) {
15248            firstRun = false;
15249            listener(newValues, newValues, self);
15250          } else {
15251            listener(newValues, oldValues, self);
15252          }
15253        }
15254
15255        return function deregisterWatchGroup() {
15256          while (deregisterFns.length) {
15257            deregisterFns.shift()();
15258          }
15259        };
15260      },
15261
15262
15263      /**
15264       * @ngdoc method
15265       * @name $rootScope.Scope#$watchCollection
15266       * @kind function
15267       *
15268       * @description
15269       * Shallow watches the properties of an object and fires whenever any of the properties change
15270       * (for arrays, this implies watching the array items; for object maps, this implies watching
15271       * the properties). If a change is detected, the `listener` callback is fired.
15272       *
15273       * - The `obj` collection is observed via standard $watch operation and is examined on every
15274       *   call to $digest() to see if any items have been added, removed, or moved.
15275       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
15276       *   adding, removing, and moving items belonging to an object or array.
15277       *
15278       *
15279       * # Example
15280       * ```js
15281          $scope.names = ['igor', 'matias', 'misko', 'james'];
15282          $scope.dataCount = 4;
15283
15284          $scope.$watchCollection('names', function(newNames, oldNames) {
15285            $scope.dataCount = newNames.length;
15286          });
15287
15288          expect($scope.dataCount).toEqual(4);
15289          $scope.$digest();
15290
15291          //still at 4 ... no changes
15292          expect($scope.dataCount).toEqual(4);
15293
15294          $scope.names.pop();
15295          $scope.$digest();
15296
15297          //now there's been a change
15298          expect($scope.dataCount).toEqual(3);
15299       * ```
15300       *
15301       *
15302       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
15303       *    expression value should evaluate to an object or an array which is observed on each
15304       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
15305       *    collection will trigger a call to the `listener`.
15306       *
15307       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
15308       *    when a change is detected.
15309       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
15310       *    - The `oldCollection` object is a copy of the former collection data.
15311       *      Due to performance considerations, the`oldCollection` value is computed only if the
15312       *      `listener` function declares two or more arguments.
15313       *    - The `scope` argument refers to the current scope.
15314       *
15315       * @returns {function()} Returns a de-registration function for this listener. When the
15316       *    de-registration function is executed, the internal watch operation is terminated.
15317       */
15318      $watchCollection: function(obj, listener) {
15319        $watchCollectionInterceptor.$stateful = true;
15320
15321        var self = this;
15322        // the current value, updated on each dirty-check run
15323        var newValue;
15324        // a shallow copy of the newValue from the last dirty-check run,
15325        // updated to match newValue during dirty-check run
15326        var oldValue;
15327        // a shallow copy of the newValue from when the last change happened
15328        var veryOldValue;
15329        // only track veryOldValue if the listener is asking for it
15330        var trackVeryOldValue = (listener.length > 1);
15331        var changeDetected = 0;
15332        var changeDetector = $parse(obj, $watchCollectionInterceptor);
15333        var internalArray = [];
15334        var internalObject = {};
15335        var initRun = true;
15336        var oldLength = 0;
15337
15338        function $watchCollectionInterceptor(_value) {
15339          newValue = _value;
15340          var newLength, key, bothNaN, newItem, oldItem;
15341
15342          // If the new value is undefined, then return undefined as the watch may be a one-time watch
15343          if (isUndefined(newValue)) return;
15344
15345          if (!isObject(newValue)) { // if primitive
15346            if (oldValue !== newValue) {
15347              oldValue = newValue;
15348              changeDetected++;
15349            }
15350          } else if (isArrayLike(newValue)) {
15351            if (oldValue !== internalArray) {
15352              // we are transitioning from something which was not an array into array.
15353              oldValue = internalArray;
15354              oldLength = oldValue.length = 0;
15355              changeDetected++;
15356            }
15357
15358            newLength = newValue.length;
15359
15360            if (oldLength !== newLength) {
15361              // if lengths do not match we need to trigger change notification
15362              changeDetected++;
15363              oldValue.length = oldLength = newLength;
15364            }
15365            // copy the items to oldValue and look for changes.
15366            for (var i = 0; i < newLength; i++) {
15367              oldItem = oldValue[i];
15368              newItem = newValue[i];
15369
15370              bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15371              if (!bothNaN && (oldItem !== newItem)) {
15372                changeDetected++;
15373                oldValue[i] = newItem;
15374              }
15375            }
15376          } else {
15377            if (oldValue !== internalObject) {
15378              // we are transitioning from something which was not an object into object.
15379              oldValue = internalObject = {};
15380              oldLength = 0;
15381              changeDetected++;
15382            }
15383            // copy the items to oldValue and look for changes.
15384            newLength = 0;
15385            for (key in newValue) {
15386              if (newValue.hasOwnProperty(key)) {
15387                newLength++;
15388                newItem = newValue[key];
15389                oldItem = oldValue[key];
15390
15391                if (key in oldValue) {
15392                  bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
15393                  if (!bothNaN && (oldItem !== newItem)) {
15394                    changeDetected++;
15395                    oldValue[key] = newItem;
15396                  }
15397                } else {
15398                  oldLength++;
15399                  oldValue[key] = newItem;
15400                  changeDetected++;
15401                }
15402              }
15403            }
15404            if (oldLength > newLength) {
15405              // we used to have more keys, need to find them and destroy them.
15406              changeDetected++;
15407              for (key in oldValue) {
15408                if (!newValue.hasOwnProperty(key)) {
15409                  oldLength--;
15410                  delete oldValue[key];
15411                }
15412              }
15413            }
15414          }
15415          return changeDetected;
15416        }
15417
15418        function $watchCollectionAction() {
15419          if (initRun) {
15420            initRun = false;
15421            listener(newValue, newValue, self);
15422          } else {
15423            listener(newValue, veryOldValue, self);
15424          }
15425
15426          // make a copy for the next time a collection is changed
15427          if (trackVeryOldValue) {
15428            if (!isObject(newValue)) {
15429              //primitive
15430              veryOldValue = newValue;
15431            } else if (isArrayLike(newValue)) {
15432              veryOldValue = new Array(newValue.length);
15433              for (var i = 0; i < newValue.length; i++) {
15434                veryOldValue[i] = newValue[i];
15435              }
15436            } else { // if object
15437              veryOldValue = {};
15438              for (var key in newValue) {
15439                if (hasOwnProperty.call(newValue, key)) {
15440                  veryOldValue[key] = newValue[key];
15441                }
15442              }
15443            }
15444          }
15445        }
15446
15447        return this.$watch(changeDetector, $watchCollectionAction);
15448      },
15449
15450      /**
15451       * @ngdoc method
15452       * @name $rootScope.Scope#$digest
15453       * @kind function
15454       *
15455       * @description
15456       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
15457       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
15458       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
15459       * until no more listeners are firing. This means that it is possible to get into an infinite
15460       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
15461       * iterations exceeds 10.
15462       *
15463       * Usually, you don't call `$digest()` directly in
15464       * {@link ng.directive:ngController controllers} or in
15465       * {@link ng.$compileProvider#directive directives}.
15466       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
15467       * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
15468       *
15469       * If you want to be notified whenever `$digest()` is called,
15470       * you can register a `watchExpression` function with
15471       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
15472       *
15473       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
15474       *
15475       * # Example
15476       * ```js
15477           var scope = ...;
15478           scope.name = 'misko';
15479           scope.counter = 0;
15480
15481           expect(scope.counter).toEqual(0);
15482           scope.$watch('name', function(newValue, oldValue) {
15483             scope.counter = scope.counter + 1;
15484           });
15485           expect(scope.counter).toEqual(0);
15486
15487           scope.$digest();
15488           // the listener is always called during the first $digest loop after it was registered
15489           expect(scope.counter).toEqual(1);
15490
15491           scope.$digest();
15492           // but now it will not be called unless the value changes
15493           expect(scope.counter).toEqual(1);
15494
15495           scope.name = 'adam';
15496           scope.$digest();
15497           expect(scope.counter).toEqual(2);
15498       * ```
15499       *
15500       */
15501      $digest: function() {
15502        var watch, value, last,
15503            watchers,
15504            length,
15505            dirty, ttl = TTL,
15506            next, current, target = this,
15507            watchLog = [],
15508            logIdx, logMsg, asyncTask;
15509
15510        beginPhase('$digest');
15511        // Check for changes to browser url that happened in sync before the call to $digest
15512        $browser.$$checkUrlChange();
15513
15514        if (this === $rootScope && applyAsyncId !== null) {
15515          // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
15516          // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
15517          $browser.defer.cancel(applyAsyncId);
15518          flushApplyAsync();
15519        }
15520
15521        lastDirtyWatch = null;
15522
15523        do { // "while dirty" loop
15524          dirty = false;
15525          current = target;
15526
15527          while (asyncQueue.length) {
15528            try {
15529              asyncTask = asyncQueue.shift();
15530              asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
15531            } catch (e) {
15532              $exceptionHandler(e);
15533            }
15534            lastDirtyWatch = null;
15535          }
15536
15537          traverseScopesLoop:
15538          do { // "traverse the scopes" loop
15539            if ((watchers = current.$$watchers)) {
15540              // process our watches
15541              length = watchers.length;
15542              while (length--) {
15543                try {
15544                  watch = watchers[length];
15545                  // Most common watches are on primitives, in which case we can short
15546                  // circuit it with === operator, only when === fails do we use .equals
15547                  if (watch) {
15548                    if ((value = watch.get(current)) !== (last = watch.last) &&
15549                        !(watch.eq
15550                            ? equals(value, last)
15551                            : (typeof value === 'number' && typeof last === 'number'
15552                               && isNaN(value) && isNaN(last)))) {
15553                      dirty = true;
15554                      lastDirtyWatch = watch;
15555                      watch.last = watch.eq ? copy(value, null) : value;
15556                      watch.fn(value, ((last === initWatchVal) ? value : last), current);
15557                      if (ttl < 5) {
15558                        logIdx = 4 - ttl;
15559                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
15560                        watchLog[logIdx].push({
15561                          msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
15562                          newVal: value,
15563                          oldVal: last
15564                        });
15565                      }
15566                    } else if (watch === lastDirtyWatch) {
15567                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
15568                      // have already been tested.
15569                      dirty = false;
15570                      break traverseScopesLoop;
15571                    }
15572                  }
15573                } catch (e) {
15574                  $exceptionHandler(e);
15575                }
15576              }
15577            }
15578
15579            // Insanity Warning: scope depth-first traversal
15580            // yes, this code is a bit crazy, but it works and we have tests to prove it!
15581            // this piece should be kept in sync with the traversal in $broadcast
15582            if (!(next = ((current.$$watchersCount && current.$$childHead) ||
15583                (current !== target && current.$$nextSibling)))) {
15584              while (current !== target && !(next = current.$$nextSibling)) {
15585                current = current.$parent;
15586              }
15587            }
15588          } while ((current = next));
15589
15590          // `break traverseScopesLoop;` takes us to here
15591
15592          if ((dirty || asyncQueue.length) && !(ttl--)) {
15593            clearPhase();
15594            throw $rootScopeMinErr('infdig',
15595                '{0} $digest() iterations reached. Aborting!\n' +
15596                'Watchers fired in the last 5 iterations: {1}',
15597                TTL, watchLog);
15598          }
15599
15600        }
vendor: 5,032 bytes, lines 15600-15726
15600 while (dirty || asyncQueue.length);
15601
15602        clearPhase();
15603
15604        while (postDigestQueue.length) {
15605          try {
15606            postDigestQueue.shift()();
15607          } catch (e) {
15608            $exceptionHandler(e);
15609          }
15610        }
15611      },
15612
15613
15614      /**
15615       * @ngdoc event
15616       * @name $rootScope.Scope#$destroy
15617       * @eventType broadcast on scope being destroyed
15618       *
15619       * @description
15620       * Broadcasted when a scope and its children are being destroyed.
15621       *
15622       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
15623       * clean up DOM bindings before an element is removed from the DOM.
15624       */
15625
15626      /**
15627       * @ngdoc method
15628       * @name $rootScope.Scope#$destroy
15629       * @kind function
15630       *
15631       * @description
15632       * Removes the current scope (and all of its children) from the parent scope. Removal implies
15633       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
15634       * propagate to the current scope and its children. Removal also implies that the current
15635       * scope is eligible for garbage collection.
15636       *
15637       * The `$destroy()` is usually used by directives such as
15638       * {@link ng.directive:ngRepeat ngRepeat} for managing the
15639       * unrolling of the loop.
15640       *
15641       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
15642       * Application code can register a `$destroy` event handler that will give it a chance to
15643       * perform any necessary cleanup.
15644       *
15645       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
15646       * clean up DOM bindings before an element is removed from the DOM.
15647       */
15648      $destroy: function() {
15649        // We can't destroy a scope that has been already destroyed.
15650        if (this.$$destroyed) return;
15651        var parent = this.$parent;
15652
15653        this.$broadcast('$destroy');
15654        this.$$destroyed = true;
15655
15656        if (this === $rootScope) {
15657          //Remove handlers attached to window when $rootScope is removed
15658          $browser.$$applicationDestroyed();
15659        }
15660
15661        incrementWatchersCount(this, -this.$$watchersCount);
15662        for (var eventName in this.$$listenerCount) {
15663          decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
15664        }
15665
15666        // sever all the references to parent scopes (after this cleanup, the current scope should
15667        // not be retained by any of our references and should be eligible for garbage collection)
15668        if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
15669        if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
15670        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
15671        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
15672
15673        // Disable listeners, watchers and apply/digest methods
15674        this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
15675        this.$on = this.$watch = this.$watchGroup = function() { return noop; };
15676        this.$$listeners = {};
15677
15678        // All of the code below is bogus code that works around V8's memory leak via optimized code
15679        // and inline caches.
15680        //
15681        // see:
15682        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15683        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15684        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15685
15686        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
15687            this.$$childTail = this.$root = this.$$watchers = null;
15688      },
15689
15690      /**
15691       * @ngdoc method
15692       * @name $rootScope.Scope#$eval
15693       * @kind function
15694       *
15695       * @description
15696       * Executes the `expression` on the current scope and returns the result. Any exceptions in
15697       * the expression are propagated (uncaught). This is useful when evaluating Angular
15698       * expressions.
15699       *
15700       * # Example
15701       * ```js
15702           var scope = ng.$rootScope.Scope();
15703           scope.a = 1;
15704           scope.b = 2;
15705
15706           expect(scope.$eval('a+b')).toEqual(3);
15707           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
15708       * ```
15709       *
15710       * @param {(string|function())=} expression An angular expression to be executed.
15711       *
15712       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
15713       *    - `function(scope)`: execute the function with the current `scope` parameter.
15714       *
15715       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
15716       * @returns {*} The result of evaluating the expression.
15717       */
15718      $eval: function(expr, locals) {
15719        return $parse(expr)(this, locals);
15720      },
15721
15722      /**
15723       * @ngdoc method
15724       * @name $rootScope.Scope#$evalAsync
15725       * @kind function
15726       *
15727       * @description
15728       * Executes the expression on the current scope at a later point in time.
15729       *
15730       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
15731       * that:
15732       *
15733       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
15734       *     rendering).
15735       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
15736       *     `expression` execution.
15737       *
15738       * Any exceptions from the execution of the expression are forwarded to the
15739       * {@link ng.$exceptionHandler $exceptionHandler} service.
15740       *
15741       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
15742       * will be scheduled. However, it is encouraged to always call code that changes the model
15743       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
15744       *
15745       * @param {(string|function())=} expression An angular expression to be executed.
15746       *
15747       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
15748       *    - `function(scope)`: execute the function with the current `scope` parameter.
15749       *
15750       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
15751       */
15752      $evalAsync: function(expr, locals) {
15753        // if we are outside of an $digest loop and this is the first time we are scheduling async
15754        // task also schedule async auto-flush
15755        if (!$rootScope.$$phase && !asyncQueue.length) {
15756          $browser.defer(function() {
15757            if (asyncQueue.length) {
15758              $rootScope.$digest();
15759            }
15760          });
15761        }
15762
15763        asyncQueue.push({scope: this, expression: expr, locals: locals});
15764      },
15765
15766      $$postDigest: function(fn) {
15767        postDigestQueue.push(fn);
15768      },
15769
15770      /**
15771       * @ngdoc method
15772       * @name $rootScope.Scope#$apply
15773       * @kind function
15774       *
15775       * @description
15776       * `$apply()` is used to execute an expression in angular from outside of the angular
15777       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
15778       * Because we are calling into the angular framework we need to perform proper scope life
15779       * cycle of {@link ng.$exceptionHandler exception handling},
15780       * {@link ng.$rootScope.Scope#$digest executing watches}.
15781       *
15782       * ## Life cycle
15783       *
15784       * # Pseudo-Code of `$apply()`
15785       * ```js
15786           function $apply(expr) {
15787             try {
15788               return $eval(expr);
15789             } catch (e) {
15790               $exceptionHandler(e);
15791             } finally {
15792               $root.$digest();
15793             }
15794           }
15795       * ```
15796       *
15797       *
15798       * Scope's `$apply()` method transitions through the following stages:
15799       *
15800       * 1. The {@link guide/expression expression} is executed using the
15801       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
15802       * 2. Any exceptions from the execution of the expression are forwarded to the
15803       *    {@link ng.$exceptionHandler $exceptionHandler} service.
15804       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
15805       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
15806       *
15807       *
15808       * @param {(string|function())=} exp An angular expression to be executed.
15809       *
15810       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
15811       *    - `function(scope)`: execute the function with current `scope` parameter.
15812       *
15813       * @returns {*} The result of evaluating the expression.
15814       */
15815      $apply: function(expr) {
15816        try {
15817          beginPhase('$apply');
15818          return this.$eval(expr);
15819        } catch (e) {
15820          $exceptionHandler(e);
15821        } finally {
15822          clearPhase();
15823          try {
15824            $rootScope.$digest();
15825          } catch (e) {
15826            $exceptionHandler(e);
15827            throw e;
15828          }
15829        }
15830      },
15831
15832      /**
15833       * @ngdoc method
15834       * @name $rootScope.Scope#$applyAsync
15835       * @kind function
15836       *
15837       * @description
15838       * Schedule the invocation of $apply to occur at a later time. The actual time difference
15839       * varies across browsers, but is typically around ~10 milliseconds.
15840       *
15841       * This can be used to queue up multiple expressions which need to be evaluated in the same
15842       * digest.
15843       *
15844       * @param {(string|function())=} exp An angular expression to be executed.
15845       *
15846       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
15847       *    - `function(scope)`: execute the function with current `scope` parameter.
15848       */
15849      $applyAsync: function(expr) {
15850        var scope = this;
15851        expr && applyAsyncQueue.push($applyAsyncExpression);
15852        scheduleApplyAsync();
15853
15854        function $applyAsyncExpression() {
15855          scope.$eval(expr);
15856        }
15857      },
15858
15859      /**
15860       * @ngdoc method
15861       * @name $rootScope.Scope#$on
15862       * @kind function
15863       *
15864       * @description
15865       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
15866       * discussion of event life cycle.
15867       *
15868       * The event listener function format is: `function(event, args...)`. The `event` object
15869       * passed into the listener has the following attributes:
15870       *
15871       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
15872       *     `$broadcast`-ed.
15873       *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
15874       *     event propagates through the scope hierarchy, this property is set to null.
15875       *   - `name` - `{string}`: name of the event.
15876       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
15877       *     further event propagation (available only for events that were `$emit`-ed).
15878       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
15879       *     to true.
15880       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
15881       *
15882       * @param {string} name Event name to listen on.
15883       * @param {function(event, ...args)} listener Function to call when the event is emitted.
15884       * @returns {function()} Returns a deregistration function for this listener.
15885       */
15886      $on: function(name, listener) {
15887        var namedListeners = this.$$listeners[name];
15888        if (!namedListeners) {
15889          this.$$listeners[name] = namedListeners = [];
15890        }
15891        namedListeners.push(listener);
15892
15893        var current = this;
15894        do {
15895          if (!current.$$listenerCount[name]) {
15896            current.$$listenerCount[name] = 0;
15897          }
15898          current.$$listenerCount[name]++;
15899        } while ((current = current.$parent));
15900
15901        var self = this;
15902        return function() {
15903          var indexOfListener = namedListeners.indexOf(listener);
15904          if (indexOfListener !== -1) {
15905            namedListeners[indexOfListener] = null;
15906            decrementListenerCount(self, 1, name);
15907          }
15908        };
15909      },
15910
15911
15912      /**
15913       * @ngdoc method
15914       * @name $rootScope.Scope#$emit
15915       * @kind function
15916       *
15917       * @description
15918       * Dispatches an event `name` upwards through the scope hierarchy notifying the
15919       * registered {@link ng.$rootScope.Scope#$on} listeners.
15920       *
15921       * The event life cycle starts at the scope on which `$emit` was called. All
15922       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
15923       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
15924       * registered listeners along the way. The event will stop propagating if one of the listeners
15925       * cancels it.
15926       *
15927       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
15928       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
15929       *
15930       * @param {string} name Event name to emit.
15931       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
15932       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
15933       */
15934      $emit: function(name, args) {
15935        var empty = [],
15936            namedListeners,
15937            scope = this,
15938            stopPropagation = false,
15939            event = {
15940              name: name,
15941              targetScope: scope,
15942              stopPropagation: function() {stopPropagation = true;},
15943              preventDefault: function() {
15944                event.defaultPrevented = true;
15945              },
15946              defaultPrevented: false
15947            },
15948            listenerArgs = concat([event], arguments, 1),
15949            i, length;
15950
15951        do {
15952          namedListeners = scope.$$listeners[name] || empty;
15953          event.currentScope = scope;
15954          for (i = 0, length = namedListeners.length; i < length; i++) {
15955
15956            // if listeners were deregistered, defragment the array
15957            if (!namedListeners[i]) {
15958              namedListeners.splice(i, 1);
15959              i--;
15960              length--;
15961              continue;
15962            }
15963            try {
15964              //allow all listeners attached to the current scope to run
15965              namedListeners[i].apply(null, listenerArgs);
15966            } catch (e) {
15967              $exceptionHandler(e);
15968            }
15969          }
15970          //if any listener on the current scope stops propagation, prevent bubbling
15971          if (stopPropagation) {
15972            event.currentScope = null;
15973            return event;
15974          }
15975          //traverse upwards
15976          scope = scope.$parent;
15977        } while (scope);
15978
15979        event.currentScope = null;
15980
15981        return event;
15982      },
15983
15984
15985      /**
15986       * @ngdoc method
15987       * @name $rootScope.Scope#$broadcast
15988       * @kind function
15989       *
15990       * @description
15991       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
15992       * registered {@link ng.$rootScope.Scope#$on} listeners.
15993       *
15994       * The event life cycle starts at the scope on which `$broadcast` was called. All
15995       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
15996       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
15997       * scope and calls all registered listeners along the way. The event cannot be canceled.
15998       *
15999       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
16000       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
16001       *
16002       * @param {string} name Event name to broadcast.
16003       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
16004       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
16005       */
16006      $broadcast: function(name, args) {
16007        var target = this,
16008            current = target,
16009            next = target,
16010            event = {
16011              name: name,
16012              targetScope: target,
16013              preventDefault: function() {
16014                event.defaultPrevented = true;
16015              },
16016              defaultPrevented: false
16017            };
16018
16019        if (!target.$$listenerCount[name]) return event;
16020
16021        var listenerArgs = concat([event], arguments, 1),
16022            listeners, i, length;
16023
16024        //down while you can, then up and next sibling or up and next sibling until back at root
16025        while ((current = next)) {
16026          event.currentScope = current;
16027          listeners = current.$$listeners[name] || [];
16028          for (i = 0, length = listeners.length; i < length; i++) {
16029            // if listeners were deregistered, defragment the array
16030            if (!listeners[i]) {
16031              listeners.splice(i, 1);
16032              i--;
16033              length--;
16034              continue;
16035            }
16036
16037            try {
16038              listeners[i].apply(null, listenerArgs);
16039            } catch (e) {
16040              $exceptionHandler(e);
16041            }
16042          }
16043
16044          // Insanity Warning: scope depth-first traversal
16045          // yes, this code is a bit crazy, but it works and we have tests to prove it!
16046          // this piece should be kept in sync with the traversal in $digest
16047          // (though it differs due to having the extra check for $$listenerCount)
16048          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
16049              (current !== target && current.$$nextSibling)))) {
16050            while (current !== target && !(next = current.$$nextSibling)) {
16051              current = current.$parent;
16052            }
16053          }
16054        }
16055
16056        event.currentScope = null;
16057        return event;
16058      }
16059    };
16060
16061    var $rootScope = new Scope();
16062
16063    //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
16064    var asyncQueue = $rootScope.$$asyncQueue = [];
16065    var postDigestQueue = $rootScope.$$postDigestQueue = [];
16066    var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
16067
16068    return $rootScope;
16069
16070
16071    function beginPhase(phase) {
16072      if ($rootScope.$$phase) {
16073        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
16074      }
16075
16076      $rootScope.$$phase = phase;
16077    }
16078
16079    function clearPhase() {
16080      $rootScope.$$phase = null;
16081    }
16082
16083    function incrementWatchersCount(current, count) {
16084      do {
16085        current.$$watchersCount += count;
16086      } while ((current = current.$parent));
16087    }
16088
16089    function decrementListenerCount(current, count, name) {
16090      do {
16091        current.$$listenerCount[name] -= count;
16092
16093        if (current.$$listenerCount[name] === 0) {
16094          delete current.$$listenerCount[name];
16095        }
16096      } while ((current = current.$parent));
16097    }
16098
16099    /**
16100     * function used as an initial value for watchers.
16101     * because it's unique we can easily tell it apart from other values
16102     */
16103    function initWatchVal() {}
16104
16105    function flushApplyAsync() {
vendor: 4,838 bytes, lines 16106-16233
16106      while (applyAsyncQueue.length) {
16107        try {
16108          applyAsyncQueue.shift()();
16109        } catch (e) {
16110          $exceptionHandler(e);
16111        }
16112      }
16113      applyAsyncId = null;
16114    }
16115
16116    function scheduleApplyAsync() {
16117      if (applyAsyncId === null) {
16118        applyAsyncId = $browser.defer(function() {
16119          $rootScope.$apply(flushApplyAsync);
16120        });
16121      }
16122    }
16123  }];
16124}
16125
16126/**
16127 * @description
16128 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
16129 */
16130function $$SanitizeUriProvider() {
16131  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
16132    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
16133
16134  /**
16135   * @description
16136   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16137   * urls during a[href] sanitization.
16138   *
16139   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16140   *
16141   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16142   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16143   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16144   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16145   *
16146   * @param {RegExp=} regexp New regexp to whitelist urls with.
16147   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16148   *    chaining otherwise.
16149   */
16150  this.aHrefSanitizationWhitelist = function(regexp) {
16151    if (isDefined(regexp)) {
16152      aHrefSanitizationWhitelist = regexp;
16153      return this;
16154    }
16155    return aHrefSanitizationWhitelist;
16156  };
16157
16158
16159  /**
16160   * @description
16161   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16162   * urls during img[src] sanitization.
16163   *
16164   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16165   *
16166   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16167   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16168   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16169   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16170   *
16171   * @param {RegExp=} regexp New regexp to whitelist urls with.
16172   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16173   *    chaining otherwise.
16174   */
16175  this.imgSrcSanitizationWhitelist = function(regexp) {
16176    if (isDefined(regexp)) {
16177      imgSrcSanitizationWhitelist = regexp;
16178      return this;
16179    }
16180    return imgSrcSanitizationWhitelist;
16181  };
16182
16183  this.$get = function() {
16184    return function sanitizeUri(uri, isImage) {
16185      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
16186      var normalizedVal;
16187      normalizedVal = urlResolve(uri).href;
16188      if (normalizedVal !== '' && !normalizedVal.match(regex)) {
16189        return 'unsafe:' + normalizedVal;
16190      }
16191      return uri;
16192    };
16193  };
16194}
16195
16196/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
16197 *     Any commits to this file should be reviewed with security in mind.  *
16198 *   Changes to this file can potentially create security vulnerabilities. *
16199 *          An approval from 2 Core members with history of modifying      *
16200 *                         this file is required.                          *
16201 *                                                                         *
16202 *  Does the change somehow allow for arbitrary javascript to be executed? *
16203 *    Or allows for someone to change the prototype of built-in objects?   *
16204 *     Or gives undesired access to variables likes document or window?    *
16205 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16206
16207var $sceMinErr = minErr('$sce');
16208
16209var SCE_CONTEXTS = {
16210  HTML: 'html',
16211  CSS: 'css',
16212  URL: 'url',
16213  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
16214  // url.  (e.g. ng-include, script src, templateUrl)
16215  RESOURCE_URL: 'resourceUrl',
16216  JS: 'js'
16217};
16218
16219// Helper functions follow.
16220
16221function adjustMatcher(matcher) {
16222  if (matcher === 'self') {
16223    return matcher;
16224  } else if (isString(matcher)) {
16225    // Strings match exactly except for 2 wildcards - '*' and '**'.
16226    // '*' matches any character except those from the set ':/.?&'.
16227    // '**' matches any character (like .* in a RegExp).
16228    // More than 2 *'s raises an error as it's ill defined.
16229    if (matcher.indexOf('***') > -1) {
16230      throw $sceMinErr('iwcard',
16231          'Illegal sequence *** in string matcher.  String: {0}', matcher);
16232    }
16233    matcher = escapeForRegexp(matcher).
16234                  replace('\\*\\*', '.*').
16235                  replace('\\*', '[^:/.?&;]*');
16236    return new RegExp('^' + matcher + '$');
16237  } else if (isRegExp(matcher)) {
16238    // The only other type of matcher allowed is a Regexp.
16239    // Match entire URL / disallow partial matches.
16240    // Flags are reset (i.e. no global, ignoreCase or multiline)
16241    return new RegExp('^' + matcher.source + '$');
16242  } else {
16243    throw $sceMinErr('imatcher',
16244        'Matchers may only be "self", string patterns or RegExp objects');
16245  }
16246}
16247
16248
16249function adjustMatchers(matchers) {
16250  var adjustedMatchers = [];
16251  if (isDefined(matchers)) {
16252    forEach(matchers, function(matcher) {
16253      adjustedMatchers.push(adjustMatcher(matcher));
16254    });
16255  }
16256  return adjustedMatchers;
16257}
16258
16259
16260/**
16261 * @ngdoc service
16262 * @name $sceDelegate
16263 * @kind function
16264 *
16265 * @description
16266 *
16267 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
16268 * Contextual Escaping (SCE)} services to AngularJS.
16269 *
16270 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
16271 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
16272 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
16273 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
16274 * work because `$sce` delegates to `$sceDelegate` for these operations.
16275 *
16276 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
16277 *
16278 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
16279 * can override it completely to change the behavior of `$sce`, the common case would
16280 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
16281 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
16282 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
16283 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
16284 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16285 */
16286
16287/**
16288 * @ngdoc provider
16289 * @name $sceDelegateProvider
16290 * @description
16291 *
16292 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
16293 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
16294 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
16295 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
16296 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
16297 *
16298 * For the general details about this service in Angular, read the main page for {@link ng.$sce
16299 * Strict Contextual Escaping (SCE)}.
16300 *
16301 * **Example**:  Consider the following case. <a name="example"></a>
16302 *
16303 * - your app is hosted at url `http://myapp.example.com/`
16304 * - but some of your templates are hosted on other domains you control such as
16305 *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
16306 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
16307 *
16308 * Here is what a secure configuration for this scenario might look like:
16309 *
16310 * ```
16311 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
16312 *    $sceDelegateProvider.resourceUrlWhitelist([
16313 *      // Allow same origin resource loads.
16314 *      'self',
16315 *      // Allow loading from our assets domain.  Notice the difference between * and **.
16316 *      'http://srv*.assets.example.com/**'
16317 *    ]);
16318 *
16319 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
16320 *    $sceDelegateProvider.resourceUrlBlacklist([
16321 *      'http://myapp.example.com/clickThru**'
16322 *    ]);
16323 *  });
16324 * ```
16325 */
16326
16327function $SceDelegateProvider() {
16328  this.SCE_CONTEXTS = SCE_CONTEXTS;
16329
16330  // Resource URLs can also be trusted by policy.
16331  var resourceUrlWhitelist = ['self'],
16332      resourceUrlBlacklist = [];
16333
16334  /**
16335   * @ngdoc method
16336   * @name $sceDelegateProvider#resourceUrlWhitelist
16337   * @kind function
16338   *
16339   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
16340   *     provided.  This must be an array or null.  A snapshot of this array is used so further
16341   *     changes to the array are ignored.
16342   *
16343   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16344   *     allowed in this array.
vendor: 4,148 bytes, lines 16345-16469
16345   *
16346   *     Note: **an empty whitelist array will block all URLs**!
16347   *
16348   * @return {Array} the currently set whitelist array.
16349   *
16350   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
16351   * same origin resource requests.
16352   *
16353   * @description
16354   * Sets/Gets the whitelist of trusted resource URLs.
16355   */
16356  this.resourceUrlWhitelist = function(value) {
16357    if (arguments.length) {
16358      resourceUrlWhitelist = adjustMatchers(value);
16359    }
16360    return resourceUrlWhitelist;
16361  };
16362
16363  /**
16364   * @ngdoc method
16365   * @name $sceDelegateProvider#resourceUrlBlacklist
16366   * @kind function
16367   *
16368   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
16369   *     provided.  This must be an array or null.  A snapshot of this array is used so further
16370   *     changes to the array are ignored.
16371   *
16372   *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
16373   *     allowed in this array.
16374   *
16375   *     The typical usage for the blacklist is to **block
16376   *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
16377   *     these would otherwise be trusted but actually return content from the redirected domain.
16378   *
16379   *     Finally, **the blacklist overrides the whitelist** and has the final say.
16380   *
16381   * @return {Array} the currently set blacklist array.
16382   *
16383   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
16384   * is no blacklist.)
16385   *
16386   * @description
16387   * Sets/Gets the blacklist of trusted resource URLs.
16388   */
16389
16390  this.resourceUrlBlacklist = function(value) {
16391    if (arguments.length) {
16392      resourceUrlBlacklist = adjustMatchers(value);
16393    }
16394    return resourceUrlBlacklist;
16395  };
16396
16397  this.$get = ['$injector', function($injector) {
16398
16399    var htmlSanitizer = function htmlSanitizer(html) {
16400      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16401    };
16402
16403    if ($injector.has('$sanitize')) {
16404      htmlSanitizer = $injector.get('$sanitize');
16405    }
16406
16407
16408    function matchUrl(matcher, parsedUrl) {
16409      if (matcher === 'self') {
16410        return urlIsSameOrigin(parsedUrl);
16411      } else {
16412        // definitely a regex.  See adjustMatchers()
16413        return !!matcher.exec(parsedUrl.href);
16414      }
16415    }
16416
16417    function isResourceUrlAllowedByPolicy(url) {
16418      var parsedUrl = urlResolve(url.toString());
16419      var i, n, allowed = false;
16420      // Ensure that at least one item from the whitelist allows this url.
16421      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
16422        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
16423          allowed = true;
16424          break;
16425        }
16426      }
16427      if (allowed) {
16428        // Ensure that no item from the blacklist blocked this url.
16429        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
16430          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
16431            allowed = false;
16432            break;
16433          }
16434        }
16435      }
16436      return allowed;
16437    }
16438
16439    function generateHolderType(Base) {
16440      var holderType = function TrustedValueHolderType(trustedValue) {
16441        this.$$unwrapTrustedValue = function() {
16442          return trustedValue;
16443        };
16444      };
16445      if (Base) {
16446        holderType.prototype = new Base();
16447      }
16448      holderType.prototype.valueOf = function sceValueOf() {
16449        return this.$$unwrapTrustedValue();
16450      };
16451      holderType.prototype.toString = function sceToString() {
16452        return this.$$unwrapTrustedValue().toString();
16453      };
16454      return holderType;
16455    }
16456
16457    var trustedValueHolderBase = generateHolderType(),
16458        byType = {};
16459
16460    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
16461    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
16462    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
16463    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
16464    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
16465
16466    /**
16467     * @ngdoc method
16468     * @name $sceDelegate#trustAs
16469     *
16470     * @description
16471     * Returns an object that is trusted by angular for use in specified strict
16472     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
16473     * attribute interpolation, any dom event binding attribute interpolation
16474     * such as for onclick,  etc.) that uses the provided value.
16475     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
16476     *
16477     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
16478     *   resourceUrl, html, js and css.
16479     * @param {*} value The value that that should be considered trusted/safe.
16480     * @returns {*} A value that can be used to stand in for the provided `value` in places
16481     * where Angular expects a $sce.trustAs() return value.
16482     */
16483    function trustAs(type, trustedValue) {
16484      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16485      if (!Constructor) {
16486        throw $sceMinErr('icontext',
16487            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
16488            type, trustedValue);
16489      }
16490      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
16491        return trustedValue;
16492      }
16493      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
16494      // mutable objects, we ensure here that the value passed in is actually a string.
16495      if (typeof trustedValue !== 'string') {
16496        throw $sceMinErr('itype',
16497            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
16498            type);
16499      }
16500      return new Constructor(trustedValue);
16501    }
16502
16503    /**
16504     * @ngdoc method
16505     * @name $sceDelegate#valueOf
16506     *
16507     * @description
16508     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
16509     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
16510     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
16511     *
16512     * If the passed parameter is not a value that had been returned by {@link
16513     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
16514     *
16515     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
16516     *      call or anything else.
16517     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
16518     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
16519     *     `value` unchanged.
16520     */
16521    function valueOf(maybeTrusted) {
16522      if (maybeTrusted instanceof trustedValueHolderBase) {
16523        return maybeTrusted.$$unwrapTrustedValue();
16524      } else {
16525        return maybeTrusted;
16526      }
16527    }
16528
16529    /**
16530     * @ngdoc method
16531     * @name $sceDelegate#getTrusted
16532     *
16533     * @description
16534     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
16535     * returns the originally supplied value if the queried context type is a supertype of the
16536     * created type.  If this condition isn't satisfied, throws an exception.
16537     *
16538     * @param {string} type The kind of context in which this value is to be used.
16539     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
16540     *     `$sceDelegate.trustAs`} call.
16541     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
16542     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
16543     */
16544    function getTrusted(type, maybeTrusted) {
16545      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
16546        return maybeTrusted;
16547      }
16548      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
16549      if (constructor && maybeTrusted instanceof constructor) {
16550        return maybeTrusted.$$unwrapTrustedValue();
16551      }
16552      // If we get here, then we may only take one of two actions.
16553      // 1. sanitize the value for the requested type, or
16554      // 2. throw an exception.
16555      if (type === SCE_CONTEXTS.RESOURCE_URL) {
16556        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
16557          return maybeTrusted;
16558        } else {
16559          throw $sceMinErr('insecurl',
16560              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
16561              maybeTrusted.toString());
16562        }
16563      } else if (type === SCE_CONTEXTS.HTML) {
16564        return htmlSanitizer(maybeTrusted);
16565      }
16566      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
16567    }
16568
16569    return { trustAs: trustAs,
16570             getTrusted: getTrusted,
16571             valueOf: valueOf };
16572  }];
16573}
16574
16575
16576/**
16577 * @ngdoc provider
16578 * @name $sceProvider
16579 * @description
16580 *
16581 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
16582 * -   enable/disable Strict Contextual Escaping (SCE) in a module
16583 * -   override the default implementation with a custom delegate
16584 *
16585 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
16586 */
16587
16588/* jshint maxlen: false*/
16589
16590/**
16591 * @ngdoc service
16592 * @name $sce
16593 * @kind function
16594 *
16595 * @description
16596 *
16597 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
16598 *
16599 * # Strict Contextual Escaping
16600 *
16601 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
16602 * contexts to result in a value that is marked as safe to use for that context.  One example of
16603 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
16604 * to these contexts as privileged or SCE contexts.
16605 *
16606 * As of version 1.2, Angular ships with SCE enabled by default.
16607 *
16608 * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
16609 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
16610 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
16611 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
16612 * to the top of your HTML document.
16613 *
16614 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
16615 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
16616 *
16617 * Here's an example of a binding in a privileged context:
16618 *
16619 * ```
16620 * <input ng-model="userHtml" aria-label="User input">
16621 * <div ng-bind-html="userHtml"></div>
16622 * ```
16623 *
16624 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
16625 * disabled, this application allows the user to render arbitrary HTML into the DIV.
16626 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
16627 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
16628 * security vulnerabilities.)
16629 *
16630 * For the case of HTML, you might use a library, either on the client side, or on the server side,
16631 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
16632 *
16633 * How would you ensure that every place that used these types of bindings was bound to a value that
16634 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
16635 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
16636 * properties/fields and forgot to update the binding to the sanitized value?
16637 *
16638 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
16639 * determine that something explicitly says it's safe to use a value for binding in that
16640 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
16641 * for those values that you can easily tell are safe - because they were received from your server,
16642 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
16643 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
16644 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
16645 *
16646 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
16647 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
16648 * obtain values that will be accepted by SCE / privileged contexts.
16649 *
16650 *
16651 * ## How does it work?
16652 *
16653 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
16654 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
16655 * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
16656 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
16657 *
16658 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
16659 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
16660 * simplified):
16661 *
16662 * ```
16663 * var ngBindHtmlDirective = ['$sce', function($sce) {
16664 *   return function(scope, element, attr) {
16665 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
16666 *       element.html(value || '');
16667 *     });
16668 *   };
16669 * }];
16670 * ```
16671 *
16672 * ## Impact on loading templates
16673 *
16674 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
16675 * `templateUrl`'s specified by {@link guide/directive directives}.
16676 *
16677 * By default, Angular only loads templates from the same domain and protocol as the application
16678 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
16679 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
16680 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
16681 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
16682 *
16683 * *Please note*:
16684 * The browser's
16685 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
16686 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
16687 * policy apply in addition to this and may further restrict whether the template is successfully
16688 * loaded.  This means that without the right CORS policy, loading templates from a different domain
16689 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
16690 * browsers.
16691 *
16692 * ## This feels like too much overhead
16693 *
16694 * It's important to remember that SCE only applies to interpolation expressions.
16695 *
16696 * If your expressions are constant literals, they're automatically trusted and you don't need to
16697 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
16698 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
16699 *
16700 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
16701 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
16702 *
16703 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
16704 * templates in `ng-include` from your application's domain without having to even know about SCE.
16705 * It blocks loading templates from other domains or loading templates over http from an https
16706 * served document.  You can change these by setting your own custom {@link
16707 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
16708 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
16709 *
16710 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
16711 * application that's secure and can be audited to verify that with much more ease than bolting
16712 * security onto an application later.
16713 *
16714 * <a name="contexts"></a>
16715 * ## What trusted context types are supported?
16716 *
16717 * | Context             | Notes          |
16718 * |---------------------|----------------|
16719 * | `$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. |
16720 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
16721 * | `$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. |
16722 * | `$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. |
16723 * | `$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. |
16724 *
16725 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
16726 *
16727 *  Each element in these arrays must be one of the following:
16728 *
16729 *  - **'self'**
16730 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
16731 *      domain** as the application document using the **same protocol**.
16732 *  - **String** (except the special value `'self'`)
16733 *    - The string is matched against the full *normalized / absolute URL* of the resource
16734 *      being tested (substring matches are not good enough.)
16735 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
16736 *      match themselves.
16737 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
16738 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
16739 *      in a whitelist.
16740 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
16741 *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
16742 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
16743 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
16744 *      http://foo.example.com/templates/**).
16745 *  - **RegExp** (*see caveat below*)
16746 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
16747 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
16748 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
16749 *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
16750 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
16751 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
16752 *      is highly recommended to use the string patterns and only fall back to regular expressions
16753 *      if they as a last resort.
16754 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
16755 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
16756 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
16757 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
16758 *    - If you are generating your JavaScript from some other templating engine (not
16759 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
16760 *      remember to escape your regular expression (and be aware that you might need more than
16761 *      one level of escaping depending on your templating engine and the way you interpolated
16762 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
16763 *      enough before coding your own.  e.g. Ruby has
16764 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
16765 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
16766 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
16767 *      Closure library's [goog.string.regExpEscape(s)](
16768 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
16769 *
16770 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
16771 *
16772 * ## Show me an example using SCE.
16773 *
16774 * <example module="mySceApp" deps="angular-sanitize.js">
16775 * <file name="index.html">
16776 *   <div ng-controller="AppController as myCtrl">
16777 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
16778 *     <b>User comments</b><br>
16779 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
16780 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
16781 *     exploit.
16782 *     <div class="well">
16783 *       <div ng-repeat="userComment in myCtrl.userComments">
16784 *         <b>{{userComment.name}}</b>:
16785 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
16786 *         <br>
16787 *       </div>
16788 *     </div>
16789 *   </div>
16790 * </file>
16791 *
16792 * <file name="script.js">
16793 *   angular.module('mySceApp', ['ngSanitize'])
16794 *     .controller('AppController', ['$http', '$templateCache', '$sce',
16795 *       function($http, $templateCache, $sce) {
16796 *         var self = this;
16797 *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
16798 *           self.userComments = userComments;
16799 *         });
16800 *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
16801 *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
16802 *             'sanitization.&quot;">Hover over this text.</span>');
16803 *       }]);
16804 * </file>
16805 *
16806 * <file name="test_data.json">
16807 * [
16808 *   { "name": "Alice",
16809 *     "htmlComment":
16810 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
16811 *   },
16812 *   { "name": "Bob",
16813 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
16814 *   }
16815 * ]
16816 * </file>
16817 *
16818 * <file name="protractor.js" type="protractor">
16819 *   describe('SCE doc demo', function() {
16820 *     it('should sanitize untrusted values', function() {
16821 *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
16822 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
16823 *     });
16824 *
16825 *     it('should NOT sanitize explicitly trusted values', function() {
16826 *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
16827 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
16828 *           'sanitization.&quot;">Hover over this text.</span>');
16829 *     });
16830 *   });
16831 * </file>
16832 * </example>
16833 *
16834 *
16835 *
16836 * ## Can I disable SCE completely?
16837 *
16838 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
16839 * for little coding overhead.  It will be much harder to take an SCE disabled application and
16840 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
16841 * for cases where you have a lot of existing code that was written before SCE was introduced and
16842 * you're migrating them a module at a time.
16843 *
16844 * That said, here's how you can completely disable SCE:
16845 *
16846 * ```
16847 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
16848 *   // Completely disable SCE.  For demonstration purposes only!
16849 *   // Do not use in new projects.
16850 *   $sceProvider.enabled(false);
16851 * });
16852 * ```
16853 *
16854 */
16855/* jshint maxlen: 100 */
16856
16857function $SceProvider() {
16858  var enabled = true;
16859
16860  /**
16861   * @ngdoc method
16862   * @name $sceProvider#enabled
16863   * @kind function
16864   *
16865   * @param {boolean=} value If provided, then enables/disables SCE.
16866   * @return {boolean} true if SCE is enabled, false otherwise.
16867   *
16868   * @description
16869   * Enables/disables SCE and returns the current value.
16870   */
16871  this.enabled = function(value) {
16872    if (arguments.length) {
16873      enabled = !!value;
16874    }
16875    return enabled;
16876  };
16877
16878
16879  /* Design notes on the default implementation for SCE.
16880   *
16881   * The API contract for the SCE delegate
16882   * -------------------------------------
16883   * The SCE delegate object must provide the following 3 methods:
16884   *
16885   * - trustAs(contextEnum, value)
16886   *     This method is used to tell the SCE service that the provided value is OK to use in the
16887   *     contexts specified by contextEnum.  It must return an object that will be accepted by
16888   *     getTrusted() for a compatible contextEnum and return this value.
16889   *
16890   * - valueOf(value)
16891   *     For values that were not produced by trustAs(), return them as is.  For values that were
16892   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
16893   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
16894   *     such a value.
16895   *
16896   * - getTrusted(contextEnum, value)
16897   *     This function should return the a value that is safe to use in the context specified by
16898   *     contextEnum or throw and exception otherwise.
16899   *
16900   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
16901   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
16902   * instance, an implementation could maintain a registry of all trusted objects by context.  In
16903   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
16904   * return the same object passed in if it was found in the registry under a compatible context or
16905   * throw an exception otherwise.  An implementation might only wrap values some of the time based
16906   * on some criteria.  getTrusted() might return a value and not throw an exception for special
16907   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
16908   *
16909   *
16910   * A note on the inheritance model for SCE contexts
16911   * ------------------------------------------------
16912   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
16913   * is purely an implementation details.
16914   *
16915   * The contract is simply this:
16916   *
16917   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
16918   *     will also succeed.
16919   *
16920   * Inheritance happens to capture this in a natural way.  In some future, we
16921   * may not use inheritance anymore.  That is OK because no code outside of
16922   * sce.js and sceSpecs.js would need to be aware of this detail.
16923   */
16924
16925  this.$get = ['$parse', '$sceDelegate', function(
16926                $parse,   $sceDelegate) {
16927    // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
16928    // the "expression(javascript expression)" syntax which is insecure.
16929    if (enabled && msie < 8) {
16930      throw $sceMinErr('iequirks',
16931        'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
16932        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
16933        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
16934    }
16935
16936    var sce = shallowCopy(SCE_CONTEXTS);
16937
16938    /**
16939     * @ngdoc method
16940     * @name $sce#isEnabled
16941     * @kind function
16942     *
16943     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
16944     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
16945     *
16946     * @description
16947     * Returns a boolean indicating if SCE is enabled.
16948     */
16949    sce.isEnabled = function() {
16950      return enabled;
16951    };
16952    sce.trustAs = $sceDelegate.trustAs;
16953    sce.getTrusted = $sceDelegate.getTrusted;
16954    sce.valueOf = $sceDelegate.valueOf;
16955
16956    if (!enabled) {
16957      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
16958      sce.valueOf = identity;
16959    }
16960
16961    /**
16962     * @ngdoc method
16963     * @name $sce#parseAs
16964     *
16965     * @description
16966     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
16967     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
16968     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
16969     * *result*)}
16970     *
16971     * @param {string} type The kind of SCE context in which this result will be used.
16972     * @param {string} expression String expression to compile.
16973     * @returns {function(context, locals)} a function which represents the compiled expression:
16974     *
16975     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
16976     *      are evaluated against (typically a scope object).
16977     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
16978     *      `context`.
16979     */
16980    sce.parseAs = function sceParseAs(type, expr) {
16981      var parsed = $parse(expr);
16982      if (parsed.literal && parsed.constant) {
16983        return parsed;
16984      } else {
16985        return $parse(expr, function(value) {
16986          return sce.getTrusted(type, value);
16987        });
16988      }
16989    };
16990
16991    /**
16992     * @ngdoc method
16993     * @name $sce#trustAs
16994     *
16995     * @description
16996     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
16997     * returns an object that is trusted by angular for use in specified strict contextual
16998     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
16999     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
17000     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
17001     * escaping.
17002     *
17003     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
17004     *   resourceUrl, html, js and css.
17005     * @param {*} value The value that that should be considered trusted/safe.
17006     * @returns {*} A value that can be used to stand in for the provided `value` in places
17007     * where Angular expects a $sce.trustAs() return value.
17008     */
17009
17010    /**
17011     * @ngdoc method
17012     * @name $sce#trustAsHtml
17013     *
17014     * @description
17015     * Shorthand method.  `$sce.trustAsHtml(value)` →
17016     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
17017     *
17018     * @param {*} value The value to trustAs.
17019     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
17020     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
17021     *     only accept expressions that are either literal constants or are the
17022     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17023     */
17024
17025    /**
17026     * @ngdoc method
17027     * @name $sce#trustAsUrl
17028     *
17029     * @description
17030     * Shorthand method.  `$sce.trustAsUrl(value)` →
17031     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
17032     *
17033     * @param {*} value The value to trustAs.
17034     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
17035     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
17036     *     only accept expressions that are either literal constants or are the
17037     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17038     */
17039
17040    /**
17041     * @ngdoc method
17042     * @name $sce#trustAsResourceUrl
17043     *
17044     * @description
17045     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
17046     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
17047     *
17048     * @param {*} value The value to trustAs.
17049     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
17050     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
17051     *     only accept expressions that are either literal constants or are the return
17052     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
17053     */
17054
17055    /**
17056     * @ngdoc method
17057     * @name $sce#trustAsJs
17058     *
17059     * @description
17060     * Shorthand method.  `$sce.trustAsJs(value)` →
17061     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
17062     *
17063     * @param {*} value The value to trustAs.
17064     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
17065     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
17066     *     only accept expressions that are either literal constants or are the
17067     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
17068     */
17069
17070    /**
17071     * @ngdoc method
17072     * @name $sce#getTrusted
17073     *
17074     * @description
17075     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
17076     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
17077     * originally supplied value if the queried context type is a supertype of the created type.
17078     * If this condition isn't satisfied, throws an exception.
17079     *
17080     * @param {string} type The kind of context in which this value is to be used.
17081     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
17082     *                         call.
17083     * @returns {*} The value the was originally provided to
17084     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
17085     *              Otherwise, throws an exception.
17086     */
17087
17088    /**
17089     * @ngdoc method
17090     * @name $sce#getTrustedHtml
17091     *
17092     * @description
17093     * Shorthand method.  `$sce.getTrustedHtml(value)` →
17094     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
17095     *
17096     * @param {*} value The value to pass to `$sce.getTrusted`.
17097     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
17098     */
17099
17100    /**
17101     * @ngdoc method
17102     * @name $sce#getTrustedCss
17103     *
17104     * @description
17105     * Shorthand method.  `$sce.getTrustedCss(value)` →
17106     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
17107     *
17108     * @param {*} value The value to pass to `$sce.getTrusted`.
17109     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
17110     */
17111
17112    /**
17113     * @ngdoc method
17114     * @name $sce#getTrustedUrl
17115     *
17116     * @description
17117     * Shorthand method.  `$sce.getTrustedUrl(value)` →
17118     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
17119     *
17120     * @param {*} value The value to pass to `$sce.getTrusted`.
17121     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
17122     */
17123
17124    /**
17125     * @ngdoc method
17126     * @name $sce#getTrustedResourceUrl
17127     *
17128     * @description
17129     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
17130     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
17131     *
17132     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
17133     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
17134     */
17135
17136    /**
17137     * @ngdoc method
17138     * @name $sce#getTrustedJs
17139     *
17140     * @description
17141     * Shorthand method.  `$sce.getTrustedJs(value)` →
17142     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
17143     *
17144     * @param {*} value The value to pass to `$sce.getTrusted`.
17145     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
17146     */
17147
17148    /**
17149     * @ngdoc method
17150     * @name $sce#parseAsHtml
17151     *
17152     * @description
17153     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
17154     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
17155     *
17156     * @param {string} expression String expression to compile.
17157     * @returns {function(context, locals)} a function which represents the compiled expression:
17158     *
17159     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17160     *      are evaluated against (typically a scope object).
17161     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17162     *      `context`.
17163     */
17164
17165    /**
17166     * @ngdoc method
17167     * @name $sce#parseAsCss
17168     *
17169     * @description
17170     * Shorthand method.  `$sce.parseAsCss(value)` →
17171     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
17172     *
17173     * @param {string} expression String expression to compile.
17174     * @returns {function(context, locals)} a function which represents the compiled expression:
17175     *
17176     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17177     *      are evaluated against (typically a scope object).
17178     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17179     *      `context`.
17180     */
17181
17182    /**
17183     * @ngdoc method
17184     * @name $sce#parseAsUrl
17185     *
17186     * @description
17187     * Shorthand method.  `$sce.parseAsUrl(value)` →
17188     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
17189     *
17190     * @param {string} expression String expression to compile.
17191     * @returns {function(context, locals)} a function which represents the compiled expression:
17192     *
17193     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17194     *      are evaluated against (typically a scope object).
17195     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17196     *      `context`.
17197     */
17198
17199    /**
17200     * @ngdoc method
17201     * @name $sce#parseAsResourceUrl
17202     *
17203     * @description
17204     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
17205     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
17206     *
17207     * @param {string} expression String expression to compile.
17208     * @returns {function(context, locals)} a function which represents the compiled expression:
17209     *
17210     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17211     *      are evaluated against (typically a scope object).
17212     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17213     *      `context`.
17214     */
17215
17216    /**
17217     * @ngdoc method
17218     * @name $sce#parseAsJs
17219     *
17220     * @description
17221     * Shorthand method.  `$sce.parseAsJs(value)` →
17222     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
17223     *
17224     * @param {string} expression String expression to compile.
17225     * @returns {function(context, locals)} a function which represents the compiled expression:
17226     *
17227     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
17228     *      are evaluated against (typically a scope object).
17229     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
17230     *      `context`.
17231     */
17232
17233    // Shorthand delegations.
17234    var parse = sce.parseAs,
17235        getTrusted = sce.getTrusted,
17236        trustAs = sce.trustAs;
17237
17238    forEach(SCE_CONTEXTS, function(enumValue, name) {
17239      var lName = lowercase(name);
17240      sce[camelCase("parse_as_" + lName)] = function(expr) {
17241        return parse(enumValue, expr);
17242      };
17243      sce[camelCase("get_trusted_" + lName)] = function(value) {
17244        return getTrusted(enumValue, value);
17245      };
17246      sce[camelCase("trust_as_" + lName)] = function(value) {
17247        return trustAs(enumValue, value);
17248      };
17249    });
17250
17251    return sce;
17252  }];
17253}
17254
17255/**
17256 * !!! This is an undocumented "private" service !!!
17257 *
17258 * @name $sniffer
17259 * @requires $window
17260 * @requires $document
17261 *
17262 * @property {boolean} history Does the browser support html5 history api ?
17263 * @property {boolean} transitions Does the browser support CSS transition events ?
17264 * @property {boolean} animations Does the browser support CSS animation events ?
17265 *
17266 * @description
17267 * This is very simple implementation of testing browser's features.
17268 */
17269function $SnifferProvider() {
17270  this.$get = ['$window', '$document', function($window, $document) {
17271    var eventSupport = {},
17272        android =
17273          toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
17274        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
17275        document = $document[0] || {},
17276        vendorPrefix,
17277        vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
17278        bodyStyle = document.body && document.body.style,
17279        transitions = false,
17280        animations = false,
17281        match;
17282
17283    if (bodyStyle) {
17284      for (var prop in bodyStyle) {
17285        if (match = vendorRegex.exec(prop)) {
17286          vendorPrefix = match[0];
17287          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
17288          break;
17289        }
17290      }
17291
17292      if (!vendorPrefix) {
17293        vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
17294      }
17295
17296      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
17297      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
17298
17299      if (android && (!transitions ||  !animations)) {
17300        transitions = isString(bodyStyle.webkitTransition);
17301        animations = isString(bodyStyle.webkitAnimation);
17302      }
17303    }
17304
17305
17306    return {
17307      // Android has history.pushState, but it does not update location correctly
17308      // so let's not use the history API at all.
17309      // http://code.google.com/p/android/issues/detail?id=17471
17310      // https://github.com/angular/angular.js/issues/904
17311
17312      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
17313      // so let's not use the history API also
17314      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
17315      // jshint -W018
17316      history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
17317      // jshint +W018
17318      hasEvent: function(event) {
17319        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
17320        // it. In particular the event is not fired when backspace or delete key are pressed or
17321        // when cut operation is performed.
17322        // IE10+ implements 'input' event but it erroneously fires under various situations,
17323        // e.g. when placeholder changes, or a form is focused.
17324        if (event === 'input' && msie <= 11) return false;
17325
17326        if (isUndefined(eventSupport[event])) {
17327          var divElm = document.createElement('div');
17328          eventSupport[event] = 'on' + event in divElm;
17329        }
17330
17331        return eventSupport[event];
17332      },
17333      csp: csp(),
17334      vendorPrefix: vendorPrefix,
17335      transitions: transitions,
17336      animations: animations,
17337      android: android
17338    };
17339  }];
17340}
17341
17342var $compileMinErr = minErr('$compile');
17343
17344/**
17345 * @ngdoc service
17346 * @name $templateRequest
17347 *
17348 * @description
17349 * The `$templateRequest` service downloads the provided template using `$http` and, upon success,
17350 * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
17351 * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
17352 * by setting the 2nd parameter of the function to true).
17353 *
17354 * @param {string} tpl The HTTP request template URL
17355 * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
17356 *
17357 * @return {Promise} a promise for the HTTP response data of the given URL.
17358 *
17359 * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
17360 */
17361function $TemplateRequestProvider() {
17362  this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
17363    function handleRequestFn(tpl, ignoreRequestError) {
17364      handleRequestFn.totalPendingRequests++;
17365
17366      var transformResponse = $http.defaults && $http.defaults.transformResponse;
17367
17368      if (isArray(transformResponse)) {
17369        transformResponse = transformResponse.filter(function(transformer) {
17370          return transformer !== defaultHttpResponseTransform;
17371        });
17372      } else if (transformResponse === defaultHttpResponseTransform) {
17373        transformResponse = null;
17374      }
17375
17376      var httpOptions = {
17377        cache: $templateCache,
17378        transformResponse: transformResponse
17379      };
17380
17381      return $http.get(tpl, httpOptions)
17382        ['finally'](function() {
17383          handleRequestFn.totalPendingRequests--;
17384        })
17385        .then(function(response) {
17386          $templateCache.put(tpl, response.data);
17387          return response.data;
17388        }, handleError);
17389
17390      function handleError(resp) {
17391        if (!ignoreRequestError) {
17392          throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
17393            tpl, resp.status, resp.statusText);
17394        }
17395        return $q.reject(resp);
17396      }
17397    }
17398
17399    handleRequestFn.totalPendingRequests = 0;
17400
17401    return handleRequestFn;
17402  }];
17403}
17404
vendor: 5,440 bytes, lines 17405-17558
17405function $$TestabilityProvider() {
17406  this.$get = ['$rootScope', '$browser', '$location',
17407       function($rootScope,   $browser,   $location) {
17408
17409    /**
17410     * @name $testability
17411     *
17412     * @description
17413     * The private $$testability service provides a collection of methods for use when debugging
17414     * or by automated test and debugging tools.
17415     */
17416    var testability = {};
17417
17418    /**
17419     * @name $$testability#findBindings
17420     *
17421     * @description
17422     * Returns an array of elements that are bound (via ng-bind or {{}})
17423     * to expressions matching the input.
17424     *
17425     * @param {Element} element The element root to search from.
17426     * @param {string} expression The binding expression to match.
17427     * @param {boolean} opt_exactMatch If true, only returns exact matches
17428     *     for the expression. Filters and whitespace are ignored.
17429     */
17430    testability.findBindings = function(element, expression, opt_exactMatch) {
17431      var bindings = element.getElementsByClassName('ng-binding');
17432      var matches = [];
17433      forEach(bindings, function(binding) {
17434        var dataBinding = angular.element(binding).data('$binding');
17435        if (dataBinding) {
17436          forEach(dataBinding, function(bindingName) {
17437            if (opt_exactMatch) {
17438              var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
17439              if (matcher.test(bindingName)) {
17440                matches.push(binding);
17441              }
17442            } else {
17443              if (bindingName.indexOf(expression) != -1) {
17444                matches.push(binding);
17445              }
17446            }
17447          });
17448        }
17449      });
17450      return matches;
17451    };
17452
17453    /**
17454     * @name $$testability#findModels
17455     *
17456     * @description
17457     * Returns an array of elements that are two-way found via ng-model to
17458     * expressions matching the input.
17459     *
17460     * @param {Element} element The element root to search from.
17461     * @param {string} expression The model expression to match.
17462     * @param {boolean} opt_exactMatch If true, only returns exact matches
17463     *     for the expression.
17464     */
17465    testability.findModels = function(element, expression, opt_exactMatch) {
17466      var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
17467      for (var p = 0; p < prefixes.length; ++p) {
17468        var attributeEquals = opt_exactMatch ? '=' : '*=';
17469        var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
17470        var elements = element.querySelectorAll(selector);
17471        if (elements.length) {
17472          return elements;
17473        }
17474      }
17475    };
17476
17477    /**
17478     * @name $$testability#getLocation
17479     *
17480     * @description
17481     * Shortcut for getting the location in a browser agnostic way. Returns
17482     *     the path, search, and hash. (e.g. /path?a=b#hash)
17483     */
17484    testability.getLocation = function() {
17485      return $location.url();
17486    };
17487
17488    /**
17489     * @name $$testability#setLocation
17490     *
17491     * @description
17492     * Shortcut for navigating to a location without doing a full page reload.
17493     *
17494     * @param {string} url The location url (path, search and hash,
17495     *     e.g. /path?a=b#hash) to go to.
17496     */
17497    testability.setLocation = function(url) {
17498      if (url !== $location.url()) {
17499        $location.url(url);
17500        $rootScope.$digest();
17501      }
17502    };
17503
17504    /**
17505     * @name $$testability#whenStable
17506     *
17507     * @description
17508     * Calls the callback when $timeout and $http requests are completed.
17509     *
17510     * @param {function} callback
17511     */
17512    testability.whenStable = function(callback) {
17513      $browser.notifyWhenNoOutstandingRequests(callback);
17514    };
17515
17516    return testability;
17517  }];
17518}
17519
17520function $TimeoutProvider() {
17521  this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
17522       function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
17523
17524    var deferreds = {};
17525
17526
17527     /**
17528      * @ngdoc service
17529      * @name $timeout
17530      *
17531      * @description
17532      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
17533      * block and delegates any exceptions to
17534      * {@link ng.$exceptionHandler $exceptionHandler} service.
17535      *
17536      * The return value of calling `$timeout` is a promise, which will be resolved when
17537      * the delay has passed and the timeout function, if provided, is executed.
17538      *
17539      * To cancel a timeout request, call `$timeout.cancel(promise)`.
17540      *
17541      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
17542      * synchronously flush the queue of deferred functions.
17543      *
17544      * If you only want a promise that will be resolved after some specified delay
17545      * then you can call `$timeout` without the `fn` function.
17546      *
17547      * @param {function()=} fn A function, whose execution should be delayed.
17548      * @param {number=} [delay=0] Delay in milliseconds.
17549      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
17550      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
17551      * @param {...*=} Pass additional parameters to the executed function.
17552      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
17553      *   promise will be resolved with is the return value of the `fn` function.
17554      *
17555      */
17556    function timeout(fn, delay, invokeApply) {
17557      if (!isFunction(fn)) {
17558        invokeApply = delay;
17559        delay = fn;
17560        fn = noop;
17561      }
17562
17563      var args = sliceArgs(arguments, 3),
17564          skipApply = (isDefined(invokeApply) && !invokeApply),
17565          deferred = (skipApply ? $$q : $q).defer(),
17566          promise = deferred.promise,
17567          timeoutId;
17568
17569      timeoutId = $browser.defer(function() {
17570        try {
17571          deferred.resolve(fn.apply(null, args));
17572        } catch (e) {
17573          deferred.reject(e);
17574          $exceptionHandler(e);
17575        }
17576        finally {
17577          delete deferreds[promise.$$timeoutId];
17578        }
17579
17580        if (!skipApply) $rootScope.$apply();
17581      }, delay);
17582
17583      promise.$$timeoutId = timeoutId;
17584      deferreds[timeoutId] = deferred;
17585
17586      return promise;
17587    }
17588
17589
17590     /**
17591      * @ngdoc method
17592      * @name $timeout#cancel
17593      *
17594      * @description
17595      * Cancels a task associated with the `promise`. As a result of this, the promise will be
17596      * resolved with a rejection.
17597      *
17598      * @param {Promise=} promise Promise returned by the `$timeout` function.
17599      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
17600      *   canceled.
17601      */
17602    timeout.cancel = function(promise) {
17603      if (promise && promise.$$timeoutId in deferreds) {
17604        deferreds[promise.$$timeoutId].reject('canceled');
17605        delete deferreds[promise.$$timeoutId];
17606        return $browser.defer.cancel(promise.$$timeoutId);
17607      }
17608      return false;
17609    };
17610
17611    return timeout;
17612  }];
17613}
17614
17615// NOTE:  The usage of window and document instead of $window and $document here is
17616// deliberate.  This service depends on the specific behavior of anchor nodes created by the
17617// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
17618// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
17619// doesn't know about mocked locations and resolves URLs to the real document - which is
17620// exactly the behavior needed here.  There is little value is mocking these out for this
17621// service.
17622var urlParsingNode = document.createElement("a");
17623var originUrl = urlResolve(window.location.href);
17624
17625
17626/**
17627 *
17628 * Implementation Notes for non-IE browsers
17629 * ----------------------------------------
17630 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
17631 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
17632 * URL will be resolved into an absolute URL in the context of the application document.
17633 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
17634 * properties are all populated to reflect the normalized URL.  This approach has wide
17635 * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
17636 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
17637 *
17638 * Implementation Notes for IE
17639 * ---------------------------
17640 * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
17641 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
17642 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
17643 * work around that by performing the parsing in a 2nd step by taking a previously normalized
17644 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
17645 * properties such as protocol, hostname, port, etc.
17646 *
17647 * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
17648 * uses the inner HTML approach to assign the URL as part of an HTML snippet -
17649 * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
17650 * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
17651 * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
17652 * method and IE < 8 is unsupported.
17653 *
17654 * References:
17655 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
17656 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
17657 *   http://url.spec.whatwg.org/#urlutils
17658 *   https://github.com/angular/angular.js/pull/2902
17659 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
17660 *
17661 * @kind function
17662 * @param {string} url The URL to be parsed.
17663 * @description Normalizes and parses a URL.
17664 * @returns {object} Returns the normalized URL as a dictionary.
17665 *
17666 *   | member name   | Description    |
17667 *   |---------------|----------------|
17668 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
17669 *   | protocol      | The protocol including the trailing colon                              |
17670 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
17671 *   | search        | The search params, minus the question mark                             |
17672 *   | hash          | The hash string, minus the hash symbol
17673 *   | hostname      | The hostname
17674 *   | port          | The port, without ":"
17675 *   | pathname      | The pathname, beginning with "/"
17676 *
17677 */
17678function urlResolve(url) {
17679  var href = url;
17680
17681  if (msie) {
17682    // Normalize before parse.  Refer Implementation Notes on why this is
17683    // done in two steps on IE.
17684    urlParsingNode.setAttribute("href", href);
17685    href = urlParsingNode.href;
17686  }
17687
17688  urlParsingNode.setAttribute('href', href);
17689
17690  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
17691  return {
17692    href: urlParsingNode.href,
17693    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
17694    host: urlParsingNode.host,
17695    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
17696    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
17697    hostname: urlParsingNode.hostname,
17698    port: urlParsingNode.port,
17699    pathname: (urlParsingNode.pathname.charAt(0) === '/')
17700      ? urlParsingNode.pathname
17701      : '/' + urlParsingNode.pathname
17702  };
17703}
17704
17705/**
17706 * Parse a request URL and determine whether this is a same-origin request as the application document.
17707 *
17708 * @param {string|object} requestUrl The url of the request as a string that will be resolved
17709 * or a parsed URL object.
17710 * @returns {boolean} Whether the request is for the same origin as the application document.
17711 */
17712function urlIsSameOrigin(requestUrl) {
17713  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
17714  return (parsed.protocol === originUrl.protocol &&
17715          parsed.host === originUrl.host);
17716}
17717
17718/**
17719 * @ngdoc service
17720 * @name $window
17721 *
17722 * @description
17723 * A reference to the browser's `window` object. While `window`
17724 * is globally available in JavaScript, it causes testability problems, because
17725 * it is a global variable. In angular we always refer to it through the
17726 * `$window` service, so it may be overridden, removed or mocked for testing.
17727 *
17728 * Expressions, like the one defined for the `ngClick` directive in the example
17729 * below, are evaluated with respect to the current scope.  Therefore, there is
17730 * no risk of inadvertently coding in a dependency on a global value in such an
17731 * expression.
17732 *
17733 * @example
17734   <example module="windowExample">
17735     <file name="index.html">
17736       <script>
17737         angular.module('windowExample', [])
17738           .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
17739             $scope.greeting = 'Hello, World!';
17740             $scope.doGreeting = function(greeting) {
17741               $window.alert(greeting);
17742             };
17743           }]);
17744       </script>
17745       <div ng-controller="ExampleController">
17746         <input type="text" ng-model="greeting" aria-label="greeting" />
17747         <button ng-click="doGreeting(greeting)">ALERT</button>
17748       </div>
17749     </file>
17750     <file name="protractor.js" type="protractor">
17751      it('should display the greeting in the input box', function() {
17752       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
17753       // If we click the button it will block the test runner
17754       // element(':button').click();
17755      });
17756     </file>
17757   </example>
17758 */
17759function $WindowProvider() {
17760  this.$get = valueFn(window);
17761}
17762
17763/**
17764 * @name $$cookieReader
17765 * @requires $document
17766 *
17767 * @description
17768 * This is a private service for reading cookies used by $http and ngCookies
17769 *
17770 * @return {Object} a key/value map of the current cookies
17771 */
17772function $$CookieReader($document) {
17773  var rawDocument = $document[0] || {};
17774  var lastCookies = {};
17775  var lastCookieString = '';
17776
17777  function safeDecodeURIComponent(str) {
17778    try {
17779      return decodeURIComponent(str);
17780    } catch (e) {
17781      return str;
17782    }
17783  }
17784
17785  return function() {
17786    var cookieArray, cookie, i, index, name;
17787    var currentCookieString = rawDocument.cookie || '';
17788
17789    if (currentCookieString !== lastCookieString) {
17790      lastCookieString = currentCookieString;
17791      cookieArray = lastCookieString.split('; ');
17792      lastCookies = {};
17793
17794      for (i = 0; i < cookieArray.length; i++) {
17795        cookie = cookieArray[i];
17796        index = cookie.indexOf('=');
17797        if (index > 0) { //ignore nameless cookies
17798          name = safeDecodeURIComponent(cookie.substring(0, index));
17799          // the first value that is seen for a cookie is the most
17800          // specific one.  values for the same cookie name that
17801          // follow are for less specific paths.
17802          if (lastCookies[name] === undefined) {
17803            lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
17804          }
17805        }
17806      }
17807    }
17808    return lastCookies;
17809  };
17810}
17811
17812$$CookieReader.$inject = ['$document'];
17813
17814function $$CookieReaderProvider() {
17815  this.$get = $$CookieReader;
17816}
17817
17818/* global currencyFilter: true,
17819 dateFilter: true,
17820 filterFilter: true,
17821 jsonFilter: true,
17822 limitToFilter: true,
17823 lowercaseFilter: true,
17824 numberFilter: true,
17825 orderByFilter: true,
17826 uppercaseFilter: true,
17827 */
17828
17829/**
17830 * @ngdoc provider
17831 * @name $filterProvider
17832 * @description
17833 *
17834 * Filters are just functions which transform input to an output. However filters need to be
17835 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
17836 * annotated with dependencies and is responsible for creating a filter function.
17837 *
17838 * <div class="alert alert-warning">
17839 * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
17840 * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
17841 * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
17842 * (`myapp_subsection_filterx`).
17843 * </div>
17844 *
17845 * ```js
17846 *   // Filter registration
17847 *   function MyModule($provide, $filterProvider) {
17848 *     // create a service to demonstrate injection (not always needed)
17849 *     $provide.value('greet', function(name){
17850 *       return 'Hello ' + name + '!';
17851 *     });
17852 *
17853 *     // register a filter factory which uses the
17854 *     // greet service to demonstrate DI.
17855 *     $filterProvider.register('greet', function(greet){
17856 *       // return the filter function which uses the greet service
17857 *       // to generate salutation
17858 *       return function(text) {
17859 *         // filters need to be forgiving so check input validity
17860 *         return text && greet(text) || text;
17861 *       };
17862 *     });
17863 *   }
17864 * ```
17865 *
17866 * The filter function is registered with the `$injector` under the filter name suffix with
17867 * `Filter`.
17868 *
17869 * ```js
17870 *   it('should be the same instance', inject(
17871 *     function($filterProvider) {
17872 *       $filterProvider.register('reverse', function(){
17873 *         return ...;
17874 *       });
17875 *     },
17876 *     function($filter, reverseFilter) {
17877 *       expect($filter('reverse')).toBe(reverseFilter);
17878 *     });
17879 * ```
17880 *
17881 *
17882 * For more information about how angular filters work, and how to create your own filters, see
17883 * {@link guide/filter Filters} in the Angular Developer Guide.
17884 */
17885
17886/**
17887 * @ngdoc service
17888 * @name $filter
17889 * @kind function
17890 * @description
17891 * Filters are used for formatting data displayed to the user.
17892 *
17893 * The general syntax in templates is as follows:
17894 *
17895 *         {{ expression [| filter_name[:parameter_value] ... ] }}
17896 *
17897 * @param {String} name Name of the filter function to retrieve
17898 * @return {Function} the filter function
17899 * @example
17900   <example name="$filter" module="filterExample">
17901     <file name="index.html">
17902       <div ng-controller="MainCtrl">
17903        <h3>{{ originalText }}</h3>
17904        <h3>{{ filteredText }}</h3>
17905       </div>
17906     </file>
17907
17908     <file name="script.js">
17909      angular.module('filterExample', [])
17910      .controller('MainCtrl', function($scope, $filter) {
17911        $scope.originalText = 'hello';
17912        $scope.filteredText = $filter('uppercase')($scope.originalText);
17913      });
17914     </file>
17915   </example>
17916  */
17917$FilterProvider.$inject = ['$provide'];
17918function $FilterProvider($provide) {
17919  var suffix = 'Filter';
17920
17921  /**
17922   * @ngdoc method
17923   * @name $filterProvider#register
17924   * @param {string|Object} name Name of the filter function, or an object map of filters where
17925   *    the keys are the filter names and the values are the filter factories.
17926   *
17927   *    <div class="alert alert-warning">
17928   *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
17929   *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
17930   *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
17931   *    (`myapp_subsection_filterx`).
17932   *    </div>
17933   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
17934   *    of the registered filter instances.
17935   */
17936  function register(name, factory) {
17937    if (isObject(name)) {
17938      var filters = {};
17939      forEach(name, function(filter, key) {
17940        filters[key] = register(key, filter);
17941      });
17942      return filters;
17943    } else {
17944      return $provide.factory(name + suffix, factory);
17945    }
17946  }
17947  this.register = register;
17948
17949  this.$get = ['$injector', function($injector) {
17950    return function(name) {
17951      return $injector.get(name + suffix);
17952    };
17953  }];
17954
17955  ////////////////////////////////////////
17956
17957  /* global
17958    currencyFilter: false,
17959    dateFilter: false,
17960    filterFilter: false,
17961    jsonFilter: false,
17962    limitToFilter: false,
17963    lowercaseFilter: false,
17964    numberFilter: false,
17965    orderByFilter: false,
17966    uppercaseFilter: false,
17967  */
17968
17969  register('currency', currencyFilter);
17970  register('date', dateFilter);
17971  register('filter', filterFilter);
17972  register('json', jsonFilter);
17973  register('limitTo', limitToFilter);
17974  register('lowercase', lowercaseFilter);
17975  register('number', numberFilter);
17976  register('orderBy', orderByFilter);
17977  register('uppercase', uppercaseFilter);
17978}
17979
17980/**
17981 * @ngdoc filter
17982 * @name filter
17983 * @kind function
17984 *
17985 * @description
17986 * Selects a subset of items from `array` and returns it as a new array.
17987 *
17988 * @param {Array} array The source array.
17989 * @param {string|Object|function()} expression The predicate to be used for selecting items from
17990 *   `array`.
17991 *
17992 *   Can be one of:
17993 *
17994 *   - `string`: The string is used for matching against the contents of the `array`. All strings or
17995 *     objects with string properties in `array` that match this string will be returned. This also
17996 *     applies to nested object properties.
17997 *     The predicate can be negated by prefixing the string with `!`.
17998 *
17999 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
18000 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
18001 *     which have property `name` containing "M" and property `phone` containing "1". A special
18002 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
18003 *     property of the object or its nested object properties. That's equivalent to the simple
18004 *     substring match with a `string` as described above. The predicate can be negated by prefixing
18005 *     the string with `!`.
18006 *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
18007 *     not containing "M".
18008 *
18009 *     Note that a named property will match properties on the same level only, while the special
18010 *     `$` property will match properties on the same level or deeper. E.g. an array item like
18011 *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
18012 *     **will** be matched by `{$: 'John'}`.
18013 *
18014 *   - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
18015 *     function is called for each element of `array`. The final result is an array of those
18016 *     elements that the predicate returned true for.
18017 *
18018 * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
18019 *     determining if the expected value (from the filter expression) and actual value (from
18020 *     the object in the array) should be considered a match.
18021 *
18022 *   Can be one of:
18023 *
18024 *   - `function(actual, expected)`:
18025 *     The function will be given the object value and the predicate value to compare and
18026 *     should return true if both values should be considered equal.
18027 *
18028 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
18029 *     This is essentially strict comparison of expected and actual.
18030 *
18031 *   - `false|undefined`: A short hand for a function which will look for a substring match in case
18032 *     insensitive way.
18033 *
18034 *     Primitive values are converted to strings. Objects are not compared against primitives,
18035 *     unless they have a custom `toString` method (e.g. `Date` objects).
18036 *
18037 * @example
18038   <example>
18039     <file name="index.html">
18040       <div ng-init="friends = [{name:'John', phone:'555-1276'},
18041                                {name:'Mary', phone:'800-BIG-MARY'},
18042                                {name:'Mike', phone:'555-4321'},
18043                                {name:'Adam', phone:'555-5678'},
18044                                {name:'Julie', phone:'555-8765'},
18045                                {name:'Juliette', phone:'555-5678'}]"></div>
18046
18047       <label>Search: <input ng-model="searchText"></label>
18048       <table id="searchTextResults">
18049         <tr><th>
18049Name</th><th>Phone</th></tr>
18050         <tr ng-repeat="friend in friends | filter:searchText">
18051           <td>{{friend.name}}</td>
18052           <td>{{friend.phone}}</td>
18053         </tr>
18054       </table>
18055       <hr>
18056       <label>Any: <input ng-model="search.$"></label> <br>
18057       <label>Name only <input ng-model="search.name"></label><br>
18058       <label>Phone only <input ng-model="search.phone"></label><br>
18059       <label>Equality <input type="checkbox" ng-model="strict"></label><br>
18060       <table id="searchObjResults">
18061         <tr><th>Name</th><th>Phone</th></tr>
18062         <tr ng-repeat="friendObj in friends | filter:search:strict">
18063           <td>{{friendObj.name}}</td>
18064           <td>{{friendObj.phone}}</td>
18065         </tr>
18066       </table>
18067     </file>
18068     <file name="protractor.js" type="protractor">
18069       var expectFriendNames = function(expectedNames, key) {
18070         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
18071           arr.forEach(function(wd, i) {
18072             expect(wd.getText()).toMatch(expectedNames[i]);
18073           });
18074         });
18075       };
18076
18077       it('should search across all fields when filtering with a string', function() {
18078         var searchText = element(by.model('searchText'));
18079         searchText.clear();
18080         searchText.sendKeys('m');
18081         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
18082
18083         searchText.clear();
18084         searchText.sendKeys('76');
18085         expectFriendNames(['John', 'Julie'], 'friend');
18086       });
18087
18088       it('should search in specific fields when filtering with a predicate object', function() {
18089         var searchAny = element(by.model('search.$'));
18090         searchAny.clear();
18091         searchAny.sendKeys('i');
18092         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
18093       });
18094       it('should use a equal comparison when comparator is true', function() {
18095         var searchName = element(by.model('search.name'));
18096         var strict = element(by.model('strict'));
18097         searchName.clear();
18098         searchName.sendKeys('Julie');
18099         strict.click();
18100         expectFriendNames(['Julie'], 'friendObj');
18101       });
18102     </file>
18103   </example>
18104 */
18105function filterFilter() {
18106  return function(array, expression, comparator) {
18107    if (!isArrayLike(array)) {
18108      if (array == null) {
18109        return array;
18110      } else {
18111        throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
18112      }
18113    }
18114
18115    var expressionType = getTypeForFilter(expression);
18116    var predicateFn;
18117    var matchAgainstAnyProp;
18118
18119    switch (expressionType) {
18120      case 'function':
18121        predicateFn = expression;
18122        break;
18123      case 'boolean':
18124      case 'null':
18125      case 'number':
18126      case 'string':
18127        matchAgainstAnyProp = true;
18128        //jshint -W086
18129      case 'object':
18130        //jshint +W086
18131        predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
18132        break;
18133      default:
18134        return array;
18135    }
18136
18137    return Array.prototype.filter.call(array, predicateFn);
18138  };
18139}
18140
18141function hasCustomToString(obj) {
18142  return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
18143}
18144
18145// Helper functions for `filterFilter`
18146function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
18147  var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
18148  var predicateFn;
18149
18150  if (comparator === true) {
18151    comparator = equals;
18152  } else if (!isFunction(comparator)) {
18153    comparator = function(actual, expected) {
18154      if (isUndefined(actual)) {
18155        // No substring matching against `undefined`
18156        return false;
18157      }
18158      if ((actual === null) || (expected === null)) {
18159        // No substring matching against `null`; only match against `null`
18160        return actual === expected;
18161      }
18162      if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
18163        // Should not compare primitives against objects, unless they have custom `toString` method
18164        return false;
18165      }
18166
18167      actual = lowercase('' + actual);
18168      expected = lowercase('' + expected);
18169      return actual.indexOf(expected) !== -1;
18170    };
18171  }
18172
18173  predicateFn = function(item) {
18174    if (shouldMatchPrimitives && !isObject(item)) {
18175      return deepCompare(item, expression.$, comparator, false);
18176    }
18177    return deepCompare(item, expression, comparator, matchAgainstAnyProp);
18178  };
18179
18180  return predicateFn;
18181}
18182
18183function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
18184  var actualType = getTypeForFilter(actual);
18185  var expectedType = getTypeForFilter(expected);
18186
18187  if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
18188    return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
18189  } else if (isArray(actual)) {
18190    // In case `actual` is an array, consider it a match
18191    // if ANY of it's items matches `expected`
18192    return actual.some(function(item) {
18193      return deepCompare(item, expected, comparator, matchAgainstAnyProp);
18194    });
18195  }
18196
18197  switch (actualType) {
18198    case 'object':
18199      var key;
18200      if (matchAgainstAnyProp) {
18201        for (key in actual) {
18202          if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
18203            return true;
18204          }
18205        }
18206        return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
18207      } else if (expectedType === 'object') {
18208        for (key in expected) {
18209          var expectedVal = expected[key];
18210          if (isFunction(expectedVal) || isUndefined(expectedVal)) {
18211            continue;
18212          }
18213
18214          var matchAnyProperty = key === '$';
18215          var actualVal = matchAnyProperty ? actual : actual[key];
18216          if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
18217            return false;
18218          }
18219        }
18220        return true;
18221      } else {
18222        return comparator(actual, expected);
18223      }
18224      break;
18225    case 'function':
18226      return false;
18227    default:
18228      return comparator(actual, expected);
18229  }
18230}
18231
18232// Used for easily differentiating between `null` and actual `object`
18233function getTypeForFilter(val) {
18234  return (val === null) ? 'null' : typeof val;
18235}
18236
18237/**
18238 * @ngdoc filter
18239 * @name currency
18240 * @kind function
18241 *
18242 * @description
18243 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
18244 * symbol for current locale is used.
18245 *
18246 * @param {number} amount Input to filter.
18247 * @param {string=} symbol Currency symbol or identifier to be displayed.
18248 * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
18249 * @returns {string} Formatted number.
18250 *
18251 *
18252 * @example
18253   <example module="currencyExample">
18254     <file name="index.html">
18255       <script>
18256         angular.module('currencyExample', [])
18257           .controller('ExampleController', ['$scope', function($scope) {
18258             $scope.amount = 1234.56;
18259           }]);
18260       </script>
18261       <div ng-controller="ExampleController">
18262         <input type="number" ng-model="amount" aria-label="amount"> <br>
18263         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
18264         custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
18265         no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
18266       </div>
18267     </file>
18268     <file name="protractor.js" type="protractor">
18269       it('should init with 1234.56', function() {
18270         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
18271         expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
18272         expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
18273       });
18274       it('should update', function() {
18275         if (browser.params.browser == 'safari') {
18276           // Safari does not understand the minus key. See
18277           // https://github.com/angular/protractor/issues/481
18278           return;
18279         }
18280         element(by.model('amount')).clear();
18281         element(by.model('amount')).sendKeys('-1234');
18282         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
18283         expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)');
18284         expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)');
18285       });
18286     </file>
18287   </example>
18288 */
18289currencyFilter.$inject = ['$locale'];
18290function currencyFilter($locale) {
18291  var formats = $locale.NUMBER_FORMATS;
18292  return function(amount, currencySymbol, fractionSize) {
18293    if (isUndefined(currencySymbol)) {
18294      currencySymbol = formats.CURRENCY_SYM;
18295    }
18296
18297    if (isUndefined(fractionSize)) {
18298      fractionSize = formats.PATTERNS[1].maxFrac;
18299    }
18300
18301    // if null or undefined pass it through
18302    return (amount == null)
18303        ? amount
18304        : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
18305            replace(/\u00A4/g, currencySymbol);
18306  };
18307}
18308
18309/**
18310 * @ngdoc filter
18311 * @name number
18312 * @kind function
18313 *
18314 * @description
18315 * Formats a number as text.
18316 *
18317 * If the input is not a number an empty string is returned.
18318 *
18319 * If the input is an infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
18320 *
18321 * @param {number|string} number Number to format.
18322 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
18323 * If this is not provided then the fraction size is computed from the current locale's number
18324 * formatting pattern. In the case of the default locale, it will be 3.
18325 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
18326 *
18327 * @example
18328   <example module="numberFilterExample">
18329     <file name="index.html">
18330       <script>
18331         angular.module('numberFilterExample', [])
18332           .controller('ExampleController', ['$scope', function($scope) {
18333             $scope.val = 1234.56789;
18334           }]);
18335       </script>
18336       <div ng-controller="ExampleController">
18337         <label>Enter number: <input ng-model='val'></label><br>
18338         Default formatting: <span id='number-default'>{{val | number}}</span><br>
18339         No fractions: <span>{{val | number:0}}</span><br>
18340         Negative number: <span>{{-val | number:4}}</span>
18341       </div>
18342     </file>
18343     <file name="protractor.js" type="protractor">
18344       it('should format numbers', function() {
18345         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
18346         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
18347         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
18348       });
18349
18350       it('should update', function() {
18351         element(by.model('val')).clear();
18352         element(by.model('val')).sendKeys('3374.333');
18353         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
18354         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
18355         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
18356      });
18357     </file>
18358   </example>
18359 */
18360
18361
18362numberFilter.$inject = ['$locale'];
18363function numberFilter($locale) {
18364  var formats = $locale.NUMBER_FORMATS;
18365  return function(number, fractionSize) {
18366
18367    // if null or undefined pass it through
18368    return (number == null)
18369        ? number
18370        : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
18371                       fractionSize);
18372  };
18373}
18374
18375var DECIMAL_SEP = '.';
18376function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
18377  if (isObject(number)) return '';
18378
18379  var isNegative = number < 0;
18380  number = Math.abs(number);
18381
18382  var isInfinity = number === Infinity;
18383  if (!isInfinity && !isFinite(number)) return '';
18384
18385  var numStr = number + '',
18386      formatedText = '',
18387      hasExponent = false,
18388      parts = [];
18389
18390  if (isInfinity) formatedText = '\u221e';
18391
18392  if (!isInfinity && numStr.indexOf('e') !== -1) {
18393    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
18394    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
18395      number = 0;
18396    } else {
18397      formatedText = numStr;
18398      hasExponent = true;
18399    }
18400  }
18401
18402  if (!isInfinity && !hasExponent) {
18403    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
18404
18405    // determine fractionSize if it is not specified
18406    if (isUndefined(fractionSize)) {
18407      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
18408    }
18409
18410    // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
18411    // inspired by:
18412    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
18413    number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
18414
18415    var fraction = ('' + number).split(DECIMAL_SEP);
18416    var whole = fraction[0];
18417    fraction = fraction[1] || '';
18418
18419    var i, pos = 0,
18420        lgroup = pattern.lgSize,
18421        group = pattern.gSize;
18422
18423    if (whole.length >= (lgroup + group)) {
18424      pos = whole.length - lgroup;
18425      for (i = 0; i < pos; i++) {
18426        if ((pos - i) % group === 0 && i !== 0) {
18427          formatedText += groupSep;
18428        }
18429        formatedText += whole.charAt(i);
18430      }
18431    }
18432
18433    for (i = pos; i < whole.length; i++) {
18434      if ((whole.length - i) % lgroup === 0 && i !== 0) {
18435        formatedText += groupSep;
18436      }
18437      formatedText += whole.charAt(i);
18438    }
18439
18440    // format fraction part.
18441    while (fraction.length < fractionSize) {
18442      fraction += '0';
18443    }
18444
18445    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
18446  } else {
18447    if (fractionSize > 0 && number < 1) {
18448      formatedText = number.toFixed(fractionSize);
18449      number = parseFloat(formatedText);
18450    }
18451  }
18452
18453  if (number === 0) {
18454    isNegative = false;
18455  }
18456
18457  parts.push(isNegative ? pattern.negPre : pattern.posPre,
18458             formatedText,
18459             isNegative ? pattern.negSuf : pattern.posSuf);
18460  return parts.join('');
18461}
18462
18463function padNumber(num, digits, trim) {
18464  var neg = '';
18465  if (num < 0) {
18466    neg =  '-';
18467    num = -num;
18468  }
18469  num = '' + num;
18470  while (num.length < digits) num = '0' + num;
18471  if (trim) {
18472    num = num.substr(num.length - digits);
18473  }
18474  return neg + num;
18475}
18476
18477
18478function dateGetter(name, size, offset, trim) {
18479  offset = offset || 0;
18480  return function(date) {
18481    var value = date['get' + name]();
18482    if (offset > 0 || value > -offset) {
18483      value += offset;
18484    }
18485    if (value === 0 && offset == -12) value = 12;
18486    return padNumber(value, size, trim);
18487  };
18488}
18489
18490function dateStrGetter(name, shortForm) {
18491  return function(date, formats) {
18492    var value = date['get' + name]();
18493    var get = uppercase(shortForm ? ('SHORT' + name) : name);
18494
18495    return formats[get][value];
18496  };
18497}
18498
18499function timeZoneGetter(date, formats, offset) {
18500  var zone = -1 * offset;
18501  var paddedZone = (zone >= 0) ? "+" : "";
18502
18503  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
18504                padNumber(Math.abs(zone % 60), 2);
18505
18506  return paddedZone;
18507}
18508
18509function getFirstThursdayOfYear(year) {
18510    // 0 = index of January
18511    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
18512    // 4 = index of Thursday (+1 to account for 1st = 5)
18513    // 11 = index of *next* Thursday (+1 account for 1st = 12)
18514    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
18515}
18516
18517function getThursdayThisWeek(datetime) {
18518    return new Date(datetime.getFullYear(), datetime.getMonth(),
18519      // 4 = index of Thursday
18520      datetime.getDate() + (4 - datetime.getDay()));
18521}
18522
18523function weekGetter(size) {
18524   return function(date) {
18525      var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
18526         thisThurs = getThursdayThisWeek(date);
18527
18528      var diff = +thisThurs - +firstThurs,
18529         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
18530
18531      return padNumber(result, size);
18532   };
18533}
18534
18535function ampmGetter(date, formats) {
18536  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
18537}
18538
18539function eraGetter(date, formats) {
vendor: 5,157 bytes, lines 18540-18652
18540  return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
18541}
18542
18543function longEraGetter(date, formats) {
18544  return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
18545}
18546
18547var DATE_FORMATS = {
18548  yyyy: dateGetter('FullYear', 4),
18549    yy: dateGetter('FullYear', 2, 0, true),
18550     y: dateGetter('FullYear', 1),
18551  MMMM: dateStrGetter('Month'),
18552   MMM: dateStrGetter('Month', true),
18553    MM: dateGetter('Month', 2, 1),
18554     M: dateGetter('Month', 1, 1),
18555    dd: dateGetter('Date', 2),
18556     d: dateGetter('Date', 1),
18557    HH: dateGetter('Hours', 2),
18558     H: dateGetter('Hours', 1),
18559    hh: dateGetter('Hours', 2, -12),
18560     h: dateGetter('Hours', 1, -12),
18561    mm: dateGetter('Minutes', 2),
18562     m: dateGetter('Minutes', 1),
18563    ss: dateGetter('Seconds', 2),
18564     s: dateGetter('Seconds', 1),
18565     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
18566     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
18567   sss: dateGetter('Milliseconds', 3),
18568  EEEE: dateStrGetter('Day'),
18569   EEE: dateStrGetter('Day', true),
18570     a: ampmGetter,
18571     Z: timeZoneGetter,
18572    ww: weekGetter(2),
18573     w: weekGetter(1),
18574     G: eraGetter,
18575     GG: eraGetter,
18576     GGG: eraGetter,
18577     GGGG: longEraGetter
18578};
18579
18580var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
18581    NUMBER_STRING = /^\-?\d+$/;
18582
18583/**
18584 * @ngdoc filter
18585 * @name date
18586 * @kind function
18587 *
18588 * @description
18589 *   Formats `date` to a string based on the requested `format`.
18590 *
18591 *   `format` string can be composed of the following elements:
18592 *
18593 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
18594 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
18595 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
18596 *   * `'MMMM'`: Month in year (January-December)
18597 *   * `'MMM'`: Month in year (Jan-Dec)
18598 *   * `'MM'`: Month in year, padded (01-12)
18599 *   * `'M'`: Month in year (1-12)
18600 *   * `'dd'`: Day in month, padded (01-31)
18601 *   * `'d'`: Day in month (1-31)
18602 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
18603 *   * `'EEE'`: Day in Week, (Sun-Sat)
18604 *   * `'HH'`: Hour in day, padded (00-23)
18605 *   * `'H'`: Hour in day (0-23)
18606 *   * `'hh'`: Hour in AM/PM, padded (01-12)
18607 *   * `'h'`: Hour in AM/PM, (1-12)
18608 *   * `'mm'`: Minute in hour, padded (00-59)
18609 *   * `'m'`: Minute in hour (0-59)
18610 *   * `'ss'`: Second in minute, padded (00-59)
18611 *   * `'s'`: Second in minute (0-59)
18612 *   * `'sss'`: Millisecond in second, padded (000-999)
18613 *   * `'a'`: AM/PM marker
18614 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
18615 *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
18616 *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
18617 *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
18618 *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
18619 *
18620 *   `format` string can also be one of the following predefined
18621 *   {@link guide/i18n localizable formats}:
18622 *
18623 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
18624 *     (e.g. Sep 3, 2010 12:05:08 PM)
18625 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
18626 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
18627 *     (e.g. Friday, September 3, 2010)
18628 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
18629 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
18630 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
18631 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
18632 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
18633 *
18634 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
18635 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
18636 *   (e.g. `"h 'o''clock'"`).
18637 *
18638 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
18639 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
18640 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
18641 *    specified in the string input, the time is considered to be in the local timezone.
18642 * @param {string=} format Formatting rules (see Description). If not specified,
18643 *    `mediumDate` is used.
18644 * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
18645 *    continental US time zone abbreviations, but for general use, use a time zone offset, for
18646 *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
18647 *    If not specified, the timezone of the browser will be used.
18648 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
18649 *
18650 * @example
18651   <example>
18652     <file name="index.html">
vendor: 4,078 bytes, lines 18653-18765
18653       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
18654           <span>{{1288323623006 | date:'medium'}}</span><br>
18655       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
18656          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
18657       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
18658          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
18659       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
18660          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
18661     </file>
18662     <file name="protractor.js" type="protractor">
18663       it('should format date', function() {
18664         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
18665            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
18666         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
18667            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
18668         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
18669            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
18670         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
18671            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
18672       });
18673     </file>
18674   </example>
18675 */
18676dateFilter.$inject = ['$locale'];
18677function dateFilter($locale) {
18678
18679
18680  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
18681                     // 1        2       3         4          5          6          7          8  9     10      11
18682  function jsonStringToDate(string) {
18683    var match;
18684    if (match = string.match(R_ISO8601_STR)) {
18685      var date = new Date(0),
18686          tzHour = 0,
18687          tzMin  = 0,
18688          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
18689          timeSetter = match[8] ? date.setUTCHours : date.setHours;
18690
18691      if (match[9]) {
18692        tzHour = toInt(match[9] + match[10]);
18693        tzMin = toInt(match[9] + match[11]);
18694      }
18695      dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
18696      var h = toInt(match[4] || 0) - tzHour;
18697      var m = toInt(match[5] || 0) - tzMin;
18698      var s = toInt(match[6] || 0);
18699      var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
18700      timeSetter.call(date, h, m, s, ms);
18701      return date;
18702    }
18703    return string;
18704  }
18705
18706
18707  return function(date, format, timezone) {
18708    var text = '',
18709        parts = [],
18710        fn, match;
18711
18712    format = format || 'mediumDate';
18713    format = $locale.DATETIME_FORMATS[format] || format;
18714    if (isString(date)) {
18715      date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
18716    }
18717
18718    if (isNumber(date)) {
18719      date = new Date(date);
18720    }
18721
18722    if (!isDate(date) || !isFinite(date.getTime())) {
18723      return date;
18724    }
18725
18726    while (format) {
18727      match = DATE_FORMATS_SPLIT.exec(format);
18728      if (match) {
18729        parts = concat(parts, match, 1);
18730        format = parts.pop();
18731      } else {
18732        parts.push(format);
18733        format = null;
18734      }
18735    }
18736
18737    var dateTimezoneOffset = date.getTimezoneOffset();
18738    if (timezone) {
18739      dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
18740      date = convertTimezoneToLocal(date, timezone, true);
18741    }
18742    forEach(parts, function(value) {
18743      fn = DATE_FORMATS[value];
18744      text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
18745                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
18746    });
18747
18748    return text;
18749  };
18750}
18751
18752
18753/**
18754 * @ngdoc filter
18755 * @name json
18756 * @kind function
18757 *
18758 * @description
18759 *   Allows you to convert a JavaScript object into JSON string.
18760 *
18761 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
18762 *   the binding is automatically converted to JSON.
18763 *
18764 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
18765 * @param {number=}
18765 spacing The number of spaces to use per indentation, defaults to 2.
18766 * @returns {string} JSON string.
18767 *
18768 *
18769 * @example
18770   <example>
18771     <file name="index.html">
18772       <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
18773       <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
18774     </file>
18775     <file name="protractor.js" type="protractor">
18776       it('should jsonify filtered objects', function() {
18777         expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
18778         expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
18779       });
18780     </file>
18781   </example>
18782 *
18783 */
18784function jsonFilter() {
18785  return function(object, spacing) {
18786    if (isUndefined(spacing)) {
18787        spacing = 2;
18788    }
18789    return toJson(object, spacing);
18790  };
18791}
18792
18793
18794/**
18795 * @ngdoc filter
18796 * @name lowercase
18797 * @kind function
18798 * @description
18799 * Converts string to lowercase.
18800 * @see angular.lowercase
18801 */
18802var lowercaseFilter = valueFn(lowercase);
18803
18804
18805/**
18806 * @ngdoc filter
18807 * @name uppercase
18808 * @kind function
18809 * @description
18810 * Converts string to uppercase.
18811 * @see angular.uppercase
18812 */
18813var uppercaseFilter = valueFn(uppercase);
18814
18815/**
18816 * @ngdoc filter
18817 * @name limitTo
18818 * @kind function
18819 *
18820 * @description
18821 * Creates a new array or string containing only a specified number of elements. The elements
18822 * are taken from either the beginning or the end of the source array, string or number, as specified by
18823 * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
18824 * converted to a string.
18825 *
18826 * @param {Array|string|number} input Source array, string or number to be limited.
18827 * @param {string|number} limit The length of the returned array or string. If the `limit` number
18828 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
18829 *     If the number is negative, `limit` number  of items from the end of the source array/string
18830 *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
18831 *     the input will be returned unchanged.
18832 * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
18833 *     indicates an offset from the end of `input`. Defaults to `0`.
18834 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
18835 *     had less than `limit` elements.
18836 *
18837 * @example
18838   <example module="limitToExample">
18839     <file name="index.html">
18840       <script>
18841         angular.module('limitToExample', [])
18842           .controller('ExampleController', ['$scope', function($scope) {
18843             $scope.numbers = [1,2,3,4,5,6,7,8,9];
18844             $scope.letters = "abcdefghi";
18845             $scope.longNumber = 2345432342;
18846             $scope.numLimit = 3;
18847             $scope.letterLimit = 3;
18848             $scope.longNumberLimit = 3;
18849           }]);
18850       </script>
18851       <div ng-controller="ExampleController">
18852         <label>
18853            Limit {{numbers}} to:
18854            <input type="number" step="1" ng-model="numLimit">
18855         </label>
18856         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
18857         <label>
18858            Limit {{letters}} to:
18859            <input type="number" step="1" ng-model="letterLimit">
18860         </label>
18861         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
18862         <label>
18863            Limit {{longNumber}} to:
18864            <input type="number" step="1" ng-model="longNumberLimit">
18865         </label>
18866         <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
18867       </div>
18868     </file>
18869     <file name="protractor.js" type="protractor">
18870       var numLimitInput = element(by.model('numLimit'));
18871       var letterLimitInput = element(by.model('letterLimit'));
18872       var longNumberLimitInput = element(by.model('longNumberLimit'));
18873       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
18874       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
18875       var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
18876
18877       it('should limit the number array to first three items', function() {
18878         expect(numLimitInput.getAttribute('value')).toBe('3');
18879         expect(letterLimitInput.getAttribute('value')).toBe('3');
18880         expect(longNumberLimitInput.getAttribute('value')).toBe('3');
18881         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
18882         expect(limitedLetters.getText()).toEqual('Output letters: abc');
18883         expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
18884       });
18885
18886       // There is a bug in safari and protractor that doesn't like the minus key
18887       // it('should update the output when -3 is entered', function() {
18888       //   numLimitInput.clear();
18889       //   numLimitInput.sendKeys('-3');
18890       //   letterLimitInput.clear();
18891       //   letterLimitInput.sendKeys('-3');
18892       //   longNumberLimitInput.clear();
18893       //   longNumberLimitInput.sendKeys('-3');
18894       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
18895       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
18896       //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
18897       // });
18898
18899       it('should not exceed the maximum size of input array', function() {
18900         numLimitInput.clear();
18901         numLimitInput.sendKeys('100');
18902         letterLimitInput.clear();
18903         letterLimitInput.sendKeys('100');
18904         longNumberLimitInput.clear();
18905         longNumberLimitInput.sendKeys('100');
18906         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
18907         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
18908         expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
18909       });
18910     </file>
18911   </example>
18912*/
18913function limitToFilter() {
18914  return function(input, limit, begin) {
18915    if (Math.abs(Number(limit)) === Infinity) {
18916      limit = Number(limit);
18917    } else {
18918      limit = toInt(limit);
18919    }
18920    if (isNaN(limit)) return input;
18921
18922    if (isNumber(input)) input = input.toString();
18923    if (!isArray(input) && !isString(input)) return input;
18924
18925    begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
18926    begin = (begin < 0 && begin >= -input.length) ? input.length + begin : begin;
18927
18928    if (limit >= 0) {
18929      return input.slice(begin, begin + limit);
18930    } else {
18931      if (begin === 0) {
18932        return input.slice(limit, input.length);
18933      } else {
18934        return input.slice(Math.max(0, begin + limit), begin);
18935      }
18936    }
18937  };
18938}
18939
18940/**
18941 * @ngdoc filter
18942 * @name orderBy
18943 * @kind function
18944 *
18945 * @description
18946 * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
18947 * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
18948 * correctly, make sure they are actually being saved as numbers and not strings.
18949 *
18950 * @param {Array} array The array to sort.
18951 * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
18952 *    used by the comparator to determine the order of elements.
18953 *
18954 *    Can be one of:
18955 *
18956 *    - `function`: Getter function. The result of this function will be sorted using the
18957 *      `<`, `===`, `>` operator.
18958 *    - `string`: An Angular expression. The result of this expression is used to compare elements
18959 *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
18960 *      3 first characters of a property called `name`). The result of a constant expression
18961 *      is interpreted as a property name to be used in comparisons (for example `"special name"`
18962 *      to sort object by the value of their `special name` property). An expression can be
18963 *      optionally prefixed with `+` or `-` to control ascending or descending sort order
18964 *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
18965 *      element itself is used to compare where sorting.
18966 *    - `Array`: An array of function or string predicates. The first predicate in the array
18967 *      is used for sorting, but when two items are equivalent, the next predicate is used.
18968 *
18969 *    If the predicate is missing or empty then it defaults to `'+'`.
18970 *
18971 * @param {boolean=} reverse Reverse the order of the array.
18972 * @returns {Array} Sorted copy of the source array.
18973 *
18974 *
18975 * @example
18976 * The example below demonstrates a simple ngRepeat, where the data is sorted
18977 * by age in descending order (predicate is set to `'-age'`).
18978 * `reverse` is not set, which means it defaults to `false`.
18979   <example module="orderByExample">
18980     <file name="index.html">
18981       <script>
18982         angular.module('orderByExample', [])
18983           .controller('ExampleController', ['$scope', function($scope) {
18984             $scope.friends =
18985                 [{name:'John', phone:'555-1212', age:10},
18986                  {name:'Mary', phone:'555-9876', age:19},
18987                  {name:'Mike', phone:'555-4321', age:21},
18988                  {name:'Adam', phone:'555-5678', age:35},
18989                  {name:'Julie', phone:'555-8765', age:29}];
18990           }]);
18991       </script>
18992       <div ng-controller="ExampleController">
18993         <table class="friend">
18994           <tr>
18995             <th>Name</th>
18996             <th>Phone Number</th>
18997             <th>Age</th>
18998           </tr>
18999           <tr ng-repeat="friend in friends | orderBy:'-age'">
19000             <td>{{friend.name}}</td>
19001             <td>{{friend.phone}}</td>
19002             <td>{{friend.age}}</td>
19003           </tr>
19004         </table>
19005       </div>
19006     </file>
19007   </example>
19008 *
19009 * The predicate and reverse parameters can be controlled dynamically through scope properties,
19010 * as shown in the next example.
19011 * @example
19012   <example module="orderByExample">
19013     <file name="index.html">
19014       <script>
19015         angular.module('orderByExample', [])
19016           .controller('ExampleController', ['$scope', function($scope) {
19017             $scope.friends =
19018                 [{name:'John', phone:'555-1212', age:10},
19019                  {name:'Mary', phone:'555-9876', age:19},
19020                  {name:'Mike', phone:'555-4321', age:21},
19021                  {name:'Adam', phone:'555-5678', age:35},
19022                  {name:'Julie', phone:'555-8765', age:29}];
19023             $scope.predicate = '-age';
19024           }]);
19025       </script>
19026       <div ng-controller="ExampleController">
19027         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
19028         <hr/>
19029         [ <a href="" ng-click="predicate=''">unsorted</a> ]
19030         <table class="friend">
19031           <tr>
19032             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
19033                 (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
19034             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
19035             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
19036           </tr>
19037           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
19038             <td>{{friend.name}}</td>
19039             <td>{{friend.phone}}</td>
19040             <td>{{friend.age}}</td>
19041           </tr>
19042         </table>
19043       </div>
19044     </file>
19045   </example>
19046 *
19047 * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
19048 * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
19049 * desired parameters.
19050 *
19051 * Example:
19052 *
19053 * @example
19054  <example module="orderByExample">
19055    <file name="index.html">
19056      <div ng-controller="ExampleController">
19057        <table class="friend">
19058          <tr>
19059            <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
19060              (<a href="" ng-click="order('-name',false)">^</a>)</th>
19061            <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
19062            <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
19063          </tr>
19064          <tr ng-repeat="friend in friends">
19065            <td>{{friend.name}}</td>
19066            <td>{{friend.phone}}</td>
19067            <td>{{friend.age}}</td>
19068          </tr>
19069        </table>
19070      </div>
19071    </file>
19072
19073    <file name="script.js">
19074      angular.module('orderByExample', [])
19075        .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
19076          var orderBy = $filter('orderBy');
19077          $scope.friends = [
19078            { name: 'John',    phone: '555-1212',    age: 10 },
19079            { name: 'Mary',    phone: '555-9876',    age: 19 },
19080            { name: 'Mike',    phone: '555-4321',    age: 21 },
19081            { name: 'Adam',    phone: '555-5678',    age: 35 },
19082            { name: 'Julie',   phone: '555-8765',    age: 29 }
19083          ];
19084          $scope.order = function(predicate, reverse) {
19085            $scope.friends = orderBy($scope.friends, predicate, reverse);
19086          };
19087          $scope.order('-age',false);
19088        }]);
19089    </file>
19090</example>
19091 */
19092orderByFilter.$inject = ['$parse'];
19093function orderByFilter($parse) {
19094  return function(array, sortPredicate, reverseOrder) {
19095    if (!(isArrayLike(array))) return array;
19096    sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
19097    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
19098    sortPredicate = sortPredicate.map(function(predicate) {
19099      var descending = false, get = predicate || identity;
19100      if (isString(predicate)) {
19101        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
19102          descending = predicate.charAt(0) == '-';
19103          predicate = predicate.substring(1);
19104        }
19105        if (predicate === '') {
19106          // Effectively no predicate was passed so we compare identity
19107          return reverseComparator(compare, descending);
19108        }
19109        get = $parse(predicate);
19110        if (get.constant) {
19111          var key = get();
19112          return reverseComparator(function(a, b) {
19113            return compare(a[key], b[key]);
19114          }, descending);
19115        }
19116      }
19117      return reverseComparator(function(a, b) {
19118        return compare(get(a),get(b));
19119      }, descending);
19120    });
19121    return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
19122
19123    function comparator(o1, o2) {
19124      for (var i = 0; i < sortPredicate.length; i++) {
19125        var comp = sortPredicate[i](o1, o2);
19126        if (comp !== 0) return comp;
19127      }
19128      return 0;
19129    }
19130    function reverseComparator(comp, descending) {
19131      return descending
19132          ? function(a, b) {return comp(b,a);}
19133          : comp;
19134    }
19135
19136    function isPrimitive(value) {
19137      switch (typeof value) {
19138        case 'number': /* falls through */
19139        case 'boolean': /* falls through */
19140        case 'string':
19141          return true;
19142        default:
19143          return false;
19144      }
19145    }
19146
19147    function objectToString(value) {
19148      if (value === null) return 'null';
19149      if (typeof value.valueOf === 'function') {
19150        value = value.valueOf();
19151        if (isPrimitive(value)) return value;
19152      }
19153      if (typeof value.toString === 'function') {
19154        value = value.toString();
19155        if (isPrimitive(value)) return value;
19156      }
19157      return '';
19158    }
19159
19160    function compare(v1, v2) {
19161      var t1 = typeof v1;
19162      var t2 = typeof v2;
19163      if (t1 === t2 && t1 === "object") {
19164        v1 = objectToString(v1);
19165        v2 = objectToString(v2);
19166      }
19167      if (t1 === t2) {
19168        if (t1 === "string") {
19169           v1 = v1.toLowerCase();
19170           v2 = v2.toLowerCase();
19171        }
19172        if (v1 === v2) return 0;
19173        return v1 < v2 ? -1 : 1;
19174      } else {
19175        return t1 < t2 ? -1 : 1;
19176      }
19177    }
19178  };
19179}
19180
19181function ngDirective(directive) {
19182  if (isFunction(directive)) {
19183    directive = {
19184      link: directive
19185    };
19186  }
19187  directive.restrict = directive.restrict || 'AC';
19188  return valueFn(directive);
19189}
19190
19191/**
19192 * @ngdoc directive
19193 * @name a
19194 * @restrict E
19195 *
19196 * @description
19197 * Modifies the default behavior of the html A tag so that the default action is prevented when
19198 * the href attribute is empty.
19199 *
19200 * This change permits the easy creation of action links with the `ngClick` directive
19201 * without changing the location or causing page reloads, e.g.:
19202 * `<a href="" ng-click="list.addItem()">Add Item</a>`
19203 */
19204var htmlAnchorDirective = valueFn({
19205  restrict: 'E',
19206  compile: function(element, attr) {
19207    if (!attr.href && !attr.xlinkHref) {
19208      return function(scope, element) {
19209        // If the linked element is not an anchor tag anymore, do nothing
19210        if (element[0].nodeName.toLowerCase() !== 'a') return;
19211
19212        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
19213        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
19214                   'xlink:href' : 'href';
19215        element.on('click', function(event) {
19216          // if we have no href url, then don't navigate anywhere.
19217          if (!element.attr(href)) {
19218            event.preventDefault();
19219          }
19220        });
19221      };
19222    }
19223  }
19224});
19225
19226/**
19227 * @ngdoc directive
19228 * @name ngHref
19229 * @restrict A
19230 * @priority 99
19231 *
19232 * @description
19233 * Using Angular markup like `{{hash}}` in an href attribute will
19234 * make the link go to the wrong URL if the user clicks it before
19235 * Angular has a chance to replace the `{{hash}}
19235` markup with its
19236 * value. Until Angular replaces the markup the link will be broken
19237 * and will most likely return a 404 error. The `ngHref` directive
19238 * solves this problem.
19239 *
19240 * The wrong way to write it:
19241 * ```html
19242 * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19243 * ```
19244 *
19245 * The correct way to write it:
19246 * ```html
19247 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
19248 * ```
19249 *
19250 * @element A
19251 * @param {template} ngHref any string which can contain `{{}}` markup.
19252 *
19253 * @example
19254 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
19255 * in links and their different behaviors:
19256    <example>
19257      <file name="index.html">
19258        <input ng-model="value" /><br />
19259        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
19260        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
19261        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
19262        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
19263        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
19264        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
19265      </file>
19266      <file name="protractor.js" type="protractor">
19267        it('should execute ng-click but not reload when href without value', function() {
19268          element(by.id('link-1')).click();
19269          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
19270          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
19271        });
19272
19273        it('should execute ng-click but not reload when href empty string', function() {
19274          element(by.id('link-2')).click();
19275          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
19276          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
19277        });
19278
19279        it('should execute ng-click and change url when ng-href specified', function() {
19280          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
19281
19282          element(by.id('link-3')).click();
19283
19284          // At this point, we navigate away from an Angular page, so we need
19285          // to use browser.driver to get the base webdriver.
19286
19287          browser.wait(function() {
19288            return browser.driver.getCurrentUrl().then(function(url) {
19289              return url.match(/\/123$/);
19290            });
19291          }, 5000, 'page should navigate to /123');
19292        });
19293
19294        it('should execute ng-click but not reload when href empty string and name specified', function() {
19295          element(by.id('link-4')).click();
19296          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
19297          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
19298        });
19299
19300        it('should execute ng-click but not reload when no href but name specified', function() {
19301          element(by.id('link-5')).click();
19302          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
19303          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
19304        });
19305
19306        it('should only change url when only ng-href', function() {
19307          element(by.model('value')).clear();
19308          element(by.model('value')).sendKeys('6');
19309          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
19310
19311          element(by.id('link-6')).click();
19312
19313          // At this point, we navigate away from an Angular page, so we need
19314          // to use browser.driver to get the base webdriver.
19315          browser.wait(function() {
19316            return browser.driver.getCurrentUrl().then(function(url) {
19317              return url.match(/\/6$/);
19318            });
19319          }, 5000, 'page should navigate to /6');
19320        });
19321      </file>
19322    </example>
19323 */
19324
19325/**
19326 * @ngdoc directive
19327 * @name ngSrc
19328 * @restrict A
19329 * @priority 99
19330 *
19331 * @description
19332 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
19333 * work right: The browser will fetch from the URL with the literal
19334 * text `{{hash}}` until Angular replaces the expression inside
19335 * `{{hash}}`. The `ngSrc` directive solves this problem.
19336 *
19337 * The buggy way to write it:
19338 * ```html
19339 * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
19340 * ```
19341 *
19342 * The correct way to write it:
19343 * ```html
19344 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
19345 * ```
19346 *
19347 * @element IMG
19348 * @param {template} ngSrc any string which can contain `{{}}` markup.
19349 */
19350
19351/**
19352 * @ngdoc directive
19353 * @name ngSrcset
19354 * @restrict A
19355 * @priority 99
19356 *
19357 * @description
19358 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
19359 * work right: The browser will fetch from the URL with the literal
19360 * text `{{hash}}` until Angular replaces the expression inside
19361 * `{{hash}}`. The `ngSrcset` directive solves this problem.
19362 *
19363 * The buggy way to write it:
19364 * ```html
19365 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
19366 * ```
19367 *
19368 * The correct way to write it:
19369 * ```html
19370 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
19371 * ```
19372 *
19373 * @element IMG
19374 * @param {template} ngSrcset any string which can contain `{{}}` markup.
19375 */
19376
19377/**
19378 * @ngdoc directive
19379 * @name ngDisabled
19380 * @restrict A
19381 * @priority 100
19382 *
19383 * @description
19384 *
19385 * This directive sets the `disabled` attribute on the element if the
19386 * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
19387 *
19388 * A special directive is necessary because we cannot use interpolation inside the `disabled`
19389 * attribute.  The following example would make the button enabled on Chrome/Firefox
19390 * but not on older IEs:
19391 *
19392 * ```html
19393 * <!-- See below for an example of ng-disabled being used correctly -->
19394 * <div ng-init="isDisabled = false">
19395 *  <button disabled="{{isDisabled}}">Disabled</button>
19396 * </div>
19397 * ```
19398 *
19399 * This is because the HTML specification does not require browsers to preserve the values of
19400 * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
19401 * If we put an Angular interpolation expression into such an attribute then the
19402 * binding information would be lost when the browser removes the attribute.
19403 *
19404 * @example
19405    <example>
19406      <file name="index.html">
19407        <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
19408        <button ng-model="button" ng-disabled="checked">Button</button>
19409      </file>
19410      <file name="protractor.js" type="protractor">
19411        it('should toggle button', function() {
19412          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
19413          element(by.model('checked')).click();
19414          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
19415        });
19416      </file>
19417    </example>
19418 *
19419 * @element INPUT
19420 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
19421 *     then the `disabled` attribute will be set on the element
19422 */
19423
19424
19425/**
19426 * @ngdoc directive
19427 * @name ngChecked
19428 * @restrict A
19429 * @priority 100
19430 *
19431 * @description
19432 * The HTML specification does not require browsers to preserve the values of boolean attributes
19433 * such as checked. (Their presence means true and their absence means false.)
19434 * If we put an Angular interpolation expression into such an attribute then the
19435 * binding information would be lost when the browser removes the attribute.
19436 * The `ngChecked` directive solves this problem for the `checked` attribute.
19437 * This complementary directive is not removed by the browser and so provides
19438 * a permanent reliable place to store the binding information.
19439 * @example
19440    <example>
19441      <file name="index.html">
19442        <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
19443        <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
19444      </file>
19445      <file name="protractor.js" type="protractor">
19446        it('should check both checkBoxes', function() {
19447          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
19448          element(by.model('master')).click();
19449          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
19450        });
19451      </file>
19452    </example>
19453 *
19454 * @element INPUT
19455 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
19456 *     then special attribute "checked" will be set on the element
19457 */
19458
19459
19460/**
19461 * @ngdoc directive
19462 * @name ngReadonly
19463 * @restrict A
19464 * @priority 100
19465 *
19466 * @description
19467 * The HTML specification does not require browsers to preserve the values of boolean attributes
19468 * such as readonly. (Their presence means true and their absence means false.)
19469 * If we put an Angular interpolation expression into such an attribute then the
19470 * binding information would be lost when the browser removes the attribute.
19471 * The `ngReadonly` directive solves this problem for the `readonly` attribute.
19472 * This complementary directive is not removed by the browser and so provides
19473 * a permanent reliable place to store the binding information.
19474 * @example
19475    <example>
19476      <file name="index.html">
19477        <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
19478        <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
19479      </file>
19480      <file name="protractor.js" type="protractor">
19481        it('should toggle readonly attr', function() {
19482          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
19483          element(by.model('checked')).click();
19484          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
19485        });
19486      </file>
19487    </example>
19488 *
19489 * @element INPUT
19490 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
19491 *     then special attribute "readonly" will be set on the element
19492 */
19493
19494
19495/**
19496 * @ngdoc directive
19497 * @name ngSelected
19498 * @restrict A
19499 * @priority 100
19500 *
19501 * @description
19502 * The HTML specification does not require browsers to preserve the values of boolean attributes
19503 * such as selected. (Their presence means true and their absence means false.)
19504 * If we put an Angular interpolation expression into such an attribute then the
19505 * binding information would be lost when the browser removes the attribute.
19506 * The `ngSelected` directive solves this problem for the `selected` attribute.
19507 * This complementary directive is not removed by the browser and so provides
19508 * a permanent reliable place to store the binding information.
19509 *
19510 * @example
19511    <example>
19512      <file name="index.html">
19513        <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
19514        <select aria-label="ngSelected demo">
19515          <option>Hello!</option>
19516          <option id="greet" ng-selected="selected">Greetings!</option>
19517        </select>
19518      </file>
19519      <file name="protractor.js" type="protractor">
19520        it('should select Greetings!', function() {
19521          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
19522          element(by.model('selected')).click();
19523          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
19524        });
19525      </file>
19526    </example>
19527 *
19528 * @element OPTION
19529 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
19530 *     then special attribute "selected" will be set on the element
19531 */
19532
19533/**
19534 * @ngdoc directive
19535 * @name ngOpen
19536 * @restrict A
19537 * @priority 100
19538 *
19539 * @description
19540 * The HTML specification does not require browsers to preserve the values of boolean attributes
19541 * such as open. (Their presence means true and their absence means false.)
19542 * If we put an Angular interpolation expression into such an attribute then the
19543 * binding information would be lost when the browser removes the attribute.
19544 * The `ngOpen` directive solves this problem for the `open` attribute.
19545 * This complementary directive is not removed by the browser and so provides
19546 * a permanent reliable place to store the binding information.
19547 * @example
19548     <example>
19549       <file name="index.html">
19550         <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
19551         <details id="details" ng-open="open">
19552            <summary>Show/Hide me</summary>
19553         </details>
19554       </file>
19555       <file name="protractor.js" type="protractor">
19556         it('should toggle open', function() {
19557           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
19558           element(by.model('open')).click();
19559           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
19560         });
19561       </file>
19562     </example>
19563 *
19564 * @element DETAILS
19565 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
19566 *     then special attribute "open" will be set on the element
19567 */
19568
19569var ngAttributeAliasDirectives = {};
19570
19571// boolean attrs are evaluated
19572forEach(BOOLEAN_ATTR, function(propName, attrName) {
19573  // binding to multiple is not supported
19574  if (propName == "multiple") return;
19575
19576  function defaultLinkFn(scope, element, attr) {
19577    scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
19578      attr.$set(attrName, !!value);
19579    });
19580  }
19581
19582  var normalized = directiveNormalize('ng-' + attrName);
19583  var linkFn = defaultLinkFn;
19584
19585  if (propName === 'checked') {
19586    linkFn = function(scope, element, attr) {
19587      // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
19588      if (attr.ngModel !== attr[normalized]) {
19589        defaultLinkFn(scope, element, attr);
19590      }
19591    };
19592  }
19593
19594  ngAttributeAliasDirectives[normalized] = function() {
19595    return {
19596      restrict: 'A',
19597      priority: 100,
19598      link: linkFn
19599    };
19600  };
19601});
19602
19603// aliased input attrs are evaluated
19604forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
19605  ngAttributeAliasDirectives[ngAttr] = function() {
19606    return {
19607      priority: 100,
19608      link: function(scope, element, attr) {
19609        //special case ngPattern when a literal regular expression value
19610        //is used as the expression (this way we don't have to watch anything).
19611        if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
19612          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
19613          if (match) {
19614            attr.$set("ngPattern", new RegExp(match[1], match[2]));
19615            return;
19616          }
19617        }
19618
19619        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
19620          attr.$set(ngAttr, value);
19621        });
19622      }
19623    };
19624  };
19625});
19626
19627// ng-src, ng-srcset, ng-href are interpolated
19628forEach(['src', 'srcset', 'href'], function(attrName) {
19629  var normalized = directiveNormalize('ng-' + attrName);
19630  ngAttributeAliasDirectives[normalized] = function() {
19631    return {
19632      priority: 99, // it needs to run after the attributes are interpolated
19633      link: function(scope, element, attr) {
19634        var propName = attrName,
19635            name = attrName;
19636
19637        if (attrName === 'href' &&
19638            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
19639          name = 'xlinkHref';
19640          attr.$attr[name] = 'xlink:href';
19641          propName = null;
19642        }
19643
19644        attr.$observe(normalized, function(value) {
19645          if (!value) {
19646            if (attrName === 'href') {
19647              attr.$set(name, null);
19648            }
19649            return;
19650          }
19651
19652          attr.$set(name, value);
19653
19654          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
19655          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
19656          // to set the property as well to achieve the desired effect.
19657          // we use attr[attrName] value since $set can sanitize the url.
19658          if (msie && propName) element.prop(propName, attr[name]);
19659        });
19660      }
19661    };
19662  };
19663});
19664
19665/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
19666 */
19667var nullFormCtrl = {
19668  $addControl: noop,
19669  $$renameControl: nullFormRenameControl,
19670  $removeControl: noop,
19671  $setValidity: noop,
19672  $setDirty: noop,
19673  $setPristine: noop,
19674  $setSubmitted: noop
19675},
19676SUBMITTED_CLASS = 'ng-submitted';
19677
19678function nullFormRenameControl(control, name) {
19679  control.$name = name;
19680}
19681
19682/**
19683 * @ngdoc type
19684 * @name form.FormController
19685 *
19686 * @property {boolean} $pristine True if user has not interacted with the form yet.
19687 * @property {boolean} $dirty True if user has already interacted with the form.
19688 * @property {boolean} $valid True if all of the containing forms and controls are valid.
19689 * @property {boolean} $invalid True if at least one containing control or form is invalid.
19690 * @property {boolean} $submitted True if user has submitted the form even if its invalid.
19691 *
19692 * @property {Object} $error Is an object hash, containing references to controls or
19693 *  forms with failing validators, where:
19694 *
19695 *  - keys are validation tokens (error names),
19696 *  - values are arrays of controls or forms that have a failing validator for given error name.
19697 *
19698 *  Built-in validation tokens:
19699 *
19700 *  - `email`
19701 *  - `max`
19702 *  - `maxlength`
19703 *  - `min`
19704 *  - `minlength`
19705 *  - `number`
19706 *  - `pattern`
19707 *  - `required`
19708 *  - `url`
19709 *  - `date`
19710 *  - `datetimelocal`
19711 *  - `time`
19712 *  - `week`
19713 *  - `month`
19714 *
19715 * @description
19716 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
19717 * such as being valid/invalid or dirty/pristine.
19718 *
19719 * Each {@link ng.directive:form form} directive creates an instance
19720 * of `FormController`.
19721 *
19722 */
19723//asks for $scope to fool the BC controller module
19724FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
19725function FormController(element, attrs, $scope, $animate, $interpolate) {
19726  var form = this,
19727      controls = [];
19728
19729  var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
19730
19731  // init state
19732  form.$error = {};
19733  form.$$success = {};
19734  form.$pending = undefined;
19735  form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
19736  form.$dirty = false;
19737  form.$pristine = true;
19738  form.$valid = true;
19739  form.$invalid = false;
19740  form.$submitted = false;
19741
19742  parentForm.$addControl(form);
19743
19744  /**
19745   * @ngdoc method
19746   * @name form.FormController#$rollbackViewValue
19747   *
19748   * @description
19749   * Rollback all form controls pending updates to the `$modelValue`.
19750   *
19751   * Updates may be pending by a debounced event or because the input is waiting for a some future
19752   * event defined in `ng-model-options`. This method is typically needed by the reset button of
19753   * a form that uses `ng-model-options` to pend updates.
19754   */
19755  form.$rollbackViewValue = function() {
19756    forEach(controls, function(control) {
19757      control.$rollbackViewValue();
19758    });
19759  };
19760
19761  /**
19762   * @ngdoc method
19763   * @name form.FormController#$commitViewValue
19764   *
19765   * @description
19766   * Commit all form controls pending updates to the `$modelValue`.
19767   *
19768   * Updates may be pending by a debounced event or because the input is waiting for a some future
19769   * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
19770   * usually handles calling this in response to input events.
19771   */
19772  form.$commitViewValue = function() {
19773    forEach(controls, function(control) {
19774      control.$commitViewValue();
19775    });
19776  };
19777
19778  /**
19779   * @ngdoc method
19780   * @name form.FormController#$addControl
19781   *
19782   * @description
19783   * Register a control with the form.
19784   *
19785   * Input elements using ngModelController do this automatically when they are linked.
19786   */
19787  form.$addControl = function(control) {
19788    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
19789    // and not added to the scope.  Now we throw an error.
19790    assertNotHasOwnProperty(control.$name, 'input');
19791    controls.push(control);
19792
19793    if (control.$name) {
19794      form[control.$name] = control;
19795    }
19796  };
19797
19798  // Private API: rename a form control
19799  form.$$renameControl = function(control, newName) {
19800    var oldName = control.$name;
19801
19802    if (form[oldName] === control) {
19803      delete form[oldName];
19804    }
19805    form[newName] = control;
19806    control.$name = newName;
19807  };
19808
19809  /**
19810   * @ngdoc method
19811   * @name form.FormController#$removeControl
19812   *
19813   * @description
19814   * Deregister a control from the form.
19815   *
19816   * Input elements using ngModelController do this automatically when they are destroyed.
19817   */
19818  form.$removeControl = function(control) {
19819    if (control.$name && form[control.$name] === control) {
19820      delete form[control.$name];
19821    }
19822    forEach(form.$pending, function(value, name) {
19823      form.$setValidity(name, null, control);
19824    });
19825    forEach(form.$error, function(value, name) {
19826      form.$setValidity(name, null, control);
19827    });
19828    forEach(form.$$success, function(value, name) {
19829      form.$setValidity(name, null, control);
19830    });
19831
19832    arrayRemove(controls, control);
19833  };
19834
19835
19836  /**
19837   * @ngdoc method
19838   * @name form.FormController#$setValidity
19839   *
19840   * @description
19841   * Sets the validity of a form control.
19842   *
19843   * This method will also propagate to parent forms.
19844   */
19845  addSetValidityMethod({
19846    ctrl: this,
19847    $element: element,
19848    set: function(object, property, controller) {
19849      var list = object[property];
19850      if (!list) {
19851        object[property] = [controller];
19852      } else {
19853        var index = list.indexOf(controller);
19854        if (index === -1) {
19855          list.push(controller);
19856        }
19857      }
19858    },
19859    unset: function(object, property, controller) {
19860      var list = object[property];
19861      if (!list) {
19862        return;
19863      }
19864      arrayRemove(list, controller);
19865      if (list.length === 0) {
19866        delete object[property];
19867      }
19868    },
19869    parentForm: parentForm,
19870    $animate: $animate
19871  });
19872
19873  /**
19874   * @ngdoc method
19875   * @name form.FormController#$setDirty
19876   *
19877   * @description
19878   * Sets the form to a dirty state.
19879   *
19880   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
19881   * state (ng-dirty class). This method will also propagate to parent forms.
19882   */
19883  form.$setDirty = function() {
19884    $animate.removeClass(element, PRISTINE_CLASS);
19885    $animate.addClass(element, DIRTY_CLASS);
19886    form.$dirty = true;
19887    form.$pristine = false;
19888    parentForm.$setDirty();
19889  };
19890
19891  /**
19892   * @ngdoc method
19893   * @name form.FormController#$setPristine
19894   *
19895   * @description
19896   * Sets the form to its pristine state.
19897   *
19898   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
19899   * state (ng-pristine class). This method will also propagate to all the controls contained
19900   * in this form.
19901   *
19902   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
19903   * saving or resetting it.
19904   */
19905  form.$setPristine = function() {
19906    $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
19907    form.$dirty = false;
19908    form.$pristine = true;
19909    form.$submitted = false;
19910    forEach(controls, function(control) {
19911      control.$setPristine();
19912    });
19913  };
19914
19915  /**
19916   * @ngdoc method
19917   * @name form.FormController#$setUntouched
19918   *
19919   * @description
19920   * Sets the form to its untouched state.
19921   *
19922   * This method can be called to remove the 'ng-touched' class and set the form controls to their
19923   * untouched state (ng-untouched class).
19924   *
19925   * Setting a form controls back to their untouched state is often useful when setting the form
19926   * back to its pristine state.
19927   */
19928  form.$setUntouched = function() {
19929    forEach(controls, function(control) {
19930      control.$setUntouched();
19931    });
19932  };
19933
19934  /**
19935   * @ngdoc method
19936   * @name form.FormController#$setSubmitted
19937   *
19938   * @description
19939   * Sets the form to its submitted state.
19940   */
19941  form.$setSubmitted = function() {
19942    $animate.addClass(element, SUBMITTED_CLASS);
19943    form.$submitted = true;
19944    parentForm.$setSubmitted();
19945  };
19946}
19947
19948/**
19949 * @ngdoc directive
19950 * @name ngForm
19951 * @restrict EAC
19952 *
19953 * @description
19954 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
19955 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
19956 * sub-group of controls needs to be determined.
19957 *
19958 * Note: the purpose of `ngForm` is to group controls,
19959 * but not to be a replacement for the `<form>` tag with all of its capabilities
19960 * (e.g. posting to the server, ...).
19961 *
19962 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
19963 *                       related scope, under this name.
19964 *
19965 */
19966
19967 /**
19968 * @ngdoc directive
19969 * @name form
19970 * @restrict E
19971 *
19972 * @description
19973 * Directive that instantiates
19974 * {@link form.FormController FormController}.
19975 *
19976 * If the `name` attribute is specified, the form controller is published onto the current scope under
19977 * this name.
19978 *
19979 * # Alias: {@link ng.directive:ngForm `ngForm`}
19980 *
19981 * In Angular, forms can be nested. This means that the outer form is valid when all of the child
19982 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
19983 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
19984 * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
19985 * using Angular validation directives in forms that are dynamically generated using the
19986 * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
19987 * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
19988 * `ngForm` directive and nest these in an outer `form` element.
19989 *
19990 *
19991 * # CSS classes
19992 *  - `ng-valid` is set if the form is valid.
19993 *  - `ng-invalid` is set if the form is invalid.
19994 *  - `ng-pristine` is set if the form is pristine.
19995 *  - `ng-dirty` is set if the form is dirty.
19996 *  - `ng-submitted` is set if the form was submitted.
19997 *
19998 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
19999 *
20000 *
20001 * # Submitting a form and preventing the default action
20002 *
20003 * Since the role of forms in client-side Angular applications is different than in classical
20004 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
20005 * page reload that sends the data to the server. Instead some javascript logic should be triggered
20006 * to handle the form submission in an application-specific way.
20007 *
20008 * For this reason, Angular prevents the default action (form submission to the server) unless the
20009 * `<form>` element has an `action` attribute specified.
20010 *
20011 * You can use one of the following two ways to specify what javascript method should be called when
20012 * a form is submitted:
20013 *
20014 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
20015 * - {@link ng.directive:ngClick ngClick} directive on the first
20016  *  button or input field of type submit (input[type=submit])
20017 *
20018 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
20019 * or {@link ng.directive:ngClick ngClick} directives.
20020 * This is because of the following form submission rules in the HTML specification:
20021 *
20022 * - If a form has only one input field then hitting enter in this field triggers form submit
20023 * (`ngSubmit`)
20024 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
20025 * doesn't trigger submit
20026 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
20027 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
20028 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
20029 *
20030 * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
20031 * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
20032 * to have access to the updated model.
20033 *
20034 * ## Animation Hooks
20035 *
20036 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
20037 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
20038 * other validations that are performed within the form. Animations in ngForm are similar to how
20039 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
20040 * as JS animations.
20041 *
20042 * The following example shows a simple way to utilize CSS transitions to style a form element
20043 * that has been rendered as invalid after it has been validated:
20044 *
20045 * <pre>
20046 * //be sure to include ngAnimate as a module to hook into more
20047 * //advanced animations
20048 * .my-form {
20049 *   transition:0.5s linear all;
20050 *   background: white;
20051 * }
20052 * .my-form.ng-invalid {
20053 *   background: red;
20054 *   color:white;
20055 * }
20056 * </pre>
20057 *
20058 * @example
20059    <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
20060      <file name="index.html">
20061       <script>
20062         angular.module('formExample', [])
20063           .controller('FormController', ['$scope', function($scope) {
20064             $scope.userType = 'guest';
20065           }]);
20066       </script>
20067       <style>
20068        .my-form {
20069          -webkit-transition:all linear 0.5s;
20070          transition:all linear 0.5s;
20071          background: transparent;
20072        }
20073        .my-form.ng-invalid {
20074          background: red;
20075        }
20076       </style>
20077       <form name="myForm" ng-controller="FormController" class="my-form">
20078         userType: <input name="input" ng-model="userType" required>
20079         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
20080         <code>userType = {{userType}}</code><br>
20081         <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
20082         <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
20083         <code>myForm.$valid = {{myForm.$valid}}</code><br>
20084         <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
20085        </form>
20086      </file>
20087      <file name="protractor.js" type="protractor">
20088        it('should initialize to model', function() {
20089          var userType = element(by.binding('userType'));
20090          var valid = element(by.binding('myForm.input.$valid'));
20091
20092          expect(userType.getText()).toContain('guest');
20093          expect(valid.getText()).toContain('true');
20094        });
20095
20096        it('should be invalid if empty', function() {
20097          var userType = element(by.binding('userType'));
20098          var valid = element(by.binding('myForm.input.$valid'));
20099          var userInput = element(by.model('userType'));
20100
20101          userInput.clear();
20102          userInput.sendKeys('');
20103
20104          expect(userType.getText()).toEqual('userType =');
20105          expect(valid.getText()).toContain('false');
20106        });
20107      </file>
20108    </example>
20109 *
20110 * @param {string=} name Name of the form. If specified, the form controller will be published into
20111 *                       related scope, under this name.
20112 */
20113var formDirectiveFactory = function(isNgForm) {
20114  return ['$timeout', function($timeout) {
20115    var formDirective = {
20116      name: 'form',
20117      restrict: isNgForm ? 'EAC' : 'E',
20118      controller: FormController,
20119      compile: function ngFormCompile(formElement, attr) {
20120        // Setup initial state of the control
20121        formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
20122
20123        var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
20124
20125        return {
20126          pre: function ngFormPreLink(scope, formElement, attr, controller) {
20127            // if `action` attr is not present on the form, prevent the default action (submission)
20128            if (!('action' in attr)) {
20129              // we can't use jq events because if a form is destroyed during submission the default
20130              // action is not prevented. see #1238
20131              //
20132              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
20133              // page reload if the form was destroyed by submission of the form via a click handler
20134              // on a button in the form. Looks like an IE9 specific bug.
20135              var handleFormSubmission = function(event) {
20136                scope.$apply(function() {
20137                  controller.$commitViewValue();
20138                  controller.$setSubmitted();
20139                });
20140
20141                event.preventDefault();
20142              };
20143
20144              addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20145
20146              // unregister the preventDefault listener so that we don't not leak memory but in a
20147              // way that will achieve the prevention of the default action.
20148              formElement.on('$destroy', function() {
20149                $timeout(function() {
20150                  removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
20151                }, 0, false);
20152              });
20153            }
20154
20155            var parentFormCtrl = controller.$$parentForm;
20156
20157            if (nameAttr) {
20158              setter(scope, controller.$name, controller, controller.$name);
20159              attr.$observe(nameAttr, function(newValue) {
20160                if (controller.$name === newValue) return;
20161                setter(scope, controller.$name, undefined, controller.$name);
20162                parentFormCtrl.$$renameControl(controller, newValue);
20163                setter(scope, controller.$name, controller, controller.$name);
20164              });
20165            }
20166            formElement.on('$destroy', function() {
20167              parentFormCtrl.$removeControl(controller);
20168              if (nameAttr) {
20169                setter(scope, attr[nameAttr], undefined, controller.$name);
20170              }
20171              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
20172            });
20173          }
20174        };
20175      }
20176    };
20177
20178    return formDirective;
20179  }];
20180};
20181
20182var formDirective = formDirectiveFactory();
20183var ngFormDirective = formDirectiveFactory(true);
20184
20185/* global VALID_CLASS: false,
20186  INVALID_CLASS: false,
20187  PRISTINE_CLASS: false,
20188  DIRTY_CLASS: false,
20189  UNTOUCHED_CLASS: false,
20190  TOUCHED_CLASS: false,
20191  $ngModelMinErr: false,
20192*/
20193
20194// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20195var 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)/;
20196var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
20197var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
20198var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
20199var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
20200var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20201var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
20202var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
20203var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
20204
20205var inputType = {
20206
20207  /**
20208   * @ngdoc input
20209   * @name input[text]
20210   *
20211   * @description
20212   * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
20213   *
20214   *
20215   * @param {string} ngModel Assignable angular expression to data-bind to.
20216   * @param {string=} name Property name of the form under which the control is published.
20217   * @param {string=} required Adds `required` validation error key if the value is not entered.
20218   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20219   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20220   *    `required` when you want to data-bind to the `required` attribute.
20221   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20222   *    minlength.
20223   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20224   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20225   *    any length.
20226   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20227   *    that contains the regular expression body that will be converted to a regular expression
20228   *    as in the ngPattern directive.
20229   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20230   *    a RegExp found by evaluating the Angular expression given in the attribute value.
20231   *    If the expression evaluates to a RegExp object, then this is used directly.
20232   *    If the expression evaluates to a string, then it will be converted to a RegExp
20233   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20234   *    `new RegExp('^abc$')`.<br />
20235   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20236   *    start at the index of the last search's match, thus not taking the whole input value into
20237   *    account.
20238   * @param {string=} ngChange Angular expression to be executed when input changes due to user
20239   *    interaction with the input element.
20240   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
20241   *    This parameter is ignored for input[type=password] controls, which will never trim the
20242   *    input.
20243   *
20244   * @example
20245      <example name="text-input-directive" module="textInputExample">
20246        <file name="index.html">
20247         <script>
20248           angular.module('textInputExample', [])
20249             .controller('ExampleController', ['$scope', function($scope) {
20250               $scope.example = {
20251                 text: 'guest',
20252                 word: /^\s*\w*\s*$/
20253               };
20254             }]);
20255         </script>
20256         <form name="myForm" ng-controller="ExampleController">
20257           <label>Single word:
20258             <input type="text" name="input" ng-model="example.text"
20259                    ng-pattern="example.word" required ng-trim="false">
20260           </label>
20261           <div role="alert">
20262             <span class="error" ng-show="myForm.input.$error.required">
20263               Required!</span>
20264             <span class="error" ng-show="myForm.input.$error.pattern">
20265               Single word only!</span>
20266           </div>
20267           <tt>text = {{example.text}}</tt><br/>
20268           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20269           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20270           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20271           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20272          </form>
20273        </file>
20274        <file name="protractor.js" type="protractor">
20275          var text = element(by.binding('example.text'));
20276          var valid = element(by.binding('myForm.input.$valid'));
20277          var input = element(by.model('example.text'));
20278
20279          it('should initialize to model', function() {
20280            expect(text.getText()).toContain('guest');
20281            expect(valid.getText()).toContain('true');
20282          });
20283
20284          it('should be invalid if empty', function() {
20285            input.clear();
20286            input.sendKeys('');
20287
20288            expect(text.getText()).toEqual('text =');
20289            expect(valid.getText()).toContain('false');
20290          });
20291
20292          it('should be invalid if multi word', function() {
20293            input.clear();
20294            input.sendKeys('hello world');
20295
20296            expect(valid.getText()).toContain('false');
20297          });
20298        </file>
20299      </example>
20300   */
20301  'text': textInputType,
20302
20303    /**
20304     * @ngdoc input
20305     * @name input[date]
20306     *
20307     * @description
20308     * Input with date validation and transformation. In browsers that do not yet support
20309     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
20310     * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
20311     * modern browsers do not yet support this input type, it is important to provide cues to users on the
20312     * expected input format via a placeholder or label.
20313     *
20314     * The model must always be a Date object, otherwise Angular will throw an error.
20315     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20316     *
20317     * The timezone to be used to read/write the `Date` instance in the model can be defined using
20318     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20319     *
20320     * @param {string} ngModel Assignable angular expression to data-bind to.
20321     * @param {string=} name Property name of the form under which the control is published.
20322     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20323     * valid ISO date string (yyyy-MM-dd).
20324     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20325     * a valid ISO date string (yyyy-MM-dd).
20326     * @param {string=} required Sets `required` validation error key if the value is not entered.
20327     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20328     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20329     *    `required` when you want to data-bind to the `required` attribute.
20330     * @param {string=} ngChange Angular expression to be executed when input changes due to user
20331     *    interaction with the input element.
20332     *
20333     * @example
20334     <example name="date-input-directive" module="dateInputExample">
20335     <file name="index.html">
20336       <script>
20337          angular.module('dateInputExample', [])
20338            .controller('DateController', ['$scope', function($scope) {
20339              $scope.example = {
20340                value: new Date(2013, 9, 22)
20341              };
20342            }]);
20343       </script>
20344       <form name="myForm" ng-controller="DateController as dateCtrl">
20345          <label for="exampleInput">Pick a date in 2013:</label>
20346          <input type="date" id="exampleInput" name="input" ng-model="example.value"
20347              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
20348          <div role="alert">
20349            <span class="error" ng-show="myForm.input.$error.required">
20350                Required!</span>
20351            <span class="error" ng-show="myForm.input.$error.date">
20352                Not a valid date!</span>
20353           </div>
20354           <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
20355           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20356           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20357           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20358           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20359       </form>
20360     </file>
20361     <file name="protractor.js" type="protractor">
20362        var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
20363        var valid = element(by.binding('myForm.input.$valid'));
20364        var input = element(by.model('example.value'));
20365
20366        // currently protractor/webdriver does not support
20367        // sending keys to all known HTML5 input controls
20368        // for various browsers (see https://github.com/angular/protractor/issues/562).
20369        function setInput(val) {
20370          // set the value of the element and force validation.
20371          var scr = "var ipt = document.getElementById('exampleInput'); " +
20372          "ipt.value = '" + val + "';" +
20373          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20374          browser.executeScript(scr);
20375        }
20376
20377        it('should initialize to model', function() {
20378          expect(value.getText()).toContain('2013-10-22');
20379          expect(valid.getText()).toContain('myForm.input.$valid = true');
20380        });
20381
20382        it('should be invalid if empty', function() {
20383          setInput('');
20384          expect(value.getText()).toEqual('value =');
20385          expect(valid.getText()).toContain('myForm.input.$valid = false');
20386        });
20387
20388        it('should be invalid if over max', function() {
20389          setInput('2015-01-01');
20390          expect(value.getText()).toContain('');
20391          expect(valid.getText()).toContain('myForm.input.$valid = false');
20392        });
20393     </file>
20394     </example>
20395     */
20396  'date': createDateInputType('date', DATE_REGEXP,
20397         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
20398         'yyyy-MM-dd'),
20399
20400   /**
20401    * @ngdoc input
20402    * @name input[datetime-local]
20403    *
20404    * @description
20405    * Input with datetime validation and transformation. In browsers that do not yet support
20406    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20407    * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
20408    *
20409    * The model must always be a Date object, otherwise Angular will throw an error.
20410    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20411    *
20412    * The timezone to be used to read/write the `Date` instance in the model can be defined using
20413    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20414    *
20415    * @param {string} ngModel Assignable angular expression to data-bind to.
20416    * @param {string=} name Property name of the form under which the control is published.
20417    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20418    * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
20419    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20420    * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
20421    * @param {string=} required Sets `required` validation error key if the value is not entered.
20422    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20423    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20424    *    `required` when you want to data-bind to the `required` attribute.
20425    * @param {string=} ngChange Angular expression to be executed when input changes due to user
20426    *    interaction with the input element.
20427    *
20428    * @example
20429    <example name="datetimelocal-input-directive" module="dateExample">
20430    <file name="index.html">
20431      <script>
20432        angular.module('dateExample', [])
20433          .controller('DateController', ['$scope', function($scope) {
20434            $scope.example = {
20435              value: new Date(2010, 11, 28, 14, 57)
20436            };
20437          }]);
20438      </script>
20439      <form name="myForm" ng-controller="DateController as dateCtrl">
20440        <label for="exampleInput">Pick a date between in 2013:</label>
20441        <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
20442            placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
20443        <div role="alert">
20444          <span class="error" ng-show="myForm.input.$error.required">
20445              Required!</span>
20446          <span class="error" ng-show="myForm.input.$error.datetimelocal">
20447              Not a valid date!</span>
20448        </div>
20449        <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
20450        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20451        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20452        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20453        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20454      </form>
20455    </file>
20456    <file name="protractor.js" type="protractor">
20457      var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
20458      var valid = element(by.binding('myForm.input.$valid'));
20459      var input = element(by.model('example.value'));
20460
20461      // currently protractor/webdriver does not support
20462      // sending keys to all known HTML5 input controls
20463      // for various browsers (https://github.com/angular/protractor/issues/562).
20464      function setInput(val) {
20465        // set the value of the element and force validation.
20466        var scr = "var ipt = document.getElementById('exampleInput'); " +
20467        "ipt.value = '" + val + "';" +
20468        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20469        browser.executeScript(scr);
20470      }
20471
20472      it('should initialize to model', function() {
20473        expect(value.getText()).toContain('2010-12-28T14:57:00');
20474        expect(valid.getText()).toContain('myForm.input.$valid = true');
20475      });
20476
20477      it('should be invalid if empty', function() {
20478        setInput('');
20479        expect(value.getText()).toEqual('value =');
20480        expect(valid.getText()).toContain('myForm.input.$valid = false');
20481      });
20482
20483      it('should be invalid if over max', function() {
20484        setInput('2015-01-01T23:59:00');
20485        expect(value.getText()).toContain('');
20486        expect(valid.getText()).toContain('myForm.input.$valid = false');
20487      });
20488    </file>
20489    </example>
20490    */
20491  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
20492      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
20493      'yyyy-MM-ddTHH:mm:ss.sss'),
20494
20495  /**
20496   * @ngdoc input
20497   * @name input[time]
20498   *
20499   * @description
20500   * Input with time validation and transformation. In browsers that do not yet support
20501   * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20502   * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
20503   * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
20504   *
20505   * The model must always be a Date object, otherwise Angular will throw an error.
20506   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20507   *
20508   * The timezone to be used to read/write the `Date` instance in the model can be defined using
20509   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20510   *
20511   * @param {string} ngModel Assignable angular expression to data-bind to.
20512   * @param {string=} name Property name of the form under which the control is published.
20513   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20514   * valid ISO time format (HH:mm:ss).
20515   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
20516   * valid ISO time format (HH:mm:ss).
20517   * @param {string=} required Sets `required` validation error key if the value is not entered.
20518   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20519   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20520   *    `required` when you want to data-bind to the `required` attribute.
20521   * @param {string=} ngChange Angular expression to be executed when input changes due to user
20522   *    interaction with the input element.
20523   *
20524   * @example
20525   <example name="time-input-directive" module="timeExample">
20526   <file name="index.html">
20527     <script>
20528      angular.module('timeExample', [])
20529        .controller('DateController', ['$scope', function($scope) {
20530          $scope.example = {
20531            value: new Date(1970, 0, 1, 14, 57, 0)
20532          };
20533        }]);
20534     </script>
20535     <form name="myForm" ng-controller="DateController as dateCtrl">
20536        <label for="exampleInput">Pick a between 8am and 5pm:</label>
20537        <input type="time" id="exampleInput" name="input" ng-model="example.value"
20538            placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
20539        <div role="alert">
20540          <span class="error" ng-show="myForm.input.$error.required">
20541              Required!</span>
20542          <span class="error" ng-show="myForm.input.$error.time">
20543              Not a valid date!</span>
20544        </div>
20545        <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
20546        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20547        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20548        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20549        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20550     </form>
20551   </file>
20552   <file name="protractor.js" type="protractor">
20553      var value = element(by.binding('example.value | date: "HH:mm:ss"'));
20554      var valid = element(by.binding('myForm.input.$valid'));
20555      var input = element(by.model('example.value'));
20556
20557      // currently protractor/webdriver does not support
20558      // sending keys to all known HTML5 input controls
20559      // for various browsers (https://github.com/angular/protractor/issues/562).
20560      function setInput(val) {
20561        // set the value of the element and force validation.
20562        var scr = "var ipt = document.getElementById('exampleInput'); " +
20563        "ipt.value = '" + val + "';" +
20564        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20565        browser.executeScript(scr);
20566      }
20567
20568      it('should initialize to model', function() {
20569        expect(value.getText()).toContain('14:57:00');
20570        expect(valid.getText()).toContain('myForm.input.$valid = true');
20571      });
20572
20573      it('should be invalid if empty', function() {
20574        setInput('');
20575        expect(value.getText()).toEqual('value =');
20576        expect(valid.getText()).toContain('myForm.input.$valid = false');
20577      });
20578
20579      it('should be invalid if over max', function() {
20580        setInput('23:59:00');
20581        expect(value.getText()).toContain('');
20582        expect(valid.getText()).toContain('myForm.input.$valid = false');
20583      });
20584   </file>
20585   </example>
20586   */
20587  'time': createDateInputType('time', TIME_REGEXP,
20588      createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
20589     'HH:mm:ss.sss'),
20590
20591   /**
20592    * @ngdoc input
20593    * @name input[week]
20594    *
20595    * @description
20596    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
20597    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20598    * week format (yyyy-W##), for example: `2013-W02`.
20599    *
20600    * The model must always be a Date object, otherwise Angular will throw an error.
20601    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20602    *
20603    * The timezone to be used to read/write the `Date` instance in the model can be defined using
20604    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20605    *
20606    * @param {string} ngModel Assignable angular expression to data-bind to.
20607    * @param {string=} name Property name of the form under which the control is published.
20608    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
20609    * valid ISO week format (yyyy-W##).
20610    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
20611    * a valid ISO week format (yyyy-W##).
20612    * @param {string=} required Sets `required` validation error key if the value is not entered.
20613    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20614    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20615    *    `required` when you want to data-bind to the `required` attribute.
20616    * @param {string=} ngChange Angular expression to be executed when input changes due to user
20617    *    interaction with the input element.
20618    *
20619    * @example
20620    <example name="week-input-directive" module="weekExample">
20621    <file name="index.html">
20622      <script>
20623      angular.module('weekExample', [])
20624        .controller('DateController', ['$scope', function($scope) {
20625          $scope.example = {
20626            value: new Date(2013, 0, 3)
20627          };
20628        }]);
20629      </script>
20630      <form name="myForm" ng-controller="DateController as dateCtrl">
20631        <label>Pick a date between in 2013:
20632          <input id="exampleInput" type="week" name="input" ng-model="example.value"
20633                 placeholder="YYYY-W##" min="2012-W32"
20634                 max="2013-W52" required />
20635        </label>
20636        <div role="alert">
20637          <span class="error" ng-show="myForm.input.$error.required">
20638              Required!</span>
20639          <span class="error" ng-show="myForm.input.$error.week">
20640              Not a valid date!</span>
20641        </div>
20642        <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
20643        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20644        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20645        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20646        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20647      </form>
20648    </file>
20649    <file name="protractor.js" type="protractor">
20650      var value = element(by.binding('example.value | date: "yyyy-Www"'));
20651      var valid = element(by.binding('myForm.input.$valid'));
20652      var input = element(by.model('example.value'));
20653
20654      // currently protractor/webdriver does not support
20655      // sending keys to all known HTML5 input controls
20656      // for various browsers (https://github.com/angular/protractor/issues/562).
20657      function setInput(val) {
20658        // set the value of the element and force validation.
20659        var scr = "var ipt = document.getElementById('exampleInput'); " +
20660        "ipt.value = '" + val + "';" +
20661        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20662        browser.executeScript(scr);
20663      }
20664
20665      it('should initialize to model', function() {
20666        expect(value.getText()).toContain('2013-W01');
20667        expect(valid.getText()).toContain('myForm.input.$valid = true');
20668      });
20669
20670      it('should be invalid if empty', function() {
20671        setInput('');
20672        expect(value.getText()).toEqual('value =');
20673        expect(valid.getText()).toContain('myForm.input.$valid = false');
20674      });
20675
20676      it('should be invalid if over max', function() {
20677        setInput('2015-W01');
20678        expect(value.getText()).toContain('');
20679        expect(valid.getText()).toContain('myForm.input.$valid = false');
20680      });
20681    </file>
20682    </example>
20683    */
20684  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
20685
20686  /**
20687   * @ngdoc input
20688   * @name input[month]
20689   *
20690   * @description
20691   * Input with month validation and transformation. In browsers that do not yet support
20692   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
20693   * month format (yyyy-MM), for example: `2009-01`.
20694   *
20695   * The model must always be a Date object, otherwise Angular will throw an error.
20696   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
20697   * If the model is not set to the first of the month, the next view to model update will set it
20698   * to the first of the month.
20699   *
20700   * The timezone to be used to read/write the `Date` instance in the model can be defined using
20701   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
20702   *
20703   * @param {string} ngModel Assignable angular expression to data-bind to.
20704   * @param {string=} name Property name of the form under which the control is published.
20705   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
20706   * a valid ISO month format (yyyy-MM).
20707   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
20708   * be a valid ISO month format (yyyy-MM).
20709   * @param {string=} required Sets `required` validation error key if the value is not entered.
20710   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20711   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20712   *    `required` when you want to data-bind to the `required` attribute.
20713   * @param {string=} ngChange Angular expression to be executed when input changes due to user
20714   *    interaction with the input element.
20715   *
20716   * @example
20717   <example name="month-input-directive" module="monthExample">
20718   <file name="index.html">
20719     <script>
20720      angular.module('monthExample', [])
20721        .controller('DateController', ['$scope', function($scope) {
20722          $scope.example = {
20723            value: new Date(2013, 9, 1)
20724          };
20725        }]);
20726     </script>
20727     <form name="myForm" ng-controller="DateController as dateCtrl">
20728       <label for="exampleInput">Pick a month in 2013:</label>
20729       <input id="exampleInput" type="month" name="input" ng-model="example.value"
20730          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
20731       <div role="alert">
20732         <span class="error" ng-show="myForm.input.$error.required">
20733            Required!</span>
20734         <span class="error" ng-show="myForm.input.$error.month">
20735            Not a valid month!</span>
20736       </div>
20737       <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
20738       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20739       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20740       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20741       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20742     </form>
20743   </file>
20744   <file name="protractor.js" type="protractor">
20745      var value = element(by.binding('example.value | date: "yyyy-MM"'));
20746      var valid = element(by.binding('myForm.input.$valid'));
20747      var input = element(by.model('example.value'));
20748
20749      // currently protractor/webdriver does not support
20750      // sending keys to all known HTML5 input controls
20751      // for various browsers (https://github.com/angular/protractor/issues/562).
20752      function setInput(val) {
20753        // set the value of the element and force validation.
20754        var scr = "var ipt = document.getElementById('exampleInput'); " +
20755        "ipt.value = '" + val + "';" +
20756        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
20757        browser.executeScript(scr);
20758      }
20759
20760      it('should initialize to model', function() {
20761        expect(value.getText()).toContain('2013-10');
20762        expect(valid.getText()).toContain('myForm.input.$valid = true');
20763      });
20764
20765      it('should be invalid if empty', function() {
20766        setInput('');
20767        expect(value.getText()).toEqual('value =');
20768        expect(valid.getText()).toContain('myForm.input.$valid = false');
20769      });
20770
20771      it('should be invalid if over max', function() {
20772        setInput('2015-01');
20773        expect(value.getText()).toContain('');
20774        expect(valid.getText()).toContain('myForm.input.$valid = false');
20775      });
20776   </file>
20777   </example>
20778   */
20779  'month': createDateInputType('month', MONTH_REGEXP,
20780     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
20781     'yyyy-MM'),
20782
20783  /**
20784   * @ngdoc input
20785   * @name input[number]
20786   *
20787   * @description
20788   * Text input with number validation and transformation. Sets the `number` validation
20789   * error if not a valid number.
20790   *
20791   * <div class="alert alert-warning">
20792   * The model must always be of type `number` otherwise Angular will throw an error.
20793   * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
20794   * error docs for more information and an example of how to convert your model if necessary.
20795   * </div>
20796   *
20797   * @param {string} ngModel Assignable angular expression to data-bind to.
20798   * @param {string=} name Property name of the form under which the control is published.
20799   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
20800   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
20801   * @param {string=} required Sets `required` validation error key if the value is not entered.
20802   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20803   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20804   *    `required` when you want to data-bind to the `required` attribute.
20805   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20806   *    minlength.
20807   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20808   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20809   *    any length.
20810   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20811   *    that contains the regular expression body that will be converted to a regular expression
20812   *    as in the ngPattern directive.
20813   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20814   *    a RegExp found by evaluating the Angular expression given in the attribute value.
20815   *    If the expression evaluates to a RegExp object, then this is used directly.
20816   *    If the expression evaluates to a string, then it will be converted to a RegExp
20817   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20818   *    `new RegExp('^abc$')`.<br />
20819   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20820   *    start at the index of the last search's match, thus not taking the whole input value into
20821   *    account.
20822   * @param {string=} ngChange Angular expression to be executed when input changes due to user
20823   *    interaction with the input element.
20824   *
20825   * @example
20826      <example name="number-input-directive" module="numberExample">
20827        <file name="index.html">
20828         <script>
20829           angular.module('numberExample', [])
20830             .controller('ExampleController', ['$scope', function($scope) {
20831               $scope.example = {
20832                 value: 12
20833               };
20834             }]);
20835         </script>
20836         <form name="myForm" ng-controller="ExampleController">
20837           <label>Number:
20838             <input type="number" name="input" ng-model="example.value"
20839                    min="0" max="99" required>
20840          </label>
20841           <div role="alert">
20842             <span class="error" ng-show="myForm.input.$error.required">
20843               Required!</span>
20844             <span class="error" ng-show="myForm.input.$error.number">
20845               Not valid number!</span>
20846           </div>
20847           <tt>value = {{example.value}}</tt><br/>
20848           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20849           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20850           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20851           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20852          </form>
20853        </file>
20854        <file name="protractor.js" type="protractor">
20855          var value = element(by.binding('example.value'));
20856          var valid = element(by.binding('myForm.input.$valid'));
20857          var input = element(by.model('example.value'));
20858
20859          it('should initialize to model', function() {
20860            expect(value.getText()).toContain('12');
20861            expect(valid.getText()).toContain('true');
20862          });
20863
20864          it('should be invalid if empty', function() {
20865            input.clear();
20866            input.sendKeys('');
20867            expect(value.getText()).toEqual('value =');
20868            expect(valid.getText()).toContain('false');
20869          });
20870
20871          it('should be invalid if over max', function() {
20872            input.clear();
20873            input.sendKeys('123');
20874            expect(value.getText()).toEqual('value =');
20875            expect(valid.getText()).toContain('false');
20876          });
20877        </file>
20878      </example>
20879   */
20880  'number': numberInputType,
20881
20882
20883  /**
20884   * @ngdoc input
20885   * @name input[url]
20886   *
20887   * @description
20888   * Text input with URL validation. Sets the `url` validation error key if the content is not a
20889   * valid URL.
20890   *
20891   * <div class="alert alert-warning">
20892   * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
20893   * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
20894   * the built-in validators (see the {@link guide/forms Forms guide})
20895   * </div>
20896   *
20897   * @param {string} ngModel Assignable angular expression to data-bind to.
20898   * @param {string=} name Property name of the form under which the control is published.
20899   * @param {string=} required Sets `required` validation error key if the value is not entered.
20900   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20901   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20902   *    `required` when you want to data-bind to the `required` attribute.
20903   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
20904   *    minlength.
20905   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
20906   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
20907   *    any length.
20908   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
20909   *    that contains the regular expression body that will be converted to a regular expression
20910   *    as in the ngPattern directive.
20911   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
20912   *    a RegExp found by evaluating the Angular expression given in the attribute value.
20913   *    If the expression evaluates to a RegExp object, then this is used directly.
20914   *    If the expression evaluates to a string, then it will be converted to a RegExp
20915   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
20916   *    `new RegExp('^abc$')`.<br />
20917   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
20918   *    start at the index of the last search's match, thus not taking the whole input value into
20919   *    account.
20920   * @param {string=} ngChange Angular expression to be executed when input changes due to user
20921   *    interaction with the input element.
20922   *
20923   * @example
20924      <example name="url-input-directive" module="urlExample">
20925        <file name="index.html">
20926         <script>
20927           angular.module('urlExample', [])
20928             .controller('ExampleController', ['$scope', function($scope) {
20929               $scope.url = {
20930                 text: 'http://google.com'
20931               };
20932             }]);
20933         </script>
20934         <form name="myForm" ng-controller="ExampleController">
20935           <label>URL:
20936             <input type="url" name="input" ng-model="url.text" required>
20937           <label>
20938           <div role="alert">
20939             <span class="error" ng-show="myForm.input.$error.required">
20940               Required!</span>
20941             <span class="error" ng-show="myForm.input.$error.url">
20942               Not valid url!</span>
20943           </div>
20944           <tt>text = {{url.text}}</tt><br/>
20945           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
20946           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
20947           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
20948           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
20949           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
20950          </form>
20951        </file>
20952        <file name="protractor.js" type="protractor">
20953          var text = element(by.binding('url.text'));
20954          var valid = element(by.binding('myForm.input.$valid'));
20955          var input = element(by.model('url.text'));
20956
20957          it('should initialize to model', function() {
20958            expect(text.getText()).toContain('http://google.com');
20959            expect(valid.getText()).toContain('true');
20960          });
20961
20962          it('should be invalid if empty', function() {
20963            input.clear();
20964            input.sendKeys('');
20965
20966            expect(text.getText()).toEqual('text =');
20967            expect(valid.getText()).toContain('false');
20968          });
20969
20970          it('should be invalid if not url', function() {
20971            input.clear();
20972            input.sendKeys('box');
20973
20974            expect(valid.getText()).toContain('false');
20975          });
20976        </file>
20977      </example>
20978   */
20979  'url': urlInputType,
20980
20981
20982  /**
20983   * @ngdoc input
20984   * @name input[email]
20985   *
20986   * @description
20987   * Text input with email validation. Sets the `email` validation error key if not a valid email
20988   * address.
20989   *
20990   * <div class="alert alert-warning">
20991   * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
20992   * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
20993   * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
20994   * </div>
20995   *
20996   * @param {string} ngModel Assignable angular expression to data-bind to.
20997   * @param {string=} name Property name of the form under which the control is published.
20998   * @param {string=} required Sets `required` validation error key if the value is not entered.
20999   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21000   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21001   *    `required` when you want to data-bind to the `required` attribute.
21002   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21003   *    minlength.
21004   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21005   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
21006   *    any length.
21007   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
21008   *    that contains the regular expression body that will be converted to a regular expression
21009   *    as in the ngPattern directive.
21010   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21011   *    a RegExp found by evaluating the Angular expression given in the attribute value.
21012   *    If the expression evaluates to a RegExp object, then this is used directly.
21013   *    If the expression evaluates to a string, then it will be converted to a RegExp
21014   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21015   *    `new RegExp('^abc$')`.<br />
21016   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21017   *    start at the index of the last search's match, thus not taking the whole input value into
21018   *    account.
21019   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21020   *    interaction with the input element.
21021   *
21022   * @example
21023      <example name="email-input-directive" module="emailExample">
21024        <file name="index.html">
21025         <script>
21026           angular.module('emailExample', [])
21027             .controller('ExampleController', ['$scope', function($scope) {
21028               $scope.email = {
21029                 text: '[email protected]'
21030               };
21031             }]);
21032         </script>
21033           <form name="myForm" ng-controller="ExampleController">
21034             <label>Email:
21035               <input type="email" name="input" ng-model="email.text" required>
21036             </label>
21037             <div role="alert">
21038               <span class="error" ng-show="myForm.input.$error.required">
21039                 Required!</span>
21040               <span class="error" ng-show="myForm.input.$error.email">
21041                 Not valid email!</span>
21042             </div>
21043             <tt>text = {{email.text}}</tt><br/>
21044             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
21045             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
21046             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21047             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21048             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
21049           </form>
21050         </file>
21051        <file name="protractor.js" type="protractor">
21052          var text = element(by.binding('email.text'));
21053          var valid = element(by.binding('myForm.input.$valid'));
21054          var input = element(by.model('email.text'));
21055
21056          it('should initialize to model', function() {
21057            expect(text.getText()).toContain('[email protected]');
21058            expect(valid.getText()).toContain('true');
21059          });
21060
21061          it('should be invalid if empty', function() {
21062            input.clear();
21063            input.sendKeys('');
21064            expect(text.getText()).toEqual('text =');
21065            expect(valid.getText()).toContain('false');
21066          });
21067
21068          it('should be invalid if not email', function() {
21069            input.clear();
21070            input.sendKeys('xxx');
21071
21072            expect(valid.getText()).toContain('false');
21073          });
21074        </file>
21075      </example>
21076   */
21077  'email': emailInputType,
21078
21079
21080  /**
21081   * @ngdoc input
21082   * @name input[radio]
21083   *
21084   * @description
21085   * HTML radio button.
21086   *
21087   * @param {string} ngModel Assignable angular expression to data-bind to.
21088   * @param {string} value The value to which the expression should be set when selected.
21089   * @param {string=} name Property name of the form under which the control is published.
21090   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21091   *    interaction with the input element.
21092   * @param {string} ngValue Angular expression which sets the value to which the expression should
21093   *    be set when selected.
21094   *
21095   * @example
21096      <example name="radio-input-directive" module="radioExample">
21097        <file name="index.html">
21098         <script>
21099           angular.module('radioExample', [])
21100             .controller('ExampleController', ['$scope', function($scope) {
21101               $scope.color = {
21102                 name: 'blue'
21103               };
21104               $scope.specialValue = {
21105                 "id": "12345",
21106                 "value": "green"
21107               };
21108             }]);
21109         </script>
21110         <form name="myForm" ng-controller="ExampleController">
21111           <label>
21112             <input type="radio" ng-model="color.name" value="red">
21113             Red
21114           </label><br/>
21115           <label>
21116             <input type="radio" ng-model="color.name" ng-value="specialValue">
21117             Green
21118           </label><br/>
21119           <label>
21120             <input type="radio" ng-model="color.name" value="blue">
21121             Blue
21122           </label><br/>
21123           <tt>color = {{color.name | json}}</tt><br/>
21124          </form>
21125          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
21126        </file>
21127        <file name="protractor.js" type="protractor">
21128          it('should change state', function() {
21129            var color = element(by.binding('color.name'));
21130
21131            expect(color.getText()).toContain('blue');
21132
21133            element.all(by.model('color.name')).get(0).click();
21134
21135            expect(color.getText()).toContain('red');
21136          });
21137        </file>
21138      </example>
21139   */
21140  'radio': radioInputType,
21141
21142
21143  /**
21144   * @ngdoc input
21145   * @name input[checkbox]
21146   *
21147   * @description
21148   * HTML checkbox.
21149   *
21150   * @param {string} ngModel Assignable angular expression to data-bind to.
21151   * @param {string=} name Property name of the form under which the control is published.
21152   * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
21153   * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
21154   * @param {string=} ngChange Angular expression to be executed when input changes due to user
21155   *    interaction with the input element.
21156   *
21157   * @example
21158      <example name="checkbox-input-directive" module="checkboxExample">
21159        <file name="index.html">
21160         <script>
21161           angular.module('checkboxExample', [])
21162             .controller('ExampleController', ['$scope', function($scope) {
21163               $scope.checkboxModel = {
21164                value1 : true,
21165                value2 : 'YES'
21166              };
21167             }]);
21168         </script>
21169         <form name="myForm" ng-controller="ExampleController">
21170           <label>Value1:
21171             <input type="checkbox" ng-model="checkboxModel.value1">
21172           </label><br/>
21173           <label>Value2:
21174             <input type="checkbox" ng-model="checkboxModel.value2"
21175                    ng-true-value="'YES'" ng-false-value="'NO'">
21176            </label><br/>
21177           <tt>value1 = {{checkboxModel.value1}}</tt><br/>
21178           <tt>value2 = {{checkboxModel.value2}}</tt><br/>
21179          </form>
21180        </file>
21181        <file name="protractor.js" type="protractor">
21182          it('should change state', function() {
21183            var value1 = element(by.binding('checkboxModel.value1'));
21184            var value2 = element(by.binding('checkboxModel.value2'));
21185
21186            expect(value1.getText()).toContain('true');
21187            expect(value2.getText()).toContain('YES');
21188
21189            element(by.model('checkboxModel.value1')).click();
21190            element(by.model('checkboxModel.value2')).click();
21191
21192            expect(value1.getText()).toContain('false');
21193            expect(value2.getText()).toContain('NO');
21194          });
21195        </file>
21196      </example>
21197   */
21198  'checkbox': checkboxInputType,
21199
21200  'hidden': noop,
21201  'button': noop,
21202  'submit': noop,
21203  'reset': noop,
21204  'file': noop
21205};
21206
21207function stringBasedInputType(ctrl) {
21208  ctrl.$formatters.push(function(value) {
21209    return ctrl.$isEmpty(value) ? value : value.toString();
21210  });
21211}
21212
21213function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21214  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21215  stringBasedInputType(ctrl);
21216}
21217
21218function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21219  var type = lowercase(element[0].type);
21220
21221  // In composition mode, users are still inputing intermediate text buffer,
21222  // hold the listener until composition is done.
21223  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
21224  if (!$sniffer.android) {
21225    var composing = false;
21226
21227    element.on('compositionstart', function(data) {
21228      composing = true;
21229    });
21230
21231    element.on('compositionend', function() {
21232      composing = false;
21233      listener();
21234    });
21235  }
21236
21237  var listener = function(ev) {
21238    if (timeout) {
21239      $browser.defer.cancel(timeout);
21240      timeout = null;
21241    }
21242    if (composing) return;
21243    var value = element.val(),
21244        event = ev && ev.type;
21245
21246    // By default we will trim the value
21247    // If the attribute ng-trim exists we will avoid trimming
21248    // If input type is 'password', the value is never trimmed
21249    if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
21250      value = trim(value);
21251    }
21252
21253    // If a control is suffering from bad input (due to native validators), browsers discard its
21254    // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
21255    // control's value is the same empty value twice in a row.
21256    if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
21257      ctrl.$setViewValue(value, event);
21258    }
21259  };
21260
21261  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
21262  // input event on backspace, delete or cut
21263  if ($sniffer.hasEvent('input')) {
21264    element.on('input', listener);
21265  } else {
21266    var timeout;
21267
21268    var deferListener = function(ev, input, origValue) {
21269      if (!timeout) {
21270        timeout = $browser.defer(function() {
21271          timeout = null;
21272          if (!input || input.value !== origValue) {
21273            listener(ev);
21274          }
21275        });
21276      }
21277    };
21278
21279    element.on('keydown', function(event) {
21280      var key = event.keyCode;
21281
21282      // ignore
21283      //    command            modifiers                   arrows
21284      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
21285
21286      deferListener(event, this, this.value);
21287    });
21288
21289    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
21290    if ($sniffer.hasEvent('paste')) {
21291      element.on('paste cut', deferListener);
21292    }
21293  }
21294
21295  // if user paste into input using mouse on older browser
21296  // or form autocomplete on newer browser, we need "change" event to catch it
21297  element.on('change', listener);
21298
21299  ctrl.$render = function() {
21300    element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
21301  };
21302}
21303
21304function weekParser(isoWeek, existingDate) {
21305  if (isDate(isoWeek)) {
21306    return isoWeek;
21307  }
21308
21309  if (isString(isoWeek)) {
21310    WEEK_REGEXP.lastIndex = 0;
21311    var parts = WEEK_REGEXP.exec(isoWeek);
21312    if (parts) {
21313      var year = +parts[1],
21314          week = +parts[2],
21315          hours = 0,
21316          minutes = 0,
21317          seconds = 0,
21318          milliseconds = 0,
21319          firstThurs = getFirstThursdayOfYear(year),
21320          addDays = (week - 1) * 7;
21321
21322      if (existingDate) {
21323        hours = existingDate.getHours();
21324        minutes = existingDate.getMinutes();
21325        seconds = existingDate.getSeconds();
21326        milliseconds = existingDate.getMilliseconds();
21327      }
21328
21329      return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
21330    }
21331  }
21332
21333  return NaN;
21334}
21335
21336function createDateParser(regexp, mapping) {
21337  return function(iso, date) {
21338    var parts, map;
21339
21340    if (isDate(iso)) {
21341      return iso;
21342    }
21343
21344    if (isString(iso)) {
21345      // When a date is JSON'ified to wraps itself inside of an extra
21346      // set of double quotes. This makes the date parsing code unable
21347      // to match the date string and parse it as a date.
21348      if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
21349        iso = iso.substring(1, iso.length - 1);
21350      }
21351      if (ISO_DATE_REGEXP.test(iso)) {
21352        return new Date(iso);
21353      }
21354      regexp.lastIndex = 0;
21355      parts = regexp.exec(iso);
21356
21357      if (parts) {
21358        parts.shift();
21359        if (date) {
21360          map = {
21361            yyyy: date.getFullYear(),
21362            MM: date.getMonth() + 1,
21363            dd: date.getDate(),
21364            HH: date.getHours(),
21365            mm: date.getMinutes(),
21366            ss: date.getSeconds(),
21367            sss: date.getMilliseconds() / 1000
21368          };
21369        } else {
21370          map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
21371        }
21372
21373        forEach(parts, function(part, index) {
21374          if (index < mapping.length) {
21375            map[mapping[index]] = +part;
21376          }
21377        });
21378        return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
21379      }
21380    }
21381
21382    return NaN;
21383  };
21384}
21385
21386function createDateInputType(type, regexp, parseDate, format) {
21387  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
21388    badInputChecker(scope, element, attr, ctrl);
21389    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21390    var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
21391    var previousDate;
21392
21393    ctrl.$$parserName = type;
21394    ctrl.$parsers.push(function(value) {
21395      if (ctrl.$isEmpty(value)) return null;
21396      if (regexp.test(value)) {
21397        // Note: We cannot read ctrl.$modelValue, as there might be a different
21398        // parser/formatter in the processing chain so that the model
21399        // contains some different data format!
21400        var parsedDate = parseDate(value, previousDate);
21401        if (timezone) {
21402          parsedDate = convertTimezoneToLocal(parsedDate, timezone);
21403        }
21404        return parsedDate;
21405      }
21406      return undefined;
21407    });
21408
21409    ctrl.$formatters.push(function(value) {
21410      if (value && !isDate(value)) {
21411        throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
21412      }
21413      if (isValidDate(value)) {
21414        previousDate = value;
21415        if (previousDate && timezone) {
21416          previousDate = convertTimezoneToLocal(previousDate, timezone, true);
21417        }
21418        return $filter('date')(value, format, timezone);
21419      } else {
21420        previousDate = null;
21421        return '';
21422      }
21423    });
21424
21425    if (isDefined(attr.min) || attr.ngMin) {
21426      var minVal;
21427      ctrl.$validators.min = function(value) {
21428        return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
21429      };
21430      attr.$observe('min', function(val) {
21431        minVal = parseObservedDateValue(val);
21432        ctrl.$validate();
21433      });
21434    }
21435
21436    if (isDefined(attr.max) || attr.ngMax) {
21437      var maxVal;
21438      ctrl.$validators.max = function(value) {
21439        return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
21440      };
21441      attr.$observe('max', function(val) {
21442        maxVal = parseObservedDateValue(val);
21443        ctrl.$validate();
21444      });
21445    }
21446
21447    function isValidDate(value) {
21448      // Invalid Date: getTime() returns NaN
21449      return value && !(value.getTime && value.getTime() !== value.getTime());
21450    }
21451
21452    function parseObservedDateValue(val) {
21453      return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
21454    }
21455  };
21456}
21457
21458function badInputChecker(scope, element, attr, ctrl) {
21459  var node = element[0];
21460  var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
21461  if (nativeValidation) {
21462    ctrl.$parsers.push(function(value) {
21463      var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
21464      // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
21465      // - also sets validity.badInput (should only be validity.typeMismatch).
21466      // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
21467      // - can ignore this case as we can still read out the erroneous email...
21468      return validity.badInput && !validity.typeMismatch ? undefined : value;
21469    });
21470  }
21471}
21472
21473function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21474  badInputChecker(scope, element, attr, ctrl);
21475  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21476
21477  ctrl.$$parserName = 'number';
21478  ctrl.$parsers.push(function(value) {
21479    if (ctrl.$isEmpty(value))      return null;
21480    if (NUMBER_REGEXP.test(value)) return parseFloat(value);
21481    return undefined;
21482  });
21483
21484  ctrl.$formatters.push(function(value) {
21485    if (!ctrl.$isEmpty(value)) {
21486      if (!isNumber(value)) {
21487        throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
21488      }
21489      value = value.toString();
21490    }
21491    return value;
21492  });
21493
21494  if (isDefined(attr.min) || attr.ngMin) {
21495    var minVal;
21496    ctrl.$validators.min = function(value) {
21497      return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
21498    };
21499
21500    attr.$observe('min', function(val) {
21501      if (isDefined(val) && !isNumber(val)) {
21502        val = parseFloat(val, 10);
21503      }
21504      minVal = isNumber(val) && !isNaN(val) ? val : undefined;
21505      // TODO(matsko): implement validateLater to reduce number of validations
21506      ctrl.$validate();
21507    });
21508  }
21509
21510  if (isDefined(attr.max) || attr.ngMax) {
21511    var maxVal;
21512    ctrl.$validators.max = function(value) {
21513      return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
21514    };
21515
21516    attr.$observe('max', function(val) {
21517      if (isDefined(val) && !isNumber(val)) {
21518        val = parseFloat(val, 10);
21519      }
21520      maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
21521      // TODO(matsko): implement validateLater to reduce number of validations
21522      ctrl.$validate();
21523    });
21524  }
21525}
21526
21527function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21528  // Note: no badInputChecker here by purpose as `url` is only a validation
21529  // in browsers, i.e. we can always read out input.value even if it is not val
21529id!
21530  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21531  stringBasedInputType(ctrl);
21532
21533  ctrl.$$parserName = 'url';
21534  ctrl.$validators.url = function(modelValue, viewValue) {
21535    var value = modelValue || viewValue;
21536    return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
21537  };
21538}
21539
21540function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
21541  // Note: no badInputChecker here by purpose as `url` is only a validation
21542  // in browsers, i.e. we can always read out input.value even if it is not valid!
21543  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
21544  stringBasedInputType(ctrl);
21545
21546  ctrl.$$parserName = 'email';
21547  ctrl.$validators.email = function(modelValue, viewValue) {
21548    var value = modelValue || viewValue;
21549    return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
21550  };
21551}
21552
21553function radioInputType(scope, element, attr, ctrl) {
21554  // make the name unique, if not defined
21555  if (isUndefined(attr.name)) {
21556    element.attr('name', nextUid());
21557  }
21558
21559  var listener = function(ev) {
21560    if (element[0].checked) {
21561      ctrl.$setViewValue(attr.value, ev && ev.type);
21562    }
21563  };
21564
21565  element.on('click', listener);
21566
21567  ctrl.$render = function() {
21568    var value = attr.value;
21569    element[0].checked = (value == ctrl.$viewValue);
21570  };
21571
21572  attr.$observe('value', ctrl.$render);
21573}
21574
21575function parseConstantExpr($parse, context, name, expression, fallback) {
21576  var parseFn;
21577  if (isDefined(expression)) {
21578    parseFn = $parse(expression);
21579    if (!parseFn.constant) {
21580      throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
21581                                   '`{1}`.', name, expression);
21582    }
21583    return parseFn(context);
21584  }
21585  return fallback;
21586}
21587
21588function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
21589  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
21590  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
21591
21592  var listener = function(ev) {
21593    ctrl.$setViewValue(element[0].checked, ev && ev.type);
21594  };
21595
21596  element.on('click', listener);
21597
21598  ctrl.$render = function() {
21599    element[0].checked = ctrl.$viewValue;
21600  };
21601
21602  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
21603  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
21604  // it to a boolean.
21605  ctrl.$isEmpty = function(value) {
21606    return value === false;
21607  };
21608
21609  ctrl.$formatters.push(function(value) {
21610    return equals(value, trueValue);
21611  });
21612
21613  ctrl.$parsers.push(function(value) {
21614    return value ? trueValue : falseValue;
21615  });
21616}
21617
21618
21619/**
21620 * @ngdoc directive
21621 * @name textarea
21622 * @restrict E
21623 *
21624 * @description
21625 * HTML textarea element control with angular data-binding. The data-binding and validation
21626 * properties of this element are exactly the same as those of the
21627 * {@link ng.directive:input input element}.
21628 *
21629 * @param {string} ngModel Assignable angular expression to data-bind to.
21630 * @param {string=} name Property name of the form under which the control is published.
21631 * @param {string=} required Sets `required` validation error key if the value is not entered.
21632 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
21633 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
21634 *    `required` when you want to data-bind to the `required` attribute.
21635 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21636 *    minlength.
21637 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21638 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
21639 *    length.
21640 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21641 *    a RegExp found by evaluating the Angular expression given in the attribute value.
21642 *    If the expression evaluates to a RegExp object, then this is used directly.
21643 *    If the expression evaluates to a string, then it will be converted to a RegExp
21644 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21645 *    `new RegExp('^abc$')`.<br />
21646 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21647 *    start at the index of the last search's match, thus not taking the whole input value into
21648 *    account.
21649 * @param {string=} ngChange Angular expression to be executed when input changes due to user
21650 *    interaction with the input element.
21651 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
21652 */
21653
21654
21655/**
21656 * @ngdoc directive
21657 * @name input
21658 * @restrict E
21659 *
21660 * @description
21661 * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
21662 * input state control, and validation.
21663 * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
21664 *
21665 * <div class="alert alert-warning">
21666 * **Note:** Not every feature offered is available for all input types.
21667 * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
21668 * </div>
21669 *
21670 * @param {string} ngModel Assignable angular expression to data-bind to.
21671 * @param {string=} name Property name of the form under which the control is published.
21672 * @param {string=} required Sets `required` validation error key if the value is not entered.
21673 * @param {boolean=} ngRequired Sets `required` attribute if set to true
21674 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
21675 *    minlength.
21676 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
21677 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
21678 *    length.
21679 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
21680 *    a RegExp found by evaluating the Angular expression given in the attribute value.
21681 *    If the expression evaluates to a RegExp object, then this is used directly.
21682 *    If the expression evaluates to a string, then it will be converted to a RegExp
21683 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
21684 *    `new RegExp('^abc$')`.<br />
21685 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
21686 *    start at the index of the last search's match, thus not taking the whole input value into
21687 *    account.
21688 * @param {string=} ngChange Angular expression to be executed when input changes due to user
21689 *    interaction with the input element.
21690 * @param {boolean=} [ngTrim=true] If set to false Angular
vendor: 4,842 bytes, lines 21690-21808
21690 will not automatically trim the input.
21691 *    This parameter is ignored for input[type=password] controls, which will never trim the
21692 *    input.
21693 *
21694 * @example
21695    <example name="input-directive" module="inputExample">
21696      <file name="index.html">
21697       <script>
21698          angular.module('inputExample', [])
21699            .controller('ExampleController', ['$scope', function($scope) {
21700              $scope.user = {name: 'guest', last: 'visitor'};
21701            }]);
21702       </script>
21703       <div ng-controller="ExampleController">
21704         <form name="myForm">
21705           <label>
21706              User name:
21707              <input type="text" name="userName" ng-model="user.name" required>
21708           </label>
21709           <div role="alert">
21710             <span class="error" ng-show="myForm.userName.$error.required">
21711              Required!</span>
21712           </div>
21713           <label>
21714              Last name:
21715              <input type="text" name="lastName" ng-model="user.last"
21716              ng-minlength="3" ng-maxlength="10">
21717           </label>
21718           <div role="alert">
21719             <span class="error" ng-show="myForm.lastName.$error.minlength">
21720               Too short!</span>
21721             <span class="error" ng-show="myForm.lastName.$error.maxlength">
21722               Too long!</span>
21723           </div>
21724         </form>
21725         <hr>
21726         <tt>user = {{user}}</tt><br/>
21727         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
21728         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
21729         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
21730         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
21731         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
21732         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
21733         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
21734         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
21735       </div>
21736      </file>
21737      <file name="protractor.js" type="protractor">
21738        var user = element(by.exactBinding('user'));
21739        var userNameValid = element(by.binding('myForm.userName.$valid'));
21740        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
21741        var lastNameError = element(by.binding('myForm.lastName.$error'));
21742        var formValid = element(by.binding('myForm.$valid'));
21743        var userNameInput = element(by.model('user.name'));
21744        var userLastInput = element(by.model('user.last'));
21745
21746        it('should initialize to model', function() {
21747          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
21748          expect(userNameValid.getText()).toContain('true');
21749          expect(formValid.getText()).toContain('true');
21750        });
21751
21752        it('should be invalid if empty when required', function() {
21753          userNameInput.clear();
21754          userNameInput.sendKeys('');
21755
21756          expect(user.getText()).toContain('{"last":"visitor"}');
21757          expect(userNameValid.getText()).toContain('false');
21758          expect(formValid.getText()).toContain('false');
21759        });
21760
21761        it('should be valid if empty when min length is set', function() {
21762          userLastInput.clear();
21763          userLastInput.sendKeys('');
21764
21765          expect(user.getText()).toContain('{"name":"guest","last":""}');
21766          expect(lastNameValid.getText()).toContain('true');
21767          expect(formValid.getText()).toContain('true');
21768        });
21769
21770        it('should be invalid if less than required min length', function() {
21771          userLastInput.clear();
21772          userLastInput.sendKeys('xx');
21773
21774          expect(user.getText()).toContain('{"name":"guest"}');
21775          expect(lastNameValid.getText()).toContain('false');
21776          expect(lastNameError.getText()).toContain('minlength');
21777          expect(formValid.getText()).toContain('false');
21778        });
21779
21780        it('should be invalid if longer than max length', function() {
21781          userLastInput.clear();
21782          userLastInput.sendKeys('some ridiculously long name');
21783
21784          expect(user.getText()).toContain('{"name":"guest"}');
21785          expect(lastNameValid.getText()).toContain('false');
21786          expect(lastNameError.getText()).toContain('maxlength');
21787          expect(formValid.getText()).toContain('false');
21788        });
21789      </file>
21790    </example>
21791 */
21792var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
21793    function($browser, $sniffer, $filter, $parse) {
21794  return {
21795    restrict: 'E',
21796    require: ['?ngModel'],
21797    link: {
21798      pre: function(scope, element, attr, ctrls) {
21799        if (ctrls[0]) {
21800          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
21801                                                              $browser, $filter, $parse);
21802        }
21803      }
21804    }
21805  };
21806}];
21807
21808
21809
21810var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
21811/**
21812 * @ngdoc directive
21813 * @name ngValue
21814 *
21815 * @description
21816 * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
21817 * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
21818 * the bound value.
21819 *
21820 * `ngValue` is useful when dynamically generating lists of radio buttons using
21821 * {@link ngRepeat `ngRepeat`}, as shown below.
21822 *
21823 * Likewise, `ngValue` can be used to generate `<option>` elements for
21824 * the {@link select `select`} element. In that case however, only strings are supported
21825 * for the `value `attribute, so the resulting `ngModel` will always be a string.
21826 * Support for `select` models with non-string values is available via `ngOptions`.
21827 *
21828 * @element input
21829 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
21830 *   of the `input` element
21831 *
21832 * @example
21833    <example name="ngValue-directive" module="valueExample">
21834      <file name="index.html">
21835       <script>
21836          angular.module('valueExample', [])
21837            .controller('ExampleController', ['$scope', function($scope) {
21838              $scope.names = ['pizza', 'unicorns', 'robots'];
21839              $scope.my = { favorite: 'unicorns' };
21840            }]);
21841       </script>
21842        <form ng-controller="ExampleController">
21843          <h2>Which is your favorite?</h2>
21844            <label ng-repeat="name in names" for="{{name}}">
21845              {{name}}
21846              <input type="radio"
21847                     ng-model="my.favorite"
21848                     ng-value="name"
21849                     id="{{name}}"
21850                     name="favorite">
21851            </label>
21852          <div>You chose {{my.favorite}}</div>
21853        </form>
21854      </file>
21855      <file name="protractor.js" type="protractor">
21856        var favorite = element(by.binding('my.favorite'));
21857
21858        it('should initialize to model', function() {
21859          expect(favorite.getText()).toContain('unicorns');
21860        });
21861        it('should bind the values to the inputs', function() {
21862          element.all(by.model('my.favorite')).get(0).click();
21863          expect(favorite.getText()).toContain('pizza');
21864        });
21865      </file>
21866    </example>
21867 */
21868var ngValueDirective = function() {
21869  return {
21870    restrict: 'A',
21871    priority: 100,
21872    compile: function(tpl, tplAttr) {
21873      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
21874        return function ngValueConstantLink(scope, elm, attr) {
21875          attr.$set('value', scope.$eval(attr.ngValue));
21876        };
21877      } else {
21878        return function ngValueLink(scope, elm, attr) {
21879          scope.$watch(attr.ngValue, function valueWatchAction(value) {
21880            attr.$set('value', value);
21881          });
21882        };
21883      }
21884    }
21885  };
21886};
21887
21888/**
21889 * @ngdoc directive
21890 * @name ngBind
21891 * @restrict AC
21892 *
21893 * @description
21894 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
21895 * with the value of a given expression, and to update the text content when the value of that
21896 * expression changes.
21897 *
21898 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
21899 * `{{ expression }}` which is similar but less verbose.
21900 *
21901 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
21902 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
21903 * element attribute, it makes the bindings invisible to the user while the page is loading.
21904 *
21905 * An alternative solution to this problem would be using the
21906 * {@link ng.directive:ngCloak ngCloak} directive.
21907 *
21908 *
21909 * @element ANY
21910 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
21911 *
21912 * @example
21913 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
21914   <example module="bindExample">
21915     <file name="index.html">
21916       <script>
21917         angular.module('bindExample', [])
21918           .controller('ExampleController', ['$scope', function($scope) {
21919             $scope.name = 'Whirled';
21920           }]);
21921       </script>
21922       <div ng-controller="ExampleController">
21923         <label>Enter name: <input type="text" ng-model="name"></label><br>
21924         Hello <span ng-bind="name"></span>!
21925       </div>
21926     </file>
21927     <file name="protractor.js" type="protractor">
21928       it('should check ng-bind', function() {
21929         var nameInput = element(by.model('name'));
21930
21931         expect(element(by.binding('name')).getText()).toBe('Whirled');
21932         nameInput.clear();
21933         nameInput.sendKeys('world');
21934         expect(element(by.binding('name')).getText()).toBe('world');
21935       });
21936     </file>
21937   </example>
21938 */
21939var ngBindDirective = ['$compile', function($compile) {
21940  return {
21941    restrict: 'AC',
21942    compile: function ngBindCompile(templateElement) {
21943      $compile.$$addBindingClass(templateElement);
21944      return function ngBindLink(scope, element, attr) {
21945        $compile.$$addBindingInfo(element, attr.ngBind);
21946        element = element[0];
21947        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
21948          element.textContent = value === undefined ? '' : value;
21949        });
21950      };
21951    }
21952  };
21953}];
21954
21955
21956/**
21957 * @ngdoc directive
21958 * @name ngBindTemplate
21959 *
21960 * @description
21961 * The `ngBindTemplate` directive specifies that the element
21962 * text content should be replaced with the interpolation of the template
21963 * in the `ngBindTemplate` attribute.
21964 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
21965 * expressions. This directive is needed since some HTML elements
21966 * (such as TITLE and OPTION) cannot contain SPAN elements.
21967 *
21968 * @element ANY
21969 * @param {string} ngBindTemplate template of form
21970 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
21971 *
21972 * @example
21973 * Try it here: enter text in text box and watch the greeting change.
21974   <example module="bindExample">
21975     <file name="index.html">
21976       <script>
21977         angular.module('bindExample', [])
21978           .controller('ExampleController', ['$scope', function($scope) {
21979             $scope.salutation = 'Hello';
21980             $scope.name = 'World';
21981           }]);
21982       </script>
21983       <div ng-controller="ExampleController">
21984        <label>Salutation: <input type="text" ng-model="salutation"></label><br>
21985        <label>Name: <input type="text" ng-model="name"></label><br>
21986        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
21987       </div>
21988     </file>
21989     <file name="protractor.js" type="protractor">
21990       it('should check ng-bind', function() {
21991         var salutationElem = element(by.binding('salutation'));
21992         var salutationInput = element(by.model('salutation'));
21993         var nameInput = element(by.model('name'));
21994
21995         expect(salutationElem.getText()).toBe('Hello World!');
21996
21997         salutationInput.clear();
21998         salutationInput.sendKeys('Greetings');
21999         nameInput.clear();
22000         nameInput.sendKeys('user');
22001
22002         expect(salutationElem.getText()).toBe('Greetings user!');
22003       });
22004     </file>
22005   </example>
22006 */
22007var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
22008  return {
22009    compile: function ngBindTemplateCompile(templateElement) {
22010      $compile.$$addBindingClass(templateElement);
22011      return function ngBindTemplateLink(scope, element, attr) {
22012        var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
22013        $compile.$$addBindingInfo(element, interpolateFn.expressions);
22014        element = element[0];
22015        attr.$observe('ngBindTemplate', function(value) {
22016          element.textContent = value === undefined ? '' : value;
22017        });
22018      };
22019    }
22020  };
22021}];
22022
22023
22024/**
22025 * @ngdoc directive
22026 * @name ngBindHtml
22027 *
22028 * @description
22029 * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
22030 * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
22031 * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
22032 * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
22033 * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
22034 *
22035 * You may also bypass sanitization for values you know are safe. To do so, bind to
22036 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
22037 * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
22038 *
22039 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
22040 * will have an exception (instead of an exploit.)
22041 *
22042 * @element ANY
22043 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
22044 *
22045 * @example
22046
22047   <example module="bindHtmlExample" deps="angular-sanitize.js">
22048     <file name="index.html">
22049       <div ng-controller="ExampleController">
22050        <p ng-bind-html="myHTML"></p>
22051       </div>
22052     </file>
22053
22054     <file name="script.js">
22055       angular.module('bindHtmlExample', ['ngSanitize'])
22056         .controller('ExampleController', ['$scope', function($scope) {
22057           $scope.myHTML =
22058              'I am an <code>HTML</code>string with ' +
22059              '<a href="#">links!</a> and other <em>stuff</em>';
22060         }]);
22061     </file>
22062
22063     <file name="protractor.js" type="protractor">
22064       it('should check ng-bind-html', function() {
22065         expect(element(by.binding('myHTML')).getText()).toBe(
22066             'I am an HTMLstring with links! and other stuff');
22067       });
22068     </file>
22069   </example>
22070 */
22071var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
22072  return {
22073    restrict: 'A',
22074    compile: function ngBindHtmlCompile(tElement, tAttrs) {
22075      var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
22076      var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
22077        return (value || '').toString();
22078      });
22079      $compile.$$addBindingClass(tElement);
22080
22081      return function ngBindHtmlLink(scope, element, attr) {
22082        $compile.$$addBindingInfo(element, attr.ngBindHtml);
22083
22084        scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
22085          // we re-evaluate the expr because we want a TrustedValueHolderType
22086          // for $sce, not a string
22087          element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
22088        });
22089      };
22090    }
22091  };
22092}];
22093
22094/**
22095 * @ngdoc directive
22096 * @name ngChange
22097 *
22098 * @description
22099 * Evaluate the given expression when the user changes the input.
22100 * The expression is evaluated immediately, unlike the JavaScript onchange event
22101 * which only triggers at the end of a change (usually, when the user leaves the
22102 * form element or presses the return key).
22103 *
22104 * The `ngChange` expression is only evaluated when a change in the input value causes
22105 * a new value to be committed to the model.
22106 *
22107 * It will not be evaluated:
22108 * * if the value returned from the `$parsers` transformation pipeline has not changed
22109 * * if the input has continued to be invalid since the model will stay `null`
22110 * * if the model is changed programmatically and not by a change to the input value
22111 *
22112 *
22113 * Note, this directive requires `ngModel` to be present.
22114 *
22115 * @element input
22116 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
22117 * in input value.
22118 *
22119 * @example
22120 * <example name="ngChange-directive" module="changeExample">
22121 *   <file name="index.html">
22122 *     <script>
22123 *       angular.module('changeExample', [])
22124 *         .controller('ExampleController', ['$scope', function($scope) {
22125 *           $scope.counter = 0;
22126 *           $scope.change = function() {
22127 *             $scope.counter++;
22128 *           };
22129 *         }]);
22130 *     </script>
22131 *     <div ng-controller="ExampleController">
22132 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
22133 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
22134 *       <label for="ng-change-example2">Confirmed</label><br />
22135 *       <tt>debug = {{confirmed}}</tt><br/>
22136 *       <tt>counter = {{counter}}</tt><br/>
22137 *     </div>
22138 *   </file>
22139 *   <file name="protractor.js" type="protractor">
22140 *     var counter = element(by.binding('counter'));
22141 *     var debug = element(by.binding('confirmed'));
22142 *
22143 *     it('should evaluate the expression if changing from view', function() {
22144 *       expect(counter.getText()).toContain('0');
22145 *
22146 *       element(by.id('ng-change-example1')).click();
22147 *
22148 *       expect(counter.getText()).toContain('1');
22149 *       expect(debug.getText()).toContain('true');
22150 *     });
22151 *
22152 *     it('should not evaluate the expression if changing from model', function() {
22153 *       element(by.id('ng-change-example2')).click();
22154
22155 *       expect(counter.getText()).toContain('0');
22156 *       expect(debug.getText()).toContain('true');
22157 *     });
22158 *   </file>
22159 * </example>
22160 */
22161var ngChangeDirective = valueFn({
22162  restrict: 'A',
22163  require: 'ngModel',
22164  link: function(scope, element, attr, ctrl) {
22165    ctrl.$viewChangeListeners.push(function() {
22166      scope.$eval(attr.ngChange);
22167    });
22168  }
22169});
22170
22171function classDirective(name, selector) {
22172  name = 'ngClass' + name;
22173  return ['$animate', function($animate) {
22174    return {
22175      restrict: 'AC',
22176      link: function(scope, element, attr) {
22177        var oldVal;
22178
22179        scope.$watch(attr[name], ngClassWatchAction, true);
22180
22181        attr.$observe('class', function(value) {
22182          ngClassWatchAction(scope.$eval(attr[name]));
22183        });
22184
22185
22186        if (name !== 'ngClass') {
22187          scope.$watch('$index', function($index, old$index) {
22188            // jshint bitwise: false
22189            var mod = $index & 1;
22190            if (mod !== (old$index & 1)) {
22191              var classes = arrayClasses(scope.$eval(attr[name]));
22192              mod === selector ?
22193                addClasses(classes) :
22194                removeClasses(classes);
22195            }
22196          });
22197        }
22198
22199        function addClasses(classes) {
22200          var newClasses = digestClassCounts(classes, 1);
22201          attr.$addClass(newClasses);
22202        }
22203
22204        function removeClasses(classes) {
22205          var newClasses = digestClassCounts(classes, -1);
22206          attr.$removeClass(newClasses);
22207        }
22208
22209        function digestClassCounts(classes, count) {
22210          // Use createMap() to prevent class assumptions involving property
22211          // names in Object.prototype
22212          var classCounts = element.data('$classCounts') || createMap();
22213          var classesToUpdate = [];
22214          forEach(classes, function(className) {
22215            if (count > 0 || classCounts[className]) {
22216              classCounts[className] = (classCounts[className] || 0) + count;
22217              if (classCounts[className] === +(count > 0)) {
22218                classesToUpdate.push(className);
22219              }
22220            }
22221          });
22222          element.data('$classCounts', classCounts);
22223          return classesToUpdate.join(' ');
22224        }
22225
22226        function updateClasses(oldClasses, newClasses) {
22227          var toAdd = arrayDifference(newClasses, oldClasses);
22228          var toRemove = arrayDifference(oldClasses, newClasses);
22229          toAdd = digestClassCounts(toAdd, 1);
22230          toRemove = digestClassCounts(toRemove, -1);
22231          if (toAdd && toAdd.length) {
22232            $animate.addClass(element, toAdd);
22233          }
22234          if (toRemove && toRemove.length) {
22235            $animate.removeClass(element, toRemove);
22236          }
22237        }
22238
22239        function ngClassWatchAction(newVal) {
22240          if (selector === true || scope.$index % 2 === selector) {
22241            var newClasses = arrayClasses(newVal || []);
22242            if (!oldVal) {
22243              addClasses(newClasses);
22244            } else if (!equals(newVal,oldVal)) {
22245              var oldClasses = arrayClasses(oldVal);
22246              updateClasses(oldClasses, newClasses);
22247            }
22248          }
22249          oldVal = shallowCopy(newVal);
22250        }
22251      }
22252    };
22253
22254    function arrayDifference(tokens1, tokens2) {
22255      var values = [];
22256
22257      outer:
22258      for (var i = 0; i < tokens1.length; i++) {
22259        var token = tokens1[i];
22260        for (var j = 0; j < tokens2.length; j++) {
22261          if (token == tokens2[j]) continue outer;
22262        }
22263        values.push(token);
22264      }
22265      return values;
22266    }
22267
22268    function arrayClasses(classVal) {
22269      var classes = [];
22270      if (isArray(classVal)) {
22271        forEach(classVal, function(v) {
22272          classes = classes.concat(arrayClasses(v));
22273        });
22274        return classes;
22275      } else if (isString(classVal)) {
22276        return classVal.split(' ');
22277      } else if (isObject(classVal)) {
22278        forEach(classVal, function(v, k) {
22279          if (v) {
22280            classes = classes.concat(k.split(' '));
22281          }
22282        });
22283        return classes;
22284      }
22285      return classVal;
22286    }
22287  }];
22288}
22289
22290/**
22291 * @ngdoc directive
22292 * @name ngClass
22293 * @restrict AC
22294 *
22295 * @description
22296 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
22297 * an expression that represents all classes to be added.
22298 *
22299 * The directive operates in three different ways, depending on which of three types the expression
22300 * evaluates to:
22301 *
22302 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
22303 * names.
22304 *
22305 * 2. If the expression evaluates to an object, then for each key-value pair of the
22306 * object with a truthy value the corresponding key is used as a class name.
22307 *
22308 * 3. If the expression evaluates to an array, each element of the array should either be a string as in
22309 * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
22310 * to give you more control over what CSS classes appear. See the code below for an example of this.
22311 *
22312 *
22313 * The directive won't add duplicate classes if a particular class was already set.
22314 *
22315 * When the expression changes, the previously added classes are removed and only then are the
22316 * new classes added.
22317 *
22318 * @animations
22319 * **add** - happens just before the class is applied to the elements
22320 *
22321 * **remove** - happens just before the class is removed from the element
22322 *
22323 * @element ANY
22324 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
22325 *   of the evaluation can be a string representing space delimited class
22326 *   names, an array, or a map of class names to boolean values. In the case of a map, the
22327 *   names of the properties whose values are truthy will be added as css classes to the
22328 *   element.
22329 *
22330 * @example Example that demonstrates basic bindings via ngClass directive.
22331   <example>
22332     <file name="index.html">
22333       <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
22334       <label>
22335          <input type="checkbox" ng-model="deleted">
22336          deleted (apply "strike" class)
22337       </label><br>
22338       <label>
22339          <input type="checkbox" ng-model="important">
22340          important (apply "bold" class)
22341       </label><br>
22342       <label>
22343          <input type="checkbox" ng-model="error">
22344          error (apply "red" class)
22345       </label>
22346       <hr>
22347       <p ng-class="style">Using String Syntax</p>
22348       <input type="text" ng-model="style"
22349              placeholder="Type: bold strike red" aria-label="Type: bold strike red">
22350       <hr>
22351       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
22352       <input ng-model="style1"
22353              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
22354       <input ng-model="style2"
22355              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
22356       <input ng-model="style3"
22357              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
22358       <hr>
22359       <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
22360       <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
22361       <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
22362     </file>
22363     <file name="style.css">
22364       .strike {
22365           text-decoration: line-through;
22366       }
22367       .bold {
22368           font-weight: bold;
22369       }
22370       .red {
22371           color: red;
22372       }
22373       .orange {
22374           color: orange;
22375       }
22376     </file>
22377     <file name="protractor.js" type="protractor">
22378       var ps = element.all(by.css('p'));
22379
22380       it('should let you toggle the class', function() {
22381
22382         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
22383         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
22384
22385         element(by.model('important')).click();
22386         expect(ps.first().getAttribute('class')).toMatch(/bold/);
22387
22388         element(by.model('error')).click();
22389         expect(ps.first().getAttribute('class')).toMatch(/red/);
22390       });
22391
22392       it('should let you toggle string example', function() {
22393         expect(ps.get(1).getAttribute('class')).toBe('');
22394         element(by.model('style')).clear();
22395         element(by.model('style')).sendKeys('red');
22396         expect(ps.get(1).getAttribute('class')).toBe('red');
22397       });
22398
22399       it('array example should have 3 classes', function() {
22400         expect(ps.get(2).getAttribute('class')).toBe('');
22401         element(by.model('style1')).sendKeys('bold');
22402         element(by.model('style2')).sendKeys('strike');
22403         element(by.model('style3')).sendKeys('red');
22404         expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
22405       });
22406
22407       it('array with map example should have 2 classes', function() {
22408         expect(ps.last().getAttribute('class')).toBe('');
22409         element(by.model('style4')).sendKeys('bold');
22410         element(by.model('warning')).click();
22411         expect(ps.last().getAttribute('class')).toBe('bold orange');
22412       });
22413     </file>
22414   </example>
22415
22416   ## Animations
22417
22418   The example below demonstrates how to perform animations using ngClass.
22419
22420   <example module="ngAnimate" deps="angular-animate.js" animations="true">
22421     <file name="index.html">
22422      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
22423      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
22424      <br>
22425      <span class="base-class" ng-class="myVar">Sample Text</span>
22426     </file>
22427     <file name="style.css">
22428       .base-class {
22429         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22430         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
22431       }
22432
22433       .base-class.my-class {
22434         color: red;
22435         font-size:3em;
22436       }
22437     </file>
22438     <file name="protractor.js" type="protractor">
22439       it('should check ng-class', function() {
22440         expect(element(by.css('.base-class')).getAttribute('class')).not.
22441           toMatch(/my-class/);
22442
22443         element(by.id('setbtn')).click();
22444
22445         expect(element(by.css('.base-class')).getAttribute('class')).
22446           toMatch(/my-class/);
22447
22448         element(by.id('clearbtn')).click();
22449
22450         expect(element(by.css('.base-class')).getAttribute('class')).not.
22451           toMatch(/my-class/);
22452       });
22453     </file>
22454   </example>
22455
22456
22457   ## ngClass and pre-existing CSS3 Transitions/Animations
22458   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
22459   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
22460   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
22461   to view the step by step details of {@link $animate#addClass $animate.addClass} and
22462   {@link $animate#removeClass $animate.removeClass}.
22463 */
22464var ngClassDirective = classDirective('', true);
22465
22466/**
22467 * @ngdoc directive
22468 * @name ngClassOdd
22469 * @restrict AC
22470 *
22471 * @description
22472 * The `ngClassOdd` and `ngClassEven` directives work exactly as
22473 * {@link ng.directive:ngClass ngClass}, except they work in
22474 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
22475 *
22476 * This directive can be applied only within the scope of an
22477 * {@link ng.directive:ngRepeat ngRepeat}.
22478 *
22479 * @element ANY
22480 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
22481 *   of the evaluation can be a string representing space delimited class names or an array.
22482 *
22483 * @example
22484   <example>
22485     <file name="index.html">
22486        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
22487          <li ng-repeat="name in names">
22488           <span ng-class-odd="'odd'" ng-class-even="'even'">
22489             {{name}}
22490           </span>
22491          </li>
22492        </ol>
22493     </file>
22494     <file name="style.css">
22495       .odd {
22496         color: red;
22497       }
22498       .even {
22499         color: blue;
22500       }
22501     </file>
22502     <file name="protractor.js" type="protractor">
22503       it('should check ng-class-odd and ng-class-even', function() {
22504         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
22505           toMatch(/odd/);
22506         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
22507           toMatch(/even/);
22508       });
22509     </file>
22510   </example>
22511 */
22512var ngClassOddDirective = classDirective('Odd', 0);
22513
22514/**
22515 * @ngdoc directive
22516 * @name ngClassEven
22517 * @restrict AC
22518 *
22519 * @description
22520 * The `ngClassOdd` and `ngClassEven` directives work exactly as
22521 * {@link ng.directive:ngClass ngClass}, except they work in
22522 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
22523 *
22524 * This directive can be applied only within the scope of an
22525 * {@link ng.directive:ngRepeat ngRepeat}.
22526 *
22527 * @element ANY
22528 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
22529 *   result of the evaluation can be a string representing space delimited class names or an array.
22530 *
22531 * @example
22532   <example>
22533     <file name="index.html">
22534        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
22535          <li ng-repeat="name in names">
22536           <span ng-class-odd="'odd'" ng-class-even="'even'">
22537             {{name}} &nbsp; &nbsp; &nbsp;
22538           </span>
22539          </li>
22540        </ol>
22541     </file>
22542     <file name="style.css">
22543       .odd {
22544         color: red;
22545       }
22546       .even {
22547         color: blue;
22548       }
22549     </file>
22550     <file name="protractor.js" type="protractor">
22551       it('should check ng-class-odd and ng-class-even', function() {
22552         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
22553           toMatch(/odd/);
22554         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
22555           toMatch(/even/);
22556       });
22557     </file>
22558   </example>
22559 */
22560var ngClassEvenDirective = classDirective('Even', 1);
22561
22562/**
22563 * @ngdoc directive
22564 * @name ngCloak
22565 * @restrict AC
22566 *
22567 * @description
22568 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
22569 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
22570 * directive to avoid the undesirable flicker effect caused by the html template display.
22571 *
22572 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
22573 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
22574 * of the browser view.
22575 *
22576 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
22577 * `angular.min.js`.
22578 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
22579 *
22580 * ```css
22581 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
22582 *   display: none !important;
22583 * }
22584 * ```
22585 *
22586 * When this css rule is loaded by the browser, all html elements (including their children) that
22587 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
22588 * during the compilation of the template it deletes the `ngCloak` element attribute, making
22589 * the compiled element visible.
22590 *
22591 * For the best result, the `angular.js` script must be loaded in the head section of the html
22592 * document; alternatively, the css rule above must be included in the external stylesheet of the
22593 * application.
22594 *
22595 * @element ANY
22596 *
22597 * @example
22598   <example>
22599     <file name="index.html">
22600        <div id="template1" ng-cloak>{{ 'hello' }}</div>
22601        <div id="template2" class="ng-cloak">{{ 'world' }}</div>
22602     </file>
22603     <file name="protractor.js" type="protractor">
22604       it('should remove the template directive and css class', function() {
22605         expect($('#template1').getAttribute('ng-cloak')).
22606           toBeNull();
22607         expect($('#template2').getAttribute('ng-cloak')).
22608           toBeNull();
22609       });
22610     </file>
22611   </example>
22612 *
22613 */
22614var ngCloakDirective = ngDirective({
22615  compile: function(element, attr) {
22616    attr.$set('ngCloak', undefined);
22617    element.removeClass('ng-cloak');
22618  }
22619});
22620
22621/**
22622 * @ngdoc directive
22623 * @name ngController
22624 *
22625 * @description
22626 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
22627 * supports the principles behind the Model-View-Controller design pattern.
22628 *
22629 * MVC components in angular:
22630 *
22631 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
22632 *   are accessed through bindings.
22633 * * View — The template (HTML with data bindings) that is rendered into the View.
22634 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
22635 *   logic behind the application to decorate the scope with functions and values
22636 *
22637 * Note that you can also attach controllers to the DOM by declaring it in a route definition
22638 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
22639 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
22640 * and executed twice.
22641 *
22642 * @element ANY
22643 * @scope
22644 * @priority 500
22645 * @param {expression} ngController Name of a constructor function registered with the current
22646 * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
22647 * that on the current scope evaluates to a constructor function.
22648 *
22649 * The controller instance can be published into a scope property by specifying
22650 * `ng-controller="as propertyName"`.
22651 *
22652 * If the current `$controllerProvider` is configured to use globals (via
22653 * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
22654 * also be the name of a globally accessible constructor function (not recommended).
22655 *
22656 * @example
22657 * Here is a simple form for editing user contact information. Adding, remov
22657ing, clearing, and
22658 * greeting are methods declared on the controller (see source tab). These methods can
22659 * easily be called from the angular markup. Any changes to the data are automatically reflected
22660 * in the View without the need for a manual update.
22661 *
22662 * Two different declaration styles are included below:
22663 *
22664 * * one binds methods and properties directly onto the controller using `this`:
22665 * `ng-controller="SettingsController1 as settings"`
22666 * * one injects `$scope` into the controller:
22667 * `ng-controller="SettingsController2"`
22668 *
22669 * The second option is more common in the Angular community, and is generally used in boilerplates
22670 * and in this guide. However, there are advantages to binding properties directly to the controller
22671 * and avoiding scope.
22672 *
22673 * * Using `controller as` makes it obvious which controller you are accessing in the template when
22674 * multiple controllers apply to an element.
22675 * * If you are writing your controllers as classes you have easier access to the properties and
22676 * methods, which will appear on the scope, from inside the controller code.
22677 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
22678 * inheritance masking primitives.
22679 *
22680 * This example demonstrates the `controller as` syntax.
22681 *
22682 * <example name="ngControllerAs" module="controllerAsExample">
22683 *   <file name="index.html">
22684 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
22685 *      <label>Name: <input type="text" ng-model="settings.name"/></label>
22686 *      <button ng-click="settings.greet()">greet</button><br/>
22687 *      Contact:
22688 *      <ul>
22689 *        <li ng-repeat="contact in settings.contacts">
22690 *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
22691 *             <option>phone</option>
22692 *             <option>email</option>
22693 *          </select>
22694 *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
22695 *          <button ng-click="settings.clearContact(contact)">clear</button>
22696 *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
22697 *        </li>
22698 *        <li><button ng-click="settings.addContact()">add</button></li>
22699 *     </ul>
22700 *    </div>
22701 *   </file>
22702 *   <file name="app.js">
22703 *    angular.module('controllerAsExample', [])
22704 *      .controller('SettingsController1', SettingsController1);
22705 *
22706 *    function SettingsController1() {
22707 *      this.name = "John Smith";
22708 *      this.contacts = [
22709 *        {type: 'phone', value: '408 555 1212'},
22710 *        {type: 'email', value: '[email protected]'} ];
22711 *    }
22712 *
22713 *    SettingsController1.prototype.greet = function() {
22714 *      alert(this.name);
22715 *    };
22716 *
22717 *    SettingsController1.prototype.addContact = function() {
22718 *      this.contacts.push({type: 'email', value: '[email protected]'});
22719 *    };
22720 *
22721 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
22722 *     var index = this.contacts.indexOf(contactToRemove);
22723 *      this.contacts.splice(index, 1);
22724 *    };
22725 *
22726 *    SettingsController1.prototype.clearContact = function(contact) {
22727 *      contact.type = 'phone';
22728 *      contact.value = '';
22729 *    };
22730 *   </file>
22731 *   <file name="protractor.js" type="protractor">
22732 *     it('should check controller as', function() {
22733 *       var container = element(by.id('ctrl-as-exmpl'));
22734 *         expect(container.element(by.model('settings.name'))
22735 *           .getAttribute('value')).toBe('John Smith');
22736 *
22737 *       var firstRepeat =
22738 *           container.element(by.repeater('contact in settings.contacts').row(0));
22739 *       var secondRepeat =
22740 *           container.element(by.repeater('contact in settings.contacts').row(1));
22741 *
22742 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
22743 *           .toBe('408 555 1212');
22744 *
22745 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
22746 *           .toBe('[email protected]');
22747 *
22748 *       firstRepeat.element(by.buttonText('clear')).click();
22749 *
22750 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
22751 *           .toBe('');
22752 *
22753 *       container.element(by.buttonText('add')).click();
22754 *
22755 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
22756 *           .element(by.model('contact.value'))
22757 *           .getAttribute('value'))
22758 *           .toBe('[email protected]');
22759 *     });
22760 *   </file>
22761 * </example>
22762 *
22763 * This example demonstrates the "attach to `$scope`" style of controller.
22764 *
22765 * <example name="ngController" module="controllerExample">
22766 *  <file name="index.html">
22767 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
22768 *     <label>Name: <input type="text" ng-model="name"/></label>
22769 *     <button ng-click="greet()">greet</button><br/>
22770 *     Contact:
22771 *     <ul>
22772 *       <li ng-repeat="contact in contacts">
22773 *         <select ng-model="contact.type" id="select_{{$index}}">
22774 *            <option>phone</option>
22775 *            <option>email</option>
22776 *         </select>
22777 *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
22778 *         <button ng-click="clearContact(contact)">clear</button>
22779 *         <button ng-click="removeContact(contact)">X</button>
22780 *       </li>
22781 *       <li>[ <button ng-click="addContact()">add</button> ]</li>
22782 *    </ul>
22783 *   </div>
22784 *  </file>
22785 *  <file name="app.js">
22786 *   angular.module('controllerExample', [])
22787 *     .controller('SettingsController2', ['$scope', SettingsController2]);
22788 *
22789 *   function SettingsController2($scope) {
22790 *     $scope.name = "John Smith";
22791 *     $scope.contacts = [
22792 *       {type:'phone', value:'408 555 1212'},
22793 *       {type:'email', value:'[email protected]'} ];
22794 *
22795 *     $scope.greet = function() {
22796 *       alert($scope.name);
22797 *     };
22798 *
22799 *     $scope.addContact = function() {
22800 *       $scope.contacts.push({type:'email', value:'[email protected]'});
22801 *     };
22802 *
22803 *     $scope.removeContact = function(contactToRemove) {
22804 *       var index = $scope.contacts.indexOf(contactToRemove);
22805 *       $scope.contacts.splice(index, 1);
22806 *     };
22807 *
22808 *     $scope.clearContact = function(contact) {
22809 *       contact.type = 'phone';
22810 *       contact.value = '';
22811 *     };
22812 *   }
22813 *  </file>
22814 *  <file name="protractor.js" type="protractor">
22815 *    it('should check controller', function() {
22816 *      var container = element(by.id('ctrl-exmpl'));
22817 *
22818 *      expect(container.element(by.model('name'))
22819 *          .getAttribute('value')).toBe('John Smith');
22820 *
22821 *      var firstRepeat =
22822 *          container.element(by.repeater('contact in contacts').row(0));
22823 *      var secondRepeat =
22824 *          container.element(by.repeater('contact in contacts').row(1));
22825 *
22826 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
22827 *          .toBe('408 555 1212');
22828 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
22829 *          .toBe('[email protected]');
22830 *
22831 *      firstRepeat.element(by.buttonText('clear')).click();
22832 *
22833 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
22834 *          .toBe('');
22835 *
22836 *      container.element(by.buttonText('add')).click();
22837 *
22838 *      expect(container.element(by.repeater('contact in contacts').row(2))
22839 *          .element(by.model('contact.value'))
22840 *          .getAttribute('value'))
22841 *          .toBe('[email protected]');
22842 *    });
22843 *  </file>
22844 *</example>
22845
22846 */
22847var ngControllerDirective = [function() {
22848  return {
22849    restrict: 'A',
22850    scope: true,
22851    controller: '@',
22852    priority: 500
22853  };
22854}];
22855
22856/**
22857 * @ngdoc directive
22858 * @name ngCsp
22859 *
22860 * @element html
22861 * @description
22862 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
22863 *
22864 * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
22865 *
22866 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
22867 * For Angular to be CSP compatible there are only two things that we need to do differently:
22868 *
22869 * - don't use `Function` constructor to generate optimized value getters
22870 * - don't inject custom stylesheet into the document
22871 *
22872 * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
22873 * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
22874 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
22875 * be raised.
22876 *
22877 * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
22878 * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
22879 * To make those directives work in CSP mode, include the `angular-csp.css` manually.
22880 *
22881 * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
22882 * autodetection however triggers a CSP error to be logged in the console:
22883 *
22884 * ```
22885 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
22886 * script in the following Content Security Policy directive: "default-src 'self'". Note that
22887 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
22888 * ```
22889 *
22890 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
22891 * directive on the root element of the application or on the `angular.js` script tag, whichever
22892 * appears first in the html document.
22893 *
22894 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
22895 *
22896 * @example
22897 * This example shows how to apply the `ngCsp` directive to the `html` tag.
22898   ```html
22899     <!doctype html>
22900     <html ng-app ng-csp>
22901     ...
22902     ...
22903     </html>
22904   ```
22905  * @example
22906      // Note: the suffix `.csp` in the example name triggers
22907      // csp mode in our http server!
22908      <example name="example.csp" module="cspExample" ng-csp="true">
22909        <file name="index.html">
22910          <div ng-controller="MainController as ctrl">
22911            <div>
22912              <button ng-click="ctrl.inc()" id="inc">Increment</button>
22913              <span id="counter">
22914                {{ctrl.counter}}
22915              </span>
22916            </div>
22917
22918            <div>
22919              <button ng-click="ctrl.evil()" id="evil">Evil</button>
22920              <span id="evilError">
22921                {{ctrl.evilError}}
22922              </span>
22923            </div>
22924          </div>
22925        </file>
22926        <file name="script.js">
22927           angular.module('cspExample', [])
22928             .controller('MainController', function() {
22929                this.counter = 0;
22930                this.inc = function() {
22931                  this.counter++;
22932                };
22933                this.evil = function() {
22934                  // jshint evil:true
22935                  try {
22936                    eval('1+2');
22937                  } catch (e) {
22938                    this.evilError = e.message;
22939                  }
22940                };
22941              });
22942        </file>
22943        <file name="protractor.js" type="protractor">
22944          var util, webdriver;
22945
22946          var incBtn = element(by.id('inc'));
22947          var counter = element(by.id('counter'));
22948          var evilBtn = element(by.id('evil'));
22949          var evilError = element(by.id('evilError'));
22950
22951          function getAndClearSevereErrors() {
22952            return browser.manage().logs().get('browser').then(function(browserLog) {
22953              return browserLog.filter(function(logEntry) {
22954                return logEntry.level.value > webdriver.logging.Level.WARNING.value;
22955              });
22956            });
22957          }
22958
22959          function clearErrors() {
22960            getAndClearSevereErrors();
22961          }
22962
22963          function expectNoErrors() {
22964            getAndClearSevereErrors().then(function(filteredLog) {
22965              expect(filteredLog.length).toEqual(0);
22966              if (filteredLog.length) {
22967                console.log('browser console errors: ' + util.inspect(filteredLog));
22968              }
22969            });
22970          }
22971
22972          function expectError(regex) {
22973            getAndClearSevereErrors().then(function(filteredLog) {
22974              var found = false;
22975              filteredLog.forEach(function(log) {
22976                if (log.message.match(regex)) {
22977                  found = true;
22978                }
22979              });
22980              if (!found) {
22981                throw new Error('expected an error that matches ' + regex);
22982              }
22983            });
22984          }
22985
22986          beforeEach(function() {
22987            util = require('util');
22988            webdriver = require('protractor/node_modules/selenium-webdriver');
22989          });
22990
22991          // For now, we only test on Chrome,
22992          // as Safari does not load the page with Protractor's injected scripts,
22993          // and Firefox webdriver always disables content security policy (#6358)
22994          if (browser.params.browser !== 'chrome') {
22995            return;
22996          }
22997
22998          it('should not report errors when the page is loaded', function() {
22999            // clear errors so we are not dependent on previous tests
23000            clearErrors();
23001            // Need to reload the page as the page is already loaded when
23002            // we come here
23003            browser.driver.getCurrentUrl().then(function(url) {
23004              browser.get(url);
23005            });
23006            expectNoErrors();
23007          });
23008
23009          it('should evaluate expressions', function() {
23010            expect(counter.getText()).toEqual('0');
23011            incBtn.click();
23012            expect(counter.getText()).toEqual('1');
23013            expectNoErrors();
23014          });
23015
23016          it('should throw and report an error when using "eval"', function() {
23017            evilBtn.click();
23018            expect(evilError.getText()).toMatch(/Content Security Policy/);
23019            expectError(/Content Security Policy/);
23020          });
23021        </file>
23022      </example>
23023  */
23024
23025// ngCsp is not implemented as a proper directive any more, because we need it be processed while we
23026// bootstrap the system (before $parse is instantiated), for this reason we just have
23027// the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
23028
23029/**
23030 * @ngdoc directive
23031 * @name ngClick
23032 *
23033 * @description
23034 * The ngClick directive allows you to specify custom behavior when
23035 * an element is clicked.
23036 *
23037 * @element ANY
23038 * @priority 0
23039 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
23040 * click. ({@link guide/expression#-event- Event object is available as `$event`})
23041 *
23042 * @example
23043   <example>
23044     <file name="index.html">
23045      <button ng-click="count = count + 1" ng-init="count=0">
23046        Increment
23047      </button>
23048      <span>
23049        count: {{count}}
23050      </span>
23051     </file>
23052     <file name="protractor.js" type="protractor">
23053       it('should check ng-click', function() {
23054         expect(element(by.binding('count')).getText()).toMatch('0');
23055         element(by.css('button')).click();
23056         expect(element(by.binding('count')).getText()).toMatch('1');
23057       });
23058     </file>
23059   </example>
23060 */
23061/*
23062 * A collection of directives that allows creation of custom event handlers that are defined as
23063 * angular expressions and are compiled and executed within the current scope.
23064 */
23065var ngEventDirectives = {};
23066
23067// For events that might fire synchronously during DOM manipulation
23068// we need to execute their event handlers asynchronously using $evalAsync,
23069// so that they are not executed in an inconsistent state.
23070var forceAsyncEvents = {
23071  'blur': true,
23072  'focus': true
23073};
23074forEach(
23075  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
23076  function(eventName) {
23077    var directiveName = directiveNormalize('ng-' + eventName);
23078    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
23079      return {
23080        restrict: 'A',
23081        compile: function($element, attr) {
23082          // We expose the powerful $event object on the scope that provides access to the Window,
23083          // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
23084          // checks at the cost of speed since event handler expressions are not executed as
23085          // frequently as regular change detection.
23086          var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
23087          return function ngEventHandler(scope, element) {
23088            element.on(eventName, function(event) {
23089              var callback = function() {
23090                fn(scope, {$event:event});
23091              };
23092              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
23093                scope.$evalAsync(callback);
23094              } else {
23095                scope.$apply(callback);
23096              }
23097            });
23098          };
23099        }
23100      };
23101    }];
23102  }
23103);
23104
23105/**
23106 * @ngdoc directive
23107 * @name ngDblclick
23108 *
23109 * @description
23110 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
23111 *
23112 * @element ANY
23113 * @priority 0
23114 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
23115 * a dblclick. (The Event object is available as `$event`)
23116 *
23117 * @example
23118   <example>
23119     <file name="index.html">
23120      <button ng-dblclick="count = count + 1" ng-init="count=0">
23121        Increment (on double click)
23122      </button>
23123      count: {{count}}
23124     </file>
23125   </example>
23126 */
23127
23128
23129/**
23130 * @ngdoc directive
23131 * @name ngMousedown
23132 *
23133 * @description
23134 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
23135 *
23136 * @element ANY
23137 * @priority 0
23138 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
23139 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
23140 *
23141 * @example
23142   <example>
23143     <file name="index.html">
23144      <button ng-mousedown="count = count + 1" ng-init="count=0">
23145        Increment (on mouse down)
23146      </button>
23147      count: {{count}}
23148     </file>
23149   </example>
23150 */
23151
23152
23153/**
23154 * @ngdoc directive
23155 * @name ngMouseup
23156 *
23157 * @description
23158 * Specify custom behavior on mouseup event.
23159 *
23160 * @element ANY
23161 * @priority 0
23162 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
23163 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
23164 *
23165 * @example
23166   <example>
23167     <file name="index.html">
23168      <button ng-mouseup="count = count + 1" ng-init="count=0">
23169        Increment (on mouse up)
23170      </button>
23171      count: {{count}}
23172     </file>
23173   </example>
23174 */
23175
23176/**
23177 * @ngdoc directive
23178 * @name ngMouseover
23179 *
23180 * @description
23181 * Specify custom behavior on mouseover event.
23182 *
23183 * @element ANY
23184 * @priority 0
23185 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
23186 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
23187 *
23188 * @example
23189   <example>
23190     <file name="index.html">
23191      <button ng-mouseover="count = count + 1" ng-init="count=0">
23192        Increment (when mouse is over)
23193      </button>
23194      count: {{count}}
23195     </file>
23196   </example>
23197 */
23198
23199
23200/**
23201 * @ngdoc directive
23202 * @name ngMouseenter
23203 *
23204 * @description
23205 * Specify custom behavior on mouseenter event.
23206 *
23207 * @element ANY
23208 * @priority 0
23209 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
23210 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
23211 *
23212 * @example
23213   <example>
23214     <file name="index.html">
23215      <button ng-mouseenter="count = count + 1" ng-init="count=0">
23216        Increment (when mouse enters)
23217      </button>
23218      count: {{count}}
23219     </file>
23220   </example>
23221 */
23222
23223
23224/**
23225 * @ngdoc directive
23226 * @name ngMouseleave
23227 *
23228 * @description
23229 * Specify custom behavior on mouseleave event.
23230 *
23231 * @element ANY
23232 * @priority 0
23233 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
23234 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
23235 *
23236 * @example
23237   <example>
23238     <file name="index.html">
23239      <button ng-mouseleave="count = count + 1" ng-init="count=0">
23240        Increment (when mouse leaves)
23241      </button>
23242      count: {{count}}
23243     </file>
23244   </example>
23245 */
23246
23247
23248/**
23249 * @ngdoc directive
23250 * @name ngMousemove
23251 *
23252 * @description
23253 * Specify custom behavior on mousemove event.
23254 *
23255 * @element ANY
23256 * @priority 0
23257 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
23258 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
23259 *
23260 * @example
23261   <example>
23262     <file name="index.html">
23263      <button ng-mousemove="count = count + 1" ng-init="count=0">
23264        Increment (when mouse moves)
23265      </button>
23266      count: {{count}}
23267     </file>
23268   </example>
23269 */
23270
23271
23272/**
23273 * @ngdoc directive
23274 * @name ngKeydown
23275 *
23276 * @description
23277 * Specify custom behavior on keydown event.
23278 *
23279 * @element ANY
23280 * @priority 0
23281 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
23282 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23283 *
23284 * @example
23285   <example>
23286     <file name="index.html">
23287      <input ng-keydown="count = count + 1" ng-init="count=0">
23288      key down count: {{count}}
23289     </file>
23290   </example>
23291 */
23292
23293
23294/**
23295 * @ngdoc directive
23296 * @name ngKeyup
23297 *
23298 * @description
23299 * Specify custom behavior on keyup event.
23300 *
23301 * @element ANY
23302 * @priority 0
23303 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
23304 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
23305 *
23306 * @example
23307   <example>
23308     <file name="index.html">
23309       <p>Typing in the input box below updates the key count</p>
23310       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
23311
23312       <p>Typing in the input box below updates the keycode</p>
23313       <input ng-keyup="event=$event">
23314       <p>event keyCode: {{ event.keyCode }}</p>
23315       <p>event altKey: {{ event.altKey }}</p>
23316     </file>
23317   </example>
23318 */
23319
23320
23321/**
23322 * @ngdoc directive
23323 * @name ngKeypress
23324 *
23325 * @description
23326 * Specify custom behavior on keypress event.
23327 *
23328 * @element ANY
23329 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
23330 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
23331 * and can be interrogated for keyCode, altKey, etc.)
23332 *
23333 * @example
23334   <example>
23335     <file name="index.html">
23336      <input ng-keypress="count = count + 1" ng-init="count=0">
23337      key press count: {{count}}
23338     </file>
23339   </example>
23340 */
23341
23342
23343/**
23344 * @ngdoc directive
23345 * @name ngSubmit
23346 *
23347 * @description
23348 * Enables binding angular expressions to onsubmit events.
23349 *
23350 * Additionally it prevents the default action (which for form means 
23350sending the request to the
23351 * server and reloading the current page), but only if the form does not contain `action`,
23352 * `data-action`, or `x-action` attributes.
23353 *
23354 * <div class="alert alert-warning">
23355 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
23356 * `ngSubmit` handlers together. See the
23357 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
23358 * for a detailed discussion of when `ngSubmit` may be triggered.
23359 * </div>
23360 *
23361 * @element form
23362 * @priority 0
23363 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
23364 * ({@link guide/expression#-event- Event object is available as `$event`})
23365 *
23366 * @example
23367   <example module="submitExample">
23368     <file name="index.html">
23369      <script>
23370        angular.module('submitExample', [])
23371          .controller('ExampleController', ['$scope', function($scope) {
23372            $scope.list = [];
23373            $scope.text = 'hello';
23374            $scope.submit = function() {
23375              if ($scope.text) {
23376                $scope.list.push(this.text);
23377                $scope.text = '';
23378              }
23379            };
23380          }]);
23381      </script>
23382      <form ng-submit="submit()" ng-controller="ExampleController">
23383        Enter text and hit enter:
23384        <input type="text" ng-model="text" name="text" />
23385        <input type="submit" id="submit" value="Submit" />
23386        <pre>list={{list}}</pre>
23387      </form>
23388     </file>
23389     <file name="protractor.js" type="protractor">
23390       it('should check ng-submit', function() {
23391         expect(element(by.binding('list')).getText()).toBe('list=[]');
23392         element(by.css('#submit')).click();
23393         expect(element(by.binding('list')).getText()).toContain('hello');
23394         expect(element(by.model('text')).getAttribute('value')).toBe('');
23395       });
23396       it('should ignore empty strings', function() {
23397         expect(element(by.binding('list')).getText()).toBe('list=[]');
23398         element(by.css('#submit')).click();
23399         element(by.css('#submit')).click();
23400         expect(element(by.binding('list')).getText()).toContain('hello');
23401        });
23402     </file>
23403   </example>
23404 */
23405
23406/**
23407 * @ngdoc directive
23408 * @name ngFocus
23409 *
23410 * @description
23411 * Specify custom behavior on focus event.
23412 *
23413 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
23414 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
23415 * during an `$apply` to ensure a consistent state.
23416 *
23417 * @element window, input, select, textarea, a
23418 * @priority 0
23419 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
23420 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
23421 *
23422 * @example
23423 * See {@link ng.directive:ngClick ngClick}
23424 */
23425
23426/**
23427 * @ngdoc directive
23428 * @name ngBlur
23429 *
23430 * @description
23431 * Specify custom behavior on blur event.
23432 *
23433 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
23434 * an element has lost focus.
23435 *
23436 * Note: As the `blur` event is executed synchronously also during DOM manipulations
23437 * (e.g. removing a focussed input),
23438 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
23439 * during an `$apply` to ensure a consistent state.
23440 *
23441 * @element window, input, select, textarea, a
23442 * @priority 0
23443 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
23444 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
23445 *
23446 * @example
23447 * See {@link ng.directive:ngClick ngClick}
23448 */
23449
23450/**
23451 * @ngdoc directive
23452 * @name ngCopy
23453 *
23454 * @description
23455 * Specify custom behavior on copy event.
23456 *
23457 * @element window, input, select, textarea, a
23458 * @priority 0
23459 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
23460 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
23461 *
23462 * @example
23463   <example>
23464     <file name="index.html">
23465      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
23466      copied: {{copied}}
23467     </file>
23468   </example>
23469 */
23470
23471/**
23472 * @ngdoc directive
23473 * @name ngCut
23474 *
23475 * @description
23476 * Specify custom behavior on cut event.
23477 *
23478 * @element window, input, select, textarea, a
23479 * @priority 0
23480 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
23481 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
23482 *
23483 * @example
23484   <example>
23485     <file name="index.html">
23486      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
23487      cut: {{cut}}
23488     </file>
23489   </example>
23490 */
23491
23492/**
23493 * @ngdoc directive
23494 * @name ngPaste
23495 *
23496 * @description
23497 * Specify custom behavior on paste event.
23498 *
23499 * @element window, input, select, textarea, a
23500 * @priority 0
23501 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
23502 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
23503 *
23504 * @example
23505   <example>
23506     <file name="index.html">
23507      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
23508      pasted: {{paste}}
23509     </file>
23510   </example>
23511 */
23512
23513/**
23514 * @ngdoc directive
23515 * @name ngIf
23516 * @restrict A
23517 *
23518 * @description
23519 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
23520 * {expression}. If the expression assigned to `ngIf` evaluates to a false
23521 * value then the element is removed from the DOM, otherwise a clone of the
23522 * element is reinserted into the DOM.
23523 *
23524 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
23525 * element in the DOM rather than changing its visibility via the `display` css property.  A common
23526 * case when this difference is significant is when using css selectors that rely on an element's
23527 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
23527s.
23528 *
23529 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
23530 * is created when the element is restored.  The scope created within `ngIf` inherits from
23531 * its parent scope using
23532 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
23533 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
23534 * a javascript primitive defined in the parent scope. In this case any modifications made to the
23535 * variable within the child scope will override (hide) the value in the parent scope.
23536 *
23537 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
23538 * is if an element's class attribute is directly modified after it's compiled, using something like
23539 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
23540 * the added class will be lost because the original compiled state is used to regenerate the element.
23541 *
23542 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
23543 * and `leave` effects.
23544 *
23545 * @animations
23546 * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
23547 * leave - happens just before the `ngIf` contents are removed from the DOM
23548 *
23549 * @element ANY
23550 * @scope
23551 * @priority 600
23552 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
23553 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
23554 *     element is added to the DOM tree.
23555 *
23556 * @example
23557  <example module="ngAnimate" deps="angular-animate.js" animations="true">
23558    <file name="index.html">
23559      <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
23560      Show when checked:
23561      <span ng-if="checked" class="animate-if">
23562        This is removed when the checkbox is unchecked.
23563      </span>
23564    </file>
23565    <file name="animations.css">
23566      .animate-if {
23567        background:white;
23568        border:1px solid black;
23569        padding:10px;
23570      }
23571
23572      .animate-if.ng-enter, .animate-if.ng-leave {
23573        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23574        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23575      }
23576
23577      .animate-if.ng-enter,
23578      .animate-if.ng-leave.ng-leave-active {
23579        opacity:0;
23580      }
23581
23582      .animate-if.ng-leave,
23583      .animate-if.ng-enter.ng-enter-active {
23584        opacity:1;
23585      }
23586    </file>
23587  </example>
23588 */
23589var ngIfDirective = ['$animate', function($animate) {
23590  return {
23591    multiElement: true,
23592    transclude: 'element',
23593    priority: 600,
23594    terminal: true,
23595    restrict: 'A',
23596    $$tlb: true,
23597    link: function($scope, $element, $attr, ctrl, $transclude) {
23598        var block, childScope, previousElements;
23599        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
23600
23601          if (value) {
23602            if (!childScope) {
23603              $transclude(function(clone, newScope) {
23604                childScope = newScope;
23605                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
23606                // Note: We only need the first/last node of the cloned nodes.
23607                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
23608                // by a directive with templateUrl when its template arrives.
23609                block = {
23610                  clone: clone
23611                };
23612                $animate.enter(clone, $element.parent(), $element);
23613              });
23614            }
23615          } else {
23616            if (previousElements) {
23617              previousElements.remove();
23618              previousElements = null;
23619            }
23620            if (childScope) {
23621              childScope.$destroy();
23622              childScope = null;
23623            }
23624            if (block) {
23625              previousElements = getBlockNodes(block.clone);
23626              $animate.leave(previousElements).then(function() {
23627                previousElements = null;
23628              });
23629              block = null;
23630            }
23631          }
23632        });
23633    }
23634  };
23635}];
23636
23637/**
23638 * @ngdoc directive
23639 * @name ngInclude
23640 * @restrict ECA
23641 *
23642 * @description
23643 * Fetches, compiles and includes an external HTML fragment.
23644 *
23645 * By default, the template URL is restricted to the same domain and protocol as the
23646 * application document. This is done by calling {@link $sce#getTrustedResourceUrl
23647 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
23648 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
23649 * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
23650 * ng.$sce Strict Contextual Escaping}.
23651 *
23652 * In addition, the browser's
23653 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
23654 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
23655 * policy may further restrict whether the template is successfully loaded.
23656 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
23657 * access on some browsers.
23658 *
23659 * @animations
23660 * enter - animation is used to bring new content into the browser.
23661 * leave - animation is used to animate existing content away.
23662 *
23663 * The enter and leave animation occur concurrently.
23664 *
23665 * @scope
23666 * @priority 400
23667 *
23668 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
23669 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
23670 * @param {string=} onload Expression to evaluate when a new partial is loaded.
23671 *
23672 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
23673 *                  $anchorScroll} to scroll the viewport after the content is loaded.
23674 *
23675 *                  - If the attribute is not set, disable scrolling.
23676 *                  - If the attribute is set without value, enable scrolling.
23677 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
23678 *
23679 * @example
23680  <example module="includeExample" deps="angular-animate.js" animations="true">
23681    <file name="index.html">
23682     <div ng-controller="ExampleController">
23683       <select ng-model="template" ng-options="t.name for t in templates">
23684        <option value="">(blank)</option>
23685       </select>
23686       url of the template: <code>{{template.url}}</code>
23687       <hr/>
23688       <div class="slide-animate-container">
23689         <div class="slide-animate" ng-include="template.url"></div>
23690       </div>
23691     </div>
23692    </file>
23693    <file name="script.js">
23694      angular.module('includeExample', ['ngAnimate'])
23695        .controller('ExampleController', ['$scope', function($scope) {
23696          $scope.templates =
23697            [ { name: 'template1.html', url: 'template1.html'},
23698              { name: 'template2.html', url: 'template2.html'} ];
23699          $scope.template = $scope.templates[0];
23700        }]);
23701     </file>
23702    <file name="template1.html">
23703      Content of template1.html
23704    </file>
23705    <file name="template2.html">
23706      Content of template2.html
23707    </file>
23708    <file name="animations.css">
23709      .slide-animate-container {
23710        position:relative;
23711        background:white;
23712        border:1px solid black;
23713        height:40px;
23714        overflow:hidden;
23715      }
23716
23717      .slide-animate {
23718        padding:10px;
23719      }
23720
23721      .slide-animate.ng-enter, .slide-animate.ng-leave {
23722        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23723        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
23724
23725        position:absolute;
23726        top:0;
23727        left:0;
23728        right:0;
23729        bottom:0;
23730        display:block;
23731        padding:10px;
23732      }
23733
23734      .slide-animate.ng-enter {
23735        top:-50px;
23736      }
23737      .slide-animate.ng-enter.ng-enter-active {
23738        top:0;
23739      }
23740
23741      .slide-animate.ng-leave {
23742        top:0;
23743      }
23744      .slide-animate.ng-leave.ng-leave-active {
23745        top:50px;
23746      }
23747    </file>
23748    <file name="protractor.js" type="protractor">
23749      var templateSelect = element(by.model('template'));
23750      var includeElem = element(by.css('[ng-include]'));
23751
23752      it('should load template1.html', function() {
23753        expect(includeElem.getText()).toMatch(/Content of template1.html/);
23754      });
23755
23756      it('should load template2.html', function() {
23757        if (browser.params.browser == 'firefox') {
23758          // Firefox can't handle using selects
23759          // See https://github.com/angular/protractor/issues/480
23760          return;
23761        }
23762        templateSelect.click();
23763        templateSelect.all(by.css('option')).get(2).click();
23764        expect(includeElem.getText()).toMatch(/Content of template2.html/);
23765      });
23766
23767      it('should change to blank', function() {
23768        if (browser.params.browser == 'firefox') {
23769          // Firefox can't handle using selects
23770          return;
23771        }
23772        templateSelect.click();
23773        templateSelect.all(by.css('option')).get(0).click();
23774        expect(includeElem.isPresent()).toBe(false);
23775      });
23776    </file>
23777  </example>
23778 */
23779
23780
23781/**
23782 * @ngdoc event
23783 * @name ngInclude#$includeContentRequested
23784 * @eventType emit on the scope ngInclude was declared in
23785 * @description
23786 * Emitted every time the ngInclude content is requested.
23787 *
23788 * @param {Object} angularEvent Synthetic event object.
23789 * @param {String} src URL of content to load.
23790 */
23791
23792
23793/**
23794 * @ngdoc event
23795 * @name ngInclude#$includeContentLoaded
23796 * @eventType emit on the current ngInclude scope
23797 * @description
23798 * Emitted every time the ngInclude content is reloaded.
23799 *
23800 * @param {Object} angularEvent Synthetic event object.
23801 * @param {String} src URL of content to load.
23802 */
23803
23804
23805/**
23806 * @ngdoc event
23807 * @name ngInclude#$includeContentError
23808 * @eventType emit on the scope ngInclude was declared in
23809 * @description
23810 * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
23811 *
23812 * @param {Object} angularEvent Synthetic event object.
23813 * @param {String} src URL of content to load.
23814 */
23815var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
23816                  function($templateRequest,   $anchorScroll,   $animate,   $sce) {
23817  return {
23818    restrict: 'ECA',
23819    priority: 400,
23820    terminal: true,
23821    transclude: 'element',
23822    controller: angular.noop,
23823    compile: function(element, attr) {
23824      var srcExp = attr.ngInclude || attr.src,
23825          onloadExp = attr.onload || '',
23826          autoScrollExp = attr.autoscroll;
23827
23828      return function(scope, $element, $attr, ctrl, $transclude) {
23829        var changeCounter = 0,
23830            currentScope,
23831            previousElement,
23832            currentElement;
23833
23834        var cleanupLastIncludeContent = function() {
23835          if (previousElement) {
23836            previousElement.remove();
23837            previousElement = null;
23838          }
23839          if (currentScope) {
23840            currentScope.$destroy();
23841            currentScope = null;
23842          }
23843          if (currentElement) {
23844            $animate.leave(currentElement).then(function() {
23845              previousElement = null;
23846            });
23847            previousElement = currentElement;
23848            currentElement = null;
23849          }
23850        };
23851
23852        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
23853          var afterAnimation = function() {
23854            if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
23855              $anchorScroll();
23856            }
23857          };
23858          var thisChangeId = ++changeCounter;
23859
23860          if (src) {
23861            //set the 2nd param to true to ignore the template request error so that the inner
23862            //contents and scope can be cleaned up.
23863            $templateRequest(src, true).then(function(response) {
23864              if (thisChangeId !== changeCounter) return;
23865              var newScope = scope.$new();
23866              ctrl.template = response;
23867
23868              // Note: This will also link all children of ng-include that were contained in the original
23869              // html. If that content contains controllers, ... they could pollute/change the scope.
23870              // However, using ng-include on an element with additional content does not make sense...
23871              // Note: We can't remove them in the cloneAttchFn of $transclude as that
23872              // function is called before linking the content, which would apply child
23873              // directives to non existing elements.
23874              var clone = $transclude(newScope, function(clone) {
23875                cleanupLastIncludeContent();
23876                $animate.enter(clone, null, $element).then(afterAnimation);
23877              });
23878
23879              currentScope = newScope;
23880              currentElement = clone;
23881
23882              currentScope.$emit('$includeContentLoaded', src);
23883              scope.$eval(onloadExp);
23884            }, function() {
23885              if (thisChangeId === changeCounter) {
23886                cleanupLastIncludeContent();
vendor: 2,651 bytes, lines 23887-23967
23887                scope.$emit('$includeContentError', src);
23888              }
23889            });
23890            scope.$emit('$includeContentRequested', src);
23891          } else {
23892            cleanupLastIncludeContent();
23893            ctrl.template = null;
23894          }
23895        });
23896      };
23897    }
23898  };
23899}];
23900
23901// This directive is called during the $transclude call of the first `ngInclude` directive.
23902// It will replace and compile the content of the element with the loaded template.
23903// We need this directive so that the element content is already filled when
23904// the link function of another directive on the same element as ngInclude
23905// is called.
23906var ngIncludeFillContentDirective = ['$compile',
23907  function($compile) {
23908    return {
23909      restrict: 'ECA',
23910      priority: -400,
23911      require: 'ngInclude',
23912      link: function(scope, $element, $attr, ctrl) {
23913        if (/SVG/.test($element[0].toString())) {
23914          // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
23915          // support innerHTML, so detect this here and try to generate the contents
23916          // specially.
23917          $element.empty();
23918          $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
23919              function namespaceAdaptedClone(clone) {
23920            $element.append(clone);
23921          }, {futureParentElement: $element});
23922          return;
23923        }
23924
23925        $element.html(ctrl.template);
23926        $compile($element.contents())(scope);
23927      }
23928    };
23929  }];
23930
23931/**
23932 * @ngdoc directive
23933 * @name ngInit
23934 * @restrict AC
23935 *
23936 * @description
23937 * The `ngInit` directive allows you to evaluate an expression in the
23938 * current scope.
23939 *
23940 * <div class="alert alert-danger">
23941 * The only appropriate use of `ngInit` is for aliasing special properties of
23942 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
23943 * should use {@link guide/controller controllers} rather than `ngInit`
23944 * to initialize values on a scope.
23945 * </div>
23946 * <div class="alert alert-warning">
23947 * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
23948 * sure you have parenthesis for correct precedence:
23949 * <pre class="prettyprint">
23950 * `<div ng-init="test1 = (data | orderBy:'name')"></div>`
23951 * </pre>
23952 * </div>
23953 *
23954 * @priority 450
23955 *
23956 * @element ANY
23957 * @param {expression} ngInit {@link guide/expression Expression} to eval.
23958 *
23959 * @example
23960   <example module="initExample">
23961     <file name="index.html">
23962   <script>
23963     angular.module('initExample', [])
23964       .controller('ExampleController', ['$scope', function($scope) {
23965         $scope.list = [['a', 'b'], ['c', 'd']];
23966       }]);
23967   </script>
23968   <div ng-controller="ExampleController">
23969     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
23970       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
23971          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
23972       </div>
23973     </div>
23974   </div>
23975     </file>
23976     <file name="protractor.js" type="protractor">
23977       it('should alias index positions', function() {
23978         var elements = element.all(by.css('.example-init'));
23979         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
23980         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
23981         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
23982         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
23983       });
23984     </file>
23985   </example>
23986 */
23987var ngInitDirective = ngDirective({
23988  priority: 450,
23989  compile: function() {
23990    return {
23991      pre: function(scope, element, attrs) {
23992        scope.$eval(attrs.ngInit);
23993      }
23994    };
23995  }
23996});
23997
23998/**
23999 * @ngdoc directive
24000 * @name ngList
24001 *
24002 * @description
24003 * Text input that converts between a delimited string and an array of strings. The default
24004 * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
24005 * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
24006 *
24007 * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
24008 * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
24009 *   list item is respected. This implies that the user of the directive is responsible for
24010 *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
24011 *   tab or newline character.
24012 * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
24013 *   when joining the list items back together) and whitespace around each list item is stripped
24014 *   before it is added to the model.
24015 *
24016 * ### Example with Validation
24017 *
24018 * <example name="ngList-directive" module="listExample">
24019 *   <file name="app.js">
24020 *      angular.module('listExample', [])
24021 *        .controller('ExampleController', ['$scope', function($scope) {
24022 *          $scope.names = ['morpheus', 'neo', 'trinity'];
24023 *        }]);
24024 *   </file>
24025 *   <file name="index.html">
24026 *    <form name="myForm" ng-controller="ExampleController">
24027 *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
24028 *      <span role="alert">
24029 *        <span class="error" ng-show="myForm.namesInput.$error.required">
24030 *        Required!</span>
24031 *      </span>
24032 *      <br>
24033 *      <tt>names = {{names}}</tt><br/>
24034 *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
24035 *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
24036 *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
24037 *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
24038 *     </form>
24039 *   </file>
24040 *   <file name="protractor.js" type="protractor">
24041 *     var listInput = element(by.model('names'));
24042 *     var names = element(by.exactBinding('names'));
24043 *     var valid = element(by.binding('myForm.namesInput.$valid'));
24044 *     var error = element(by.css('span.error'));
24045 *
24046 *     it('should initialize to model', function() {
24047 *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
24048 *       expect(valid.getText()).toContain('true');
24049 *       expect(error.getCssValue('display')).toBe('none');
24050 *     });
24051 *
24052 *     it('should be invalid if empty', function() {
24053 *       listInput.clear();
24054 *       listInput.sendKeys('');
24055 *
24056 *       expect(names.getText()).toContain('');
24057 *       expect(valid.getText()).toContain('false');
24058 *       expect(error.getCssValue('display')).not.toBe('none');
24059 *     });
24060 *   </file>
24061 * </example>
24062 *
24063 * ### Example - splitting on whitespace
24064 * <example name="ngList-directive-newlines">
24065 *   <file name="index.html">
24066 *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
24067 *    <pre>{{ list | json }}</pre>
24068 *   </file>
24069 *   <file name="protractor.js" type="protractor">
24070 *     it("should split the text by newlines", function() {
24071 *       var listInput = element(by.model('list'));
24072 *       var output = element(by.binding('list | json'));
24073 *       listInput.sendKeys('abc\ndef\nghi');
24074 *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
24075 *     });
24076 *   </file>
24077 * </example>
24078 *
24079 * @element input
24080 * @param {string=} ngList optional delimiter that should be used to split the value.
24081 */
24082var ngListDirective = function() {
24083  return {
24084    restrict: 'A',
24085    priority: 100,
24086    require: 'ngModel',
24087    link: function(scope, element, attr, ctrl) {
24088      // We want to control whitespace trimming so we use this convoluted approach
24089      // to access the ngList attribute, which doesn't pre-trim the attribute
24090      var ngList = element.attr(attr.$attr.ngList) || ', ';
24091      var trimValues = attr.ngTrim !== 'false';
24092      var separator = trimValues ? trim(ngList) : ngList;
24093
24094      var parse = function(viewValue) {
24095        // If the viewValue is invalid (say required but empty) it will be `undefined`
24096        if (isUndefined(viewValue)) return;
24097
24098        var list = [];
24099
24100        if (viewValue) {
24101          forEach(viewValue.split(separator), function(value) {
24102            if (value) list.push(trimValues ? trim(value) : value);
24103          });
24104        }
24105
24106        return list;
24107      };
24108
24109      ctrl.$parsers.push(parse);
24110      ctrl.$formatters.push(function(value) {
24111        if (isArray(value)) {
24112          return value.join(ngList);
24113        }
24114
24115        return undefined;
24116      });
24117
24118      // Override the standard $isEmpty because an empty array means the input is empty.
24119      ctrl.$isEmpty = function(value) {
24120        return !value || !value.length;
24121      };
24122    }
24123  };
24124};
24125
24126/* global VALID_CLASS: true,
24127  INVALID_CLASS: true,
24128  PRISTINE_CLASS: true,
24129  DIRTY_CLASS: true,
24130  UNTOUCHED_CLASS: true,
24131  TOUCHED_CLASS: true,
24132*/
24133
24134var VALID_CLASS = 'ng-valid',
24135    INVALID_CLASS = 'ng-invalid',
24136    PRISTINE_CLASS = 'ng-pristine',
24137    DIRTY_CLASS = 'ng-dirty',
24138    UNTOUCHED_CLASS = 'ng-untouched',
24139    TOUCHED_CLASS = 'ng-touched',
24140    PENDING_CLASS = 'ng-pending';
24141
24142
24143var $ngModelMinErr = new minErr('ngModel');
24144
24145/**
24146 * @ngdoc type
24147 * @name ngModel.NgModelController
24148 *
24149 * @property {string} $viewValue Actual string value in the view.
24150 * @property {*} $modelValue The value in the model that the control is bound to.
24151 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
24152       the control reads value from the DOM. The functions are called in array order, each passing
24153       its return value through to the next. The last return value is forwarded to the
24154       {@link ngModel.NgModelController#$validators `$validators`} collection.
24155
24156Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
24157`$viewValue`}.
24158
24159Returning `undefined` from a parser means a parse error occurred. In that case,
24160no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
24161will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
24162is set to `true`. The parse error is stored in `ngModel.$error.parse`.
24163
24164 *
24165 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
24166       the model value changes. The functions are called in reverse array order, each passing the value through to the
24167       next. The last return value is used as the actual DOM value.
24168       Used to format / convert values for display in the control.
24169 * ```js
24170 * function formatter(value) {
24171 *   if (value) {
24172 *     return value.toUpperCase();
24173 *   }
24174 * }
24175 * ngModel.$formatters.push(formatter);
24176 * ```
24177 *
24178 * @property {Object.<string, function>} $validators A collection of validators that are applied
24179 *      whenever the model value changes. The key value within the object refers to the name of the
24180 *      validator while the function refers to the validation operation. The validation operation is
24181 *      provided with the model value as an argument and must return a true or false value depending
24182 *      on the response of that validation.
24183 *
24184 * ```js
24185 * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
24186 *   var value = modelValue || viewValue;
24187 *   return /[0-9]+/.test(value) &&
24188 *          /[a-z]+/.test(value) &&
24189 *          /[A-Z]+/.test(value) &&
24190 *          /\W+/.test(value);
24191 * };
24192 * ```
24193 *
24194 * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
24195 *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
24196 *      is expected to return a promise when it is run during the model validation process. Once the promise
24197 *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
24198 *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
24199 *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
24200 *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
24201 *      will only run once all synchronous validators have passed.
24202 *
24203 * Please note that if $http is used then it is important that the server returns a success HTTP response code
24204 * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
24205 *
24206 * ```js
24207 * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
24208 *   var value = modelValue || viewValue;
24209 *
24210 *   // Lookup user by username
24211 *   return $http.get('/api/users/' + value).
24212 *      then(function resolved() {
24213 *        //username exists, this means validation fails
24214 *        return $q.reject('exists');
24215 *      }, function rejected() {
24216 *        //username does not exist, therefore this validation passes
24217 *        return true;
24218 *      });
24219 * };
24220 * ```
24221 *
24222 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
24223 *     view value has changed. It is called with no arguments, and its return value is ignored.
24224 *     This can be used in place of additional $watches against the model value.
24225 *
24226 * @property {Object} $error An object hash with all failing validator ids as keys.
24227 * @property {Object} $pending An object hash with all pending validator ids as keys.
24228 *
24229 * @property {boolean} $untouched True if control has not lost focus yet.
24230 * @property {boolean} $touched True if control has lost focus.
24231 * @property {boolean} $pristine True if user has not interacted with the control yet.
24232 * @property {boolean} $dirty True if user has already interacted with the control.
24233 * @property {boolean} $valid True if there is no error.
24234 * @property {boolean}
24234 $invalid True if at least one error on the control.
24235 * @property {string} $name The name attribute of the control.
24236 *
24237 * @description
24238 *
24239 * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
24240 * The controller contains services for data-binding, validation, CSS updates, and value formatting
24241 * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
24242 * listening to DOM events.
24243 * Such DOM related logic should be provided by other directives which make use of
24244 * `NgModelController` for data-binding to control elements.
24245 * Angular provides this DOM logic for most {@link input `input`} elements.
24246 * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
24247 * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
24248 *
24249 * @example
24250 * ### Custom Control Example
24251 * This example shows how to use `NgModelController` with a custom control to achieve
24252 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
24253 * collaborate together to achieve the desired result.
24254 *
24255 * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
24256 * contents be edited in place by the user.
24257 *
24258 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
24259 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
24260 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
24261 * that content using the `$sce` service.
24262 *
24263 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
24264    <file name="style.css">
24265      [contenteditable] {
24266        border: 1px solid black;
24267        background-color: white;
24268        min-height: 20px;
24269      }
24270
24271      .ng-invalid {
24272        border: 1px solid red;
24273      }
24274
24275    </file>
24276    <file name="script.js">
24277      angular.module('customControl', ['ngSanitize']).
24278        directive('contenteditable', ['$sce', function($sce) {
24279          return {
24280            restrict: 'A', // only activate on element attribute
24281            require: '?ngModel', // get a hold of NgModelController
24282            link: function(scope, element, attrs, ngModel) {
24283              if (!ngModel) return; // do nothing if no ng-model
24284
24285              // Specify how UI should be updated
24286              ngModel.$render = function() {
24287                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
24288              };
24289
24290              // Listen for change events to enable binding
24291              element.on('blur keyup change', function() {
24292                scope.$evalAsync(read);
24293              });
24294              read(); // initialize
24295
24296              // Write data to the model
24297              function read() {
24298                var html = element.html();
24299                // When we clear the content editable the browser leaves a <br> behind
24300                // If strip-br attribute is provided then we strip this out
24301                if ( attrs.stripBr && html == '<br>' ) {
24302                  html = '';
24303                }
24304                ngModel.$setViewValue(html);
24305              }
24306            }
24307          };
24308        }]);
24309    </file>
24310    <file name="index.html">
24311      <form name="myForm">
24312       <div contenteditable
24313            name="myWidget" ng-model="userContent"
24314            strip-br="true"
24315            required>Change me!</div>
24316        <span ng-show="myForm.myWidget.$error.required">Required!</span>
24317       <hr>
24318       <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
24319      </form>
24320    </file>
24321    <file name="protractor.js" type="protractor">
24322    it('should data-bind and become invalid', function() {
24323      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
24324        // SafariDriver can't handle contenteditable
24325        // and Firefox driver can't clear contenteditables very well
24326        return;
24327      }
24328      var contentEditable = element(by.css('[contenteditable]'));
24329      var content = 'Change me!';
24330
24331      expect(contentEditable.getText()).toEqual(content);
24332
24333      contentEditable.clear();
24334      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
24335      expect(contentEditable.getText()).toEqual('');
24336      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
24337    });
24338    </file>
24339 * </example>
24340 *
24341 *
24342 */
24343var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
24344    function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
24345  this.$viewValue = Number.NaN;
24346  this.$modelValue = Number.NaN;
24347  this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
24348  this.$validators = {};
24349  this.$asyncValidators = {};
24350  this.$parsers = [];
24351  this.$formatters = [];
24352  this.$viewChangeListeners = [];
24353  this.$untouched = true;
24354  this.$touched = false;
24355  this.$pristine = true;
24356  this.$dirty = false;
24357  this.$valid = true;
24358  this.$invalid = false;
24359  this.$error = {}; // keep invalid keys here
24360  this.$$success = {}; // keep valid keys here
24361  this.$pending = undefined; // keep pending keys here
24362  this.$name = $interpolate($attr.name || '', false)($scope);
24363
24364
24365  var parsedNgModel = $parse($attr.ngModel),
24366      parsedNgModelAssign = parsedNgModel.assign,
24367      ngModelGet = parsedNgModel,
24368      ngModelSet = parsedNgModelAssign,
24369      pendingDebounce = null,
24370      parserValid,
24371      ctrl = this;
24372
24373  this.$$setOptions = function(options) {
24374    ctrl.$options = options;
24375    if (options && options.getterSetter) {
24376      var invokeModelGetter = $parse($attr.ngModel + '()'),
24377          invokeModelSetter = $parse($attr.ngModel + '($$$p)');
24378
24379      ngModelGet = function($scope) {
24380        var modelValue = parsedNgModel($scope);
24381        if (isFunction(modelValue)) {
24382          modelValue = invokeModelGetter($scope);
24383        }
24384        return modelValue;
24385      };
24386      ngModelSet = function($scope, newValue) {
24387        if (isFunction(parsedNgModel($scope))) {
24388          invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
24389        } else {
24390          parsedNgModelAssign($scope, ctrl.$modelValue);
24391        }
24392      };
24393    } else if (!parsedNgModel.assign) {
24394      throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
24395          $attr.ngModel, startingTag($element));
24396    }
24397  };
24398
24399  /**
24400   * @ngdoc method
24401   * @name ngModel.NgModelController#$render
24402   *
24403   * @description
24404   * Called when the view needs to be updated. It is expected that the user of the ng-model
24405   * directive will implement this method.
24406   *
24407   * The `$render()` method is invoked in the following situations:
24408   *
24409   * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
24410   *   committed value then `$render()` is called to update the input control.
24411   * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
24412   *   the `$viewValue` are different from last time.
24413   *
24414   * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
24415   * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
24416   * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
24417   * invoked if you only change a property on the objects.
24418   */
24419  this.$render = noop;
24420
24421  /**
24422   * @ngdoc method
24423   * @name ngModel.NgModelController#$isEmpty
24424   *
24425   * @description
24426   * This is called when we need to determine if the value of an input is empty.
24427   *
24428   * For instance, the required directive does this to work out if the input has data or not.
24429   *
24430   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
24431   *
24432   * You can override this for input directives whose concept of being empty is different from the
24433   * default. The `checkboxInputType` directive does this because in its case a value of `false`
24434   * implies empty.
24435   *
24436   * @param {*} value The value of the input to check for emptiness.
24437   * @returns {boolean} True if `value` is "empty".
24438   */
24439  this.$isEmpty = function(value) {
24440    return isUndefined(value) || value === '' || value === null || value !== value;
24441  };
24442
24443  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
24444      currentValidationRunId = 0;
24445
24446  /**
24447   * @ngdoc method
24448   * @name ngModel.NgModelController#$setValidity
24449   *
24450   * @description
24451   * Change the validity state, and notify the form.
24452   *
24453   * This method can be called within $parsers/$formatters or a custom validation implementation.
24454   * However, in most cases it should be sufficient to use the `ngModel.$validators` and
24455   * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
24456   *
24457   * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
24458   *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
24459   *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
24460   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
24461   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
24462   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
24463   * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
24464   *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
24465   *                          Skipped is used by Angular when validators do not run because of parse errors and
24466   *                          when `$asyncValidators` do not run because any of the `$validators` failed.
24467   */
24468  addSetValidityMethod({
24469    ctrl: this,
24470    $element: $element,
24471    set: function(object, property) {
24472      object[property] = true;
24473    },
24474    unset: function(object, property) {
24475      delete object[property];
24476    },
24477    parentForm: parentForm,
24478    $animate: $animate
24479  });
24480
24481  /**
24482   * @ngdoc method
24483   * @name ngModel.NgModelController#$setPristine
24484   *
24485   * @description
24486   * Sets the control to its pristine state.
24487   *
24488   * This method can be called to remove the `ng-dirty` class and set the control to its pristine
24489   * state (`ng-pristine` class). A model is considered to be pristine when the control
24490   * has not been changed from when first compiled.
24491   */
24492  this.$setPristine = function() {
24493    ctrl.$dirty = false;
24494    ctrl.$pristine = true;
24495    $animate.removeClass($element, DIRTY_CLASS);
24496    $animate.addClass($element, PRISTINE_CLASS);
24497  };
24498
24499  /**
24500   * @ngdoc method
24501   * @name ngModel.NgModelController#$setDirty
24502   *
24503   * @description
24504   * Sets the control to its dirty state.
24505   *
24506   * This method can be called to remove the `ng-pristine` class and set the control to its dirty
24507   * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
24508   * from when first compiled.
24509   */
24510  this.$setDirty = function() {
24511    ctrl.$dirty = true;
24512    ctrl.$pristine = false;
24513    $animate.removeClass($element, PRISTINE_CLASS);
24514    $animate.addClass($element, DIRTY_CLASS);
24515    parentForm.$setDirty();
24516  };
24517
24518  /**
24519   * @ngdoc method
24520   * @name ngModel.NgModelController#$setUntouched
24521   *
24522   * @description
24523   * Sets the control to its untouched state.
24524   *
24525   * This method can be called to remove the `ng-touched` class and set the control to its
24526   * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
24527   * by default, however this function can be used to restore that state if the model has
24528   * already been touched by the user.
24529   */
24530  this.$setUntouched = function() {
24531    ctrl.$touched = false;
24532    ctrl.$untouched = true;
24533    $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
24534  };
24535
24536  /**
24537   * @ngdoc method
24538   * @name ngModel.NgModelController#$setTouched
24539   *
24540   * @description
24541   * Sets the control to its touched state.
24542   *
24543   * This method can be called to remove the `ng-untouched` class and set the control to its
24544   * touched state (`ng-touched` class). A model is considered to be touched when the user has
24545   * first focused the control element and then shifted focus away from the control (blur event).
24546   */
24547  this.$setTouched = function() {
24548    ctrl.$touched = true;
24549    ctrl.$untouched = false;
24550    $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
24551  };
24552
24553  /**
24554   * @ngdoc method
24555   * @name ngModel.NgModelController#$rollbackViewValue
24556   *
24557   * @description
24558   * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
24559   * which may be caused by a pending debounced event or because the input is waiting for a some
24560   * future event.
24561   *
24562   * If you have an input that uses `ng-model-options` to set up debounced events or events such
24563   * as blur you can have a situation where there is a period when the `$viewValue`
24564   * is out of synch with the ngModel's `$modelValue`.
24565   *
24566   * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
24567   * programmatically before these debounced/future events have resolved/occurred, because Angular's
24568   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
24569   *
24570   * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
24571   * input which may have such events pending. This is important in order to make sure that the
24572   * input field will be updated with the new model value and any pending operations are cancelled.
24573   *
24574   * <example name="ng-model-cancel-update" module="cancel-update-example">
24575   *   <file name="app.js">
24576   *     angular.module('cancel-update-example', [])
24577   *
24578   *     .controller('CancelUpdateController', ['$scope', function($scope) {
24579   *       $scope.resetWithCancel = function(e) {
24580   *         if (e.keyCode == 27) {
24581   *           $scope.myForm.myInput1.$rollbackViewValue();
24582   *           $scope.myValue = '';
24583   *         }
24584   *       };
24585   *       $scope.resetWithoutCancel = function(e) {
24586   *         if (e.keyCode == 27) {
24587   *           $scope.myValue = '';
24588   *         }
24589   *       };
24590   *     }]);
24591   *   </file>
24592   *   <file name="index.html">
24593   *     <div ng-controller="CancelUpdateController">
24594   *       <p>Try typing something in each input.  See that the model only updates when you
24595   *          blur off the input.
24596   *        </p>
24597   *        <p>Now see what happens if you start typing then press the Escape key</p>
24598   *
24599   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
24600   *         <p id="inputDescription1">With $rollbackViewValue()</p>
24601   *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
24602   *                ng-keydown="resetWithCancel($event)"><br/>
24603   *         myValue: "{{ myValue }}"
24604   *
24605   *         <p id="inputDescription2">Without $rollbackViewValue()</p>
24606   *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
24607   *                ng-keydown="resetWithoutCancel($event)"><br/>
24608   *         myValue: "{{ myValue }}"
24609   *       </form>
24610   *     </div>
24611   *   </file>
24612   * </example>
24613   */
24614  this.$rollbackViewValue = function() {
24615    $timeout.cancel(pendingDebounce);
24616    ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
24617    ctrl.$render();
24618  };
24619
24620  /**
24621   * @ngdoc method
24622   * @name ngModel.NgModelController#$validate
24623   *
24624   * @description
24625   * Runs each of the registered validators (first synchronous validators and then
24626   * asynchronous validators).
24627   * If the validity changes to invalid, the model will be set to `undefined`,
24628   * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
24629   * If the validity changes to valid, it will set the model to the last available valid
24630   * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
24631   */
24632  this.$validate = function() {
24633    // ignore $validate before model is initialized
24634    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
24635      return;
24636    }
24637
24638    var viewValue = ctrl.$$lastCommittedViewValue;
24639    // Note: we use the $$rawModelValue as $modelValue might have been
24640    // set to undefined during a view -> model update that found validation
24641    // errors. We can't parse the view here, since that could change
24642    // the model although neither viewValue nor the model on the scope changed
24643    var modelValue = ctrl.$$rawModelValue;
24644
24645    var prevValid = ctrl.$valid;
24646    var prevModelValue = ctrl.$modelValue;
24647
24648    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
24649
24650    ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
24651      // If there was no change in validity, don't update the model
24652      // This prevents changing an invalid modelValue to undefined
24653      if (!allowInvalid && prevValid !== allValid) {
24654        // Note: Don't check ctrl.$valid here, as we could have
24655        // external validators (e.g. calculated on the server),
24656        // that just call $setValidity and need the model value
24657        // to calculate their validity.
24658        ctrl.$modelValue = allValid ? modelValue : undefined;
24659
24660        if (ctrl.$modelValue !== prevModelValue) {
24661          ctrl.$$writeModelToScope();
24662        }
24663      }
24664    });
24665
24666  };
24667
24668  this.$$runValidators = function(modelValue, viewValue, doneCallback) {
24669    currentValidationRunId++;
24670    var localValidationRunId = currentValidationRunId;
24671
24672    // check parser error
24673    if (!processParseErrors()) {
24674      validationDone(false);
24675      return;
24676    }
24677    if (!processSyncValidators()) {
24678      validationDone(false);
24679      return;
24680    }
24681    processAsyncValidators();
24682
24683    function processParseErrors() {
24684      var errorKey = ctrl.$$parserName || 'parse';
24685      if (parserValid === undefined) {
24686        setValidity(errorKey, null);
24687      } else {
24688        if (!parserValid) {
24689          forEach(ctrl.$validators, function(v, name) {
24690            setValidity(name, null);
24691          });
24692          forEach(ctrl.$asyncValidators, function(v, name) {
24693            setValidity(name, null);
24694          });
24695        }
24696        // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
24697        setValidity(errorKey, parserValid);
24698        return parserValid;
24699      }
24700      return true;
24701    }
24702
24703    function processSyncValidators() {
24704      var syncValidatorsValid = true;
24705      forEach(ctrl.$validators, function(validator, name) {
24706        var result = validator(modelValue, viewValue);
24707        syncValidatorsValid = syncValidatorsValid && result;
24708        setValidity(name, result);
24709      });
24710      if (!syncValidatorsValid) {
24711        forEach(ctrl.$asyncValidators, function(v, name) {
24712          setValidity(name, null);
24713        });
24714        return false;
24715      }
24716      return true;
24717    }
24718
24719    function processAsyncValidators() {
24720      var validatorPromises = [];
24721      var allValid = true;
24722      forEach(ctrl.$asyncValidators, function(validator, name) {
24723        var promise = validator(modelValue, viewValue);
24724        if (!isPromiseLike(promise)) {
24725          throw $ngModelMinErr("$asyncValidators",
24726            "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
24727        }
24728        setValidity(name, undefined);
24729        validatorPromises.push(promise.then(function() {
24730          setValidity(name, true);
24731        }, function(error) {
24732          allValid = false;
24733          setValidity(name, false);
24734        }));
24735      });
24736      if (!validatorPromises.length) {
24737        validationDone(true);
24738      } else {
24739        $q.all(validatorPromises).then(function() {
24740          validationDone(allValid);
24741        }, noop);
24742      }
24743    }
24744
24745    function setValidity(name, isValid) {
24746      if (localValidationRunId === currentValidationRunId) {
24747        ctrl.$setValidity(name, isValid);
24748      }
24749    }
24750
24751    function validationDone(allValid) {
24752      if (localValidationRunId === currentValidationRunId) {
24753
24754        doneCallback(allValid);
24755      }
24756    }
24757  };
24758
24759  /**
24760   * @ngdoc method
24761   * @name ngModel.NgModelController#$commitViewValue
24762   *
24763   * @description
24764   * Commit a pending update to the `$modelValue`.
24765   *
24766   * Updates may be pending by a debounced event or because the input is waiting for a some future
24767   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
24768   * usually handles calling this in response to input events.
24769   */
24770  this.$commitViewValue = function() {
24771    var viewValue = ctrl.$viewValue;
24772
24773    $timeout.cancel(pendingDebounce);
24774
24775    // If the view value has not changed then we should just exit, except in the case where there is
24776    // a native validator on the element. In this case the validation state may have changed even though
24777    // the viewValue has stayed empty.
24778    if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
24779      return;
24780    }
24781    ctrl.$$lastCommittedViewValue = viewValue;
24782
24783    // change to dirty
24784    if (ctrl.$pristine) {
24785      this.$setDirty();
24786    }
24787    this.$$parseAndValidate();
24788  };
24789
24790  this.$$parseAndValidate = function() {
24791    var viewValue = ctrl.$$lastCommittedViewValue;
24792    var modelValue = viewValue;
24793    parserValid = isUndefined(modelValue) ? undefined : true;
24794
24795    if (parserValid) {
24796      for (var i = 0; i < ctrl.$parsers.length; i++) {
24797        modelValue = ctrl.$parsers[i](modelValue);
24798        if (isUndefined(modelValue)) {
24799          parserValid = false;
24800          break;
24801        }
24802      }
24803    }
24804    if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
24805      // ctrl.$modelValue has not been touched yet...
24806      ctrl.$modelValue = ngModelGet($scope);
24807    }
24808    var prevModelValue = ctrl.$modelValue;
24809    var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
24810    ctrl.$$rawModelValue = modelValue;
24811
24812    if (allowInvalid) {
24813      ctrl.$modelValue = modelValue;
24814      writeToModelIfNeeded();
24815    }
24816
24817    // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
24818    // This can happen if e.g. $setViewValue is called from inside a parser
24819    ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
24820      if (!allowInvalid) {
24821        // Note: Don't check ctrl.$valid here, as we could have
24822        // external validators (e.g. calculated on the server),
24823        // that just call $setValidity and need the model value
24824        // to calculate their validity.
24825        ctrl.$modelValue = allValid ? modelValue : undefined;
24826        writeToModelIfNeeded();
24827      }
24828    });
24829
24830    function writeToModelIfNeeded() {
24831      if (ctrl.$modelValue !== prevModelValue) {
24832        ctrl.$$writeModelToScope();
24833      }
24834    }
24835  };
24836
24837  this.$$writeModelToScope = function() {
24838    ngModelSet($scope, ctrl.$modelValue);
24839    forEach(ctrl.$viewChangeListeners, function(listener) {
24840      try {
24841        listener();
24842      } catch (e) {
24843        $exceptionHandler(e);
24844      }
24845    });
24846  };
24847
24848  /**
24849   * @ngdoc method
24850   * @name ngModel.NgModelController#$setViewValue
24851   *
24852   * @description
24853   * Update the view value.
24854   *
24855   * This method should be called when an input directive want to change the view value; typically,
24856   * this is done from within a DOM event handler.
24857   *
24858   * For example {@link ng.directive:input input} calls it when the value of the input changes and
24859   * {@link ng.directive:select select} calls it when an option is selected.
24860   *
24861   * If the new `value` is an object (rather than a string or a number), we should make a copy of the
24862   * object before passing it to `$setViewValue`.  This is because `ngModel` does not perform a deep
24863   * watch of objects, it only looks for a change of identity. If you only change the property of
24864   * the object then ngModel will not realise that the object has changed and will not invoke the
24865   * `$parsers` and `$validators` pipelines.
24866   *
24867   * For this reason, you should not change properties of the copy once it has been passed to
24868   * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
24869   *
24870   * When this method is called, the new `value` will be staged for committing through the `$parsers`
24871   * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
24872   * value sent directly for processing, finally to be applied to `$modelValue` and then the
24873   * **expression** specified in the `ng-model` attribute.
24874   *
24875   * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
24876   *
24877   * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
24878   * and the `default` trigger is not listed, all those actions will remain pending until one of the
24879   * `updateOn` events is triggered on the DOM element.
24880   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
24881   * directive is used with a custom debounce for this particular event.
24882   *
24883   * Note that calling this function does not trigger a `$digest`.
24884   *
24885   * @param {string} value Value from the view.
24886   * @param {string} trigger Event that triggered the update.
24887   */
24888  this.$setViewValue = function(value, trigger) {
24889    ctrl.$viewValue = value;
24890    if (!ctrl.$options || ctrl.$options.updateOnDefault) {
24891      ctrl.$$debounceViewValueCommit(trigger);
24892    }
24893  };
24894
24895  this.$$debounceViewValueCommit = function(trigger) {
24896    var debounceDelay = 0,
24897        options = ctrl.$options,
24898        debounce;
24899
24900    if (options && isDefined(options.debounce)) {
24901      debounce = options.debounce;
24902      if (isNumber(debounce)) {
24903        debounceDelay = debounce;
24904      } else if (isNumber(debounce[trigger])) {
24905        debounceDelay = debounce[trigger];
24906      } else if (isNumber(debounce['default'])) {
24907        debounceDelay = debounce['default'];
24908      }
24909    }
24910
24911    $timeout.cancel(pendingDebounce);
24912    if (debounceDelay) {
24913      pendingDebounce = $timeout(function() {
24914        ctrl.$commitViewValue();
24915      }, debounceDelay);
24916    } else if ($rootScope.$$phase) {
24917      ctrl.$commitViewValue();
24918    } else {
24919      $scope.$apply(function() {
24920        ctrl.$commitViewValue();
24921      });
24922    }
24923  };
24924
24925  // model -> value
24926  // Note: we cannot use a normal scope.$watch as we want to detect the following:
24927  // 1. scope value is 'a'
24928  // 2. user enters 'b'
24929  // 3. ng-change kicks in and reverts scope value to 'a'
24930  //    -> scope value did not change since the last digest as
24931  //       ng-change executes in apply phase
24932  // 4. view should be changed back to 'a'
24933  $scope.$watch(function ngModelWatch() {
24934    var modelValue = ngModelGet($scope);
24935
24936    // if scope model value and ngModel value are out of sync
24937    // TODO(perf): why not move this to the action fn?
24938    if (modelValue !== ctrl.$modelValue &&
24939       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
24940       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
24941    ) {
24942      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
24943      parserValid = undefined;
24944
24945      var formatters = ctrl.$formatters,
24946          idx = formatters.length;
24947
24948      var viewValue = modelValue;
24949      while (idx--) {
24950        viewValue = formatters[idx](viewValue);
24951      }
24952      if (ctrl.$viewValue !== viewValue) {
24953        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
24954        ctrl.$render();
24955
24956        ctrl.$$runValidators(modelValue, viewValue, noop);
24957      }
24958    }
24959
24960    return modelValue;
24961  });
24962}];
24963
24964
24965/**
24966 * @ngdoc directive
24967 * @name ngModel
24968 *
24969 * @element input
24970 * @priority 1
24971 *
24972 * @description
24973 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
24974 * property on the scope using {@link ngModel.NgModelController NgModelController},
24975 * which is created and exposed by this directive.
24976 *
24977 * `ngModel` is responsible for:
24978 *
24979 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
24980 *   require.
24981 * - Providing validation behavior (i.e. required, number, email, url).
24982 * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
24983 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
24984 * - Registering the control with its parent {@link ng.directive:form form}.
24985 *
24986 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
24987 * current scope. If the property doesn't already exist on this scope, it will be created
24988 * implicitly and added to the scope.
24989 *
24990 * For best practices on using `ngModel`, see:
24991 *
24992 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
24993 *
24994 * For basic examples, how to use `ngModel`, see:
24995 *
24996 *  - {@link ng.directive:input input}
24997 *    - {@link input[text] text}
24998 *    - {@link input[checkbox] checkbox}
24999 *    - {@link input[radio] radio}
25000 *    - {@link input[number] number}
25001 *    - {@link input[email] email}
25002 *    - {@link input[url] url}
25003 *    - {@link input[date] date}
25004 *    - {@link input[datetime-local] datetime-local}
25005 *    - {@link input[time] time}
25006 *    - {@link input[month] month}
25007 *    - {@link input[week] week}
25008 *  - {@link ng.directive:select select}
25009 *  - {@link ng.directive:textarea textarea}
25010 *
25011 * # CSS classes
25012 * The following CSS classes are added and removed on the associated input/select/textarea element
25013 * depending on the validity of the model.
25014 *
25015 *  - `ng-valid`: the model is valid
25016 *  - `ng-invalid`: the model is invalid
25017 *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
25018 *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
25019 *  - `ng-pristine`: the control hasn't been interacted with yet
25020 *  - `ng-dirty`: the control has been interacted with
25021 *  - `ng-touched`: the control has been blurred
25022 *  - `ng-untouched`: the control hasn't been blurred
25023 *  - `ng-pending`: any `$asyncValidators` are unfulfilled
25024 *
25025 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
25026 *
25027 * ## Animation Hooks
25028 *
25029 * Animations within models are triggered when any of the associated CSS classes are added and removed
25030 * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
25031 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
25032 * The animations that are triggered within ngModel are similar to how they work in ngClass and
25033 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
25034 *
25035 * The following example shows a simple way to utilize CSS transitions to style an input element
25036 * that has been rendered as invalid after it has been validated:
25037 *
25038 * <pre>
25039 * //be sure to include ngAnimate as a module to hook into more
25040 * //advanced animations
25041 * .my-input {
25042 *   transition:0.5s linear all;
25043 *   background: white;
25044 * }
25045 * .my-input.ng-invalid {
25046 *   background: red;
25047 *   color:white;
25048 * }
25049 * </pre>
25050 *
25051 * @example
25052 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
25053     <file name="index.html">
25054       <script>
25055        angular.module('inputExample', [])
25056          .controller('ExampleController', ['$scope', function($scope) {
25057            $scope.val = '1';
25058          }]);
25059       </script>
25060       <style>
25061         .my-input {
25062           -webkit-transition:all linear 0.5s;
25063           transition:all linear 0.5s;
25064           background: transparent;
25065         }
25066         .my-input.ng-invalid {
25067           color:white;
25068           background: red;
25069         }
25070       </style>
25071       <p id="inputDescription">
25072        Update input to see transitions when valid/invalid.
25073        Integer is a valid value.
25074       </p>
25075       <form name="testForm" ng-controller="ExampleController">
25076         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
25077                aria-describedby="inputDescription" />
25078       </form>
25079     </file>
25080 * </example>
25081 *
25082 * ## Binding to a getter/setter
25083 *
25084 * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
25085 * function that returns a representation of the model when called with zero arguments, and sets
25086 * the internal state of a model when called with an argument. It's sometimes useful to use this
25087 * for models that have an internal representation that's different from what the model exposes
25088 * to the view.
25089 *
25090 * <div class="alert alert-success">
25091 * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
25092 * frequently than other parts of your code.
25093 * </div>
25094 *
25095 * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
25096 * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
25097 * a `<form>`, which will enable this behavior for all `<input>`s within it. See
25098 * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
25099 *
25100 * The following example shows how to use `ngModel` with a getter/setter:
25101 *
25102 * @example
25103 * <example name="ngModel-getter-setter" module="getterSetterExample">
25104     <file name="index.html">
25105       <div ng-controller="ExampleController">
25106         <form name="userForm">
25107           <label>Name:
25108             <input type="text" name="userName"
25109                    ng-model="user.name"
25110                    ng-model-options="{ getterSetter: true }" />
25111           </label>
25112         </form>
25113         <pre>user.name = <span ng-bind="user.name()"></span></pre>
25114       </div>
25115     </file>
25116     <file name="app.js">
25117       angular.module('getterSetterExample', [])
25118         .controller('ExampleController', ['$scope', function($scope) {
25119           var _name = 'Brian';
25120           $scope.user = {
25121             name: function(newName) {
25122              // Note that newName can be undefined for two reasons:
25123              // 1. Because it is called as a getter and thus called with no arguments
25124              // 2. Because the property should actually be set to undefined. This happens e.g. if the
25125              //    input is invalid
25126              return arguments.length ? (_name = newName) : _name;
25127             }
25128           };
25129         }]);
25130     </file>
25131 * </example>
25132 */
25133var ngModelDirective = ['$rootScope', function($rootScope) {
25134  return {
25135    restrict: 'A',
25136    require: ['ngModel', '^?form', '^?ngModelOptions'],
25137    controller: NgModelController,
25138    // Prelink needs to run before any input directive
25139    // so that we can set the NgModelOptions in NgModelController
25140    // before anyone else uses it.
25141    priority: 1,
25142    compile: function ngModelCompile(element) {
25143      // Setup initial state of the control
25144      element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
25145
25146      return {
25147        pre: function ngModelPreLink(scope, element, attr, ctrls) {
25148          var modelCtrl = ctrls[0],
25149              formCtrl = ctrls[1] || nullFormCtrl;
25150
25151          modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
25152
25153          // notify others, especially parent forms
25154          formCtrl.$addControl(modelCtrl);
25155
25156          attr.$observe('name', function(newValue) {
25157            if (modelCtrl.$name !== newValue) {
25158              formCtrl.$$renameControl(modelCtrl, newValue);
25159            }
25160          });
25161
25162          scope.$on('$destroy', function() {
25163            formCtrl.$removeControl(modelCtrl);
25164          });
25165        },
25166        post: function ngModelPostLink(scope, element, attr, ctrls) {
25167          var modelCtrl = ctrls[0];
25168          if (modelCtrl.$options && modelCtrl.$options.updateOn) {
25169            element.on(modelCtrl.$options.updateOn, function(ev) {
25170              modelCtrl.$$debounceViewValueCommit(ev && ev.type);
25171            });
25172          }
25173
25174          element.on('blur', function(ev) {
25175            if (modelCtrl.$touched) return;
25176
25177            if ($rootScope.$$phase) {
25178              scope.$evalAsync(modelCtrl.$setTouched);
25179            } else {
25180              scope.$apply(modelCtrl.$setTouched);
25181            }
25182          });
25183        }
25184      };
25185    }
25186  };
25187}];
25188
25189var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25190
25191/**
25192 * @ngdoc directive
25193 * @name ngModelOptions
25194 *
25195 * @description
25196 * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
25197 * events that will trigger a model update and/or a debouncing delay so that the actual update only
25198 * takes place when a timer expires; this timer will be reset after another change takes place.
25199 *
25200 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
25201 * be different from the value in the actual model. This means that if you update the model you
25202 * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
25203 * order to make sure it is synchronized with the model and that any debounced action is canceled.
25204 *
25205 * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
25206 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
25207 * important because `form` controllers are published to the related scope under the name in their
25208 * `name` attribute.
25209 *
25210 * Any pending changes will take place immediately when an enclosing form is submitted via the
25211 * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
25212 * to have access to the updated model.
25213 *
25214 * `ngModelOptions` has an effect on the element it's declared on and its desce
25214ndants.
25215 *
25216 * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
25217 *   - `updateOn`: string specifying which event should the input be bound to. You can set several
25218 *     events using an space delimited list. There is a special event called `default` that
25219 *     matches the default events belonging of the control.
25220 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
25221 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
25222 *     custom value for each event. For example:
25223 *     `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
25224 *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
25225 *     not validate correctly instead of the default behavior of setting the model to undefined.
25226 *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
25227       `ngModel` as getters/setters.
25228 *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
25229 *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
25230 *     continental US time zone abbreviations, but for general use, use a time zone offset, for
25231 *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
25232 *     If not specified, the timezone of the browser will be used.
25233 *
25234 * @example
25235
25236  The following example shows how to override immediate updates. Changes on the inputs within the
25237  form will update the model only when the control loses focus (blur event). If `escape` key is
25238  pressed while the input field is focused, the value is reset to the value in the current model.
25239
25240  <example name="ngModelOptions-directive-blur" module="optionsExample">
25241    <file name="index.html">
25242      <div ng-controller="ExampleController">
25243        <form name="userForm">
25244          <label>Name:
25245            <input type="text" name="userName"
25246                   ng-model="user.name"
25247                   ng-model-options="{ updateOn: 'blur' }"
25248                   ng-keyup="cancel($event)" />
25249          </label><br />
25250          <label>Other data:
25251            <input type="text" ng-model="user.data" />
25252          </label><br />
25253        </form>
25254        <pre>user.name = <span ng-bind="user.name"></span></pre>
25255      </div>
25256    </file>
25257    <file name="app.js">
25258      angular.module('optionsExample', [])
25259        .controller('ExampleController', ['$scope', function($scope) {
25260          $scope.user = { name: 'say', data: '' };
25261
25262          $scope.cancel = function(e) {
25263            if (e.keyCode == 27) {
25264              $scope.userForm.userName.$rollbackViewValue();
25265            }
25266          };
25267        }]);
25268    </file>
25269    <file name="protractor.js" type="protractor">
25270      var model = element(by.binding('user.name'));
25271      var input = element(by.model('user.name'));
25272      var other = element(by.model('user.data'));
25273
25274      it('should allow custom events', function() {
25275        input.sendKeys(' hello');
25276        input.click();
25277        expect(model.getText()).toEqual('say');
25278        other.click();
25279        expect(model.getText()).toEqual('say hello');
25280      });
25281
25282      it('should $rollbackViewValue when model changes', function() {
25283        input.sendKeys(' hello');
25284        expect(input.getAttribute('value')).toEqual('say hello');
25285        input.sendKeys(protractor.Key.ESCAPE);
25286        expect(input.getAttribute('value')).toEqual('say');
25287        other.click();
25288        expect(model.getText()).toEqual('say');
25289      });
25290    </file>
25291  </example>
25292
25293  This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
25294  If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
25295
25296  <example name="ngModelOptions-directive-debounce" module="optionsExample">
25297    <file name="index.html">
25298      <div ng-controller="ExampleController">
25299        <form name="userForm">
25300          <label>Name:
25301            <input type="text" name="userName"
25302                   ng-model="user.name"
25303                   ng-model-options="{ debounce: 1000 }" />
25304          </label>
25305          <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
25306          <br />
25307        </form>
25308        <pre>user.name = <span ng-bind="user.name"></span></pre>
25309      </div>
25310    </file>
25311    <file name="app.js">
25312      angular.module('optionsExample', [])
25313        .controller('ExampleController', ['$scope', function($scope) {
25314          $scope.user = { name: 'say' };
25315        }]);
25316    </file>
25317  </example>
25318
25319  This one shows how to bind to getter/setters:
25320
25321  <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
25322    <file name="index.html">
25323      <div ng-controller="ExampleController">
25324        <form name="userForm">
25325          <label>Name:
25326            <input type="text" name="userName"
25327                   ng-model="user.name"
25328                   ng-model-options="{ getterSetter: true }" />
25329          </label>
25330        </form>
25331        <pre>user.name = <span ng-bind="user.name()"></span></pre>
25332      </div>
25333    </file>
25334    <file name="app.js">
25335      angular.module('getterSetterExample', [])
25336        .controller('ExampleController', ['$scope', function($scope) {
25337          var _name = 'Brian';
25338          $scope.user = {
25339            name: function(newName) {
25340              // Note that newName can be undefined for two reasons:
25341              // 1. Because it is called as a getter and thus called with no arguments
25342              // 2. Because the property should actually be set to undefined. This happens e.g. if the
25343              //    input is invalid
25344              return arguments.length ? (_name = newName) : _name;
25345            }
25346          };
25347        }]);
25348    </file>
25349  </example>
25350 */
25351var ngModelOptionsDirective = function() {
25352  return {
25353    restrict: 'A',
25354    controller: ['$scope', '$attrs', function($scope, $attrs) {
25355      var that = this;
25356      this.$options = copy($scope.$eval($attrs.ngModelOptions));
25357      // Allow adding/overriding bound events
25358      if (this.$options.updateOn !== undefined) {
25359        this.$options.updateOnDefault = false;
25360        // extract "default" pseudo-event from list of events that can trigger a model update
25361        this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
25362          that.$options.updateOnDefault = true;
25363          return ' ';
25364        }));
25365      } else {
25366        this.$options.updateOnDefault = true;
25367      }
25368    }]
25369  };
25370};
25371
25372
25373
25374// helper methods
25375function addSetValidityMethod(context) {
25376  var ctrl = context.ctrl,
25377      $element = context.$element,
25378      classCache = {},
25379      set = context.set,
25380      unset = context.unset,
25381      parentForm = context.parentForm,
25382      $animate = context.$animate;
25383
25384  classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
25385
25386  ctrl.$setValidity = setValidity;
25387
25388  function setValidity(validationErrorKey, state, controller) {
25389    if (state === undefined) {
25390      createAndSet('$pending', validationErrorKey, controller);
25391    } else {
25392      unsetAndCleanup('$pending', validationErrorKey, controller);
25393    }
25394    if (!isBoolean(state)) {
25395      unset(ctrl.$error, validationErrorKey, controller);
25396      unset(ctrl.$$success, validationErrorKey, controller);
25397    } else {
25398      if (state) {
25399        unset(ctrl.$error, validationErrorKey, controller);
25400        set(ctrl.$$success, validationErrorKey, controller);
25401      } else {
25402        set(ctrl.$error, validationErrorKey, controller);
25403        unset(ctrl.$$success, validationErrorKey, controller);
25404      }
25405    }
25406    if (ctrl.$pending) {
25407      cachedToggleClass(PENDING_CLASS, true);
25408      ctrl.$valid = ctrl.$invalid = undefined;
25409      toggleValidationCss('', null);
25410    } else {
25411      cachedToggleClass(PENDING_CLASS, false);
25412      ctrl.$valid = isObjectEmpty(ctrl.$error);
25413      ctrl.$invalid = !ctrl.$valid;
25414      toggleValidationCss('', ctrl.$valid);
25415    }
25416
25417    // re-read the state as the set/unset methods could have
25418    // combined state in ctrl.$error[validationError] (used for forms),
25419    // where setting/unsetting only increments/decrements the value,
25420    // and does not replace it.
25421    var combinedState;
25422    if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
25423      combinedState = undefined;
25424    } else if (ctrl.$error[validationErrorKey]) {
25425      combinedState = false;
25426    } else if (ctrl.$$success[validationErrorKey]) {
25427      combinedState = true;
25428    } else {
25429      combinedState = null;
25430    }
25431
25432    toggleValidationCss(validationErrorKey, combinedState);
25433    parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
25434  }
25435
25436  function createAndSet(name, value, controller) {
25437    if (!ctrl[name]) {
25438      ctrl[name] = {};
25439    }
25440    set(ctrl[name], value, controller);
25441  }
25442
25443  function unsetAndCleanup(name, value, controller) {
25444    if (ctrl[name]) {
25445      unset(ctrl[name], value, controller);
25446    }
25447    if (isObjectEmpty(ctrl[name])) {
25448      ctrl[name] = undefined;
25449    }
25450  }
25451
25452  function cachedToggleClass(className, switchValue) {
25453    if (switchValue && !classCache[className]) {
25454      $animate.addClass($element, className);
25455      classCache[className] = true;
25456    } else if (!switchValue && classCache[className]) {
25457      $animate.removeClass($element, className);
25458      classCache[className] = false;
25459    }
25460  }
25461
25462  function toggleValidationCss(validationErrorKey, isValid) {
25463    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
25464
25465    cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
25466    cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
25467  }
25468}
25469
25470function isObjectEmpty(obj) {
25471  if (obj) {
25472    for (var prop in obj) {
25473      return false;
25474    }
25475  }
25476  return true;
25477}
25478
25479/**
25480 * @ngdoc directive
25481 * @name ngNonBindable
25482 * @restrict AC
25483 * @priority 1000
25484 *
25485 * @description
25486 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
25487 * DOM element. This is useful if the element contains what appears to be Angular directives and
25488 * bindings but which should be ignored by Angular. This could be the case if you have a site that
25489 * displays snippets of code, for instance.
25490 *
25491 * @element ANY
25492 *
25493 * @example
25494 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
25495 * but the one wrapped in `ngNonBindable` is left alone.
25496 *
25497 * @example
25498    <example>
25499      <file name="index.html">
25500        <div>Normal: {{1 + 2}}</div>
25501        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
25502      </file>
25503      <file name="protractor.js" type="protractor">
25504       it('should check ng-non-bindable', function() {
25505         expect(element(by.binding('1 + 2')).getText()).toContain('3');
25506         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
25507       });
25508      </file>
25509    </example>
25510 */
25511var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
25512
25513/* global jqLiteRemove */
25514
25515var ngOptionsMinErr = minErr('ngOptions');
25516
25517/**
25518 * @ngdoc directive
25519 * @name ngOptions
25520 * @restrict A
25521 *
25522 * @description
25523 *
25524 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
25525 * elements for the `<select>` element using the array or object obtained by evaluating the
25526 * `ngOptions` comprehension expression.
25527 *
25528 * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
25529 * similar result. However, `ngOptions` provides some benefits such as reducing memory and
25530 * increasing speed by not creating a new scope for each repeated instance, as well as providing
25531 * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
25532 * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
25533 *  to a non-string value. This is because an option element can only be bound to string values at
25534 * present.
25535 *
25536 * When an item in the `<select>` menu is selected, the array element or object property
25537 * represented by the selected option will be bound to the model identified by the `ngModel`
25538 * directive.
25539 *
25540 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
25541 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
25542 * option. See example below for demonstration.
25543 *
25544 * ## Complex Models (objects or collections)
25545 *
25546 * **Note:** By default, `ngModel` watches the model by reference, not value. This is important when
25547 * binding any input directive to a model that is an object or a collection.
25548 *
25549 * Since this is a common situation for `ngOptions` the directive additionally watches the model using
25550 * `$watchCollection` when the select has the `multiple` attribute or when there is a `track by` clause in
25551 * the options expression. This allows ngOptions to trigger a re-rendering of the options even if the actual
25552 * object/collection has not changed identity but only a property on the object or an item in the collection
25553 * changes.
25554 *
25555 * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
25556 * if the model is an array). This means that changing a property deeper inside the object/collection that the
25557 * first level will not trigger a re-rendering.
25558 *
25559 *
25560 * ## `select` **`as`**
25561 *
25562 * Using `select` **`as`** will bind the result of the `select` expression to the model, but
25563 * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
25564 * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
25565 * is used, the result of that expression will be set as the value of the `option` and `select` elements.
25566 *
25567 *
25568 * ### `select` **`as`** and **`track by`**
25569 *
25570 * <div class="alert alert-warning">
25571 * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
25572 * </div>
25573 *
25574 * Consider the following example:
25575 *
25576 * ```html
25577 * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
25578 * ```
25579 *
25580 * ```js
25581 * $scope.values = [{
25582 *   id: 1,
25583 *   label: 'aLabel',
25584 *   subItem: { name: 'aSubItem' }
25585 * }, {
25586 *   id: 2,
25587 *   label: 'bLabel',
25588 *   subItem: { name: 'bSubItem' }
25589 * }];
25590 *
25591 * $scope.selected = { name: 'aSubItem' };
25592 * ```
25593 *
25594 * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
25595 * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
25596 * following:
25597 *
25598 * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
25599 * 2. Apply **`track by`** to the already selected value in `ngModel`.
25600 *    In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
25601 *    value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
25602 *    a wrong object, the selected element can't be found, `<select>` is always reset to the "not
25603 *    selected" option.
25604 *
25605 *
25606 * @param {string} ngModel Assignable angular expression to data-bind to.
25607 * @param {string=} name Property name of the form under which the control is published.
25608 * @param {string=} required The control is considered valid only if value is entered.
25609 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
25610 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
25611 *    `required` when you want to data-bind to the `required` attribute.
25612 * @param {comprehension_expression=} ngOptions in one of the following forms:
25613 *
25614 *   * for array data sources:
25615 *     * `label` **`for`** `value` **`in`** `array`
25616 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
25617 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
25618 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
25619 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25620 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
25621 *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
25622 *        (for including a filter with `track by`)
25623 *   * for object data sources:
25624 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25625 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
25626 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
25627 *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
25628 *     * `select` **`as`** `label` **`group by`** `group`
25629 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
25630 *     * `select` **`as`** `label` **`disable when`** `disable`
25631 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
25632 *
25633 * Where:
25634 *
25635 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
25636 *   * `value`: local variable which will refer to each item in the `array` or each property value
25637 *      of `object` during iteration.
25638 *   * `key`: local variable which will refer to a property name in `object` during iteration.
25639 *   * `label`: The result of this expression will be the label for `<option>` element. The
25640 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
25641 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
25642 *      element. If not specified, `select` expression will default to `value`.
25643 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
25644 *      DOM element.
25645 *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
25646 *      element. Return `true` to disable.
25647 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
25648 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
25649 *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
25650 *      even when the options are recreated (e.g. reloaded from the server).
25651 *
25652 * @example
25653    <example module="selectExample">
25654      <file name="index.html">
25655        <script>
25656        angular.module('selectExample', [])
25657          .controller('ExampleController', ['$scope', function($scope) {
25658            $scope.colors = [
25659              {name:'black', shade:'dark'},
25660              {name:'white', shade:'light', notAnOption: true},
25661              {name:'red', shade:'dark'},
25662              {name:'blue', shade:'dark', notAnOption: true},
25663              {name:'yellow', shade:'light', notAnOption: false}
25664            ];
25665            $scope.myColor = $scope.colors[2]; // red
25666          }]);
25667        </script>
25668        <div ng-controller="ExampleController">
25669          <ul>
25670            <li ng-repeat="color in colors">
25671              <label>Name: <input ng-model="color.name"></label>
25672              <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
25673              <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
25674            </li>
25675            <li>
25676              <button ng-click="colors.push({})">add</button>
25677            </li>
25678          </ul>
25679          <hr/>
25680          <label>Color (null not allowed):
25681            <select ng-model="myColor" ng-options="color.name for color in colors"></select>
25682          </label><br/>
25683          <label>Color (null allowed):
25684          <span  class="nullable">
25685            <select ng-model="myColor" ng-options="color.name for color in colors">
25686              <option value="">-- choose color --</option>
25687            </select>
25688          </span></label><br/>
25689
25690          <label>Color grouped by shade:
25691            <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
25692            </select>
25693          </label><br/>
25694
25695          <label>Color grouped by shade, with some disabled:
25696            <select ng-model="myColor"
25697                  ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
25698            </select>
25699          </label><br/>
25700
25701
25702
25703          Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
25704          <br/>
25705          <hr/>
25706          Currently selected: {{ {selected_color:myColor} }}
25707          <div style="border:solid 1px black; height:20px"
25708               ng-style="{'background-color':myColor.name}">
25709          </div>
25710        </div>
25711      </file>
25712      <file name="protractor.js" type="protractor">
25713         it('should check ng-options', function() {
25714           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
25715           element.all(by.model('myColor')).first().click();
25716           element.all(by.css('select[ng-model="myColor"] option')).first().click();
25717           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
25718           element(by.css('.nullable select[ng-model="myColor"]')).click();
25719           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
25720           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
25721         });
25722      </file>
25723    </example>
25724 */
25725
25726// jshint maxlen: false
25727//                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
25728var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\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]+?))?$/;
25729                        // 1: value expression (valueFn)
25730                        // 2: label expression (displayFn)
25731                        // 3: group by expression (groupByFn)
25732                        // 4: disable when expression (disableWhenFn)
25733                        // 5: array item variable name
25734                        // 6: object item key variable name
25735                        // 7: object item value variable name
25736                        // 8: collection expression
25737                        // 9: track by expression
25738// jshint maxlen: 100
25739
25740
25741var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
25742
25743  function parseOptionsExpression(optionsExp, selectElement, scope) {
25744
25745    var match = optionsExp.match(NG_OPTIONS_REGEXP);
25746    if (!(match)) {
25747      throw ngOptionsMinErr('iexp',
25748        "Expected expression in form of " +
25749        "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
25750        " but got '{0}'. Element: {1}",
25751        optionsExp, startingTag(selectElement));
25752    }
25753
25754    // Extract the parts from the ngOptions expression
25755
25756    // The variable name for the value of the item in the collection
25757    var valueName = match[5] || match[7];
25758    // The variable name for the key of the item in the collection
25759    var keyName = match[6];
25760
25761    // An expression that generates the viewValue for an option if there is a label expression
25762    var selectAs = / as /.test(match[0]) && match[1];
25763    // An expression that is used to track the id of each object in the options collection
25764    var trackBy = match[9];
25765    // An expression that generates the viewValue for an option if there is no label expression
25766    var valueFn = $parse(match[2] ? match[1] : valueName);
25767    var selectAsFn = selectAs && $parse(selectAs);
25768    var viewValueFn = selectAsFn || valueFn;
25769    var trackByFn = trackBy && $parse(trackBy);
25770
25771    // Get the value by which we are going to track the option
25772    // if we have a trackFn then use that (passing scope and locals)
25773    // otherwise just hash the given viewValue
25774    var getTrackByValueFn = trackBy ?
25775                              function(value, locals) { return trackByFn(scope, locals); } :
25776                              function getHashOfValue(value) { return hashKey(value); };
25777    var getTrackByValue = function(value, key) {
25778      return getTrackByValueFn(value, getLocals(value, key));
25779    };
25780
25781    var displayFn = $parse(match[2] || match[1]);
25782    var groupByFn = $parse(match[3] || '');
25783    var disableWhenFn = $parse(match[4] || '');
25784    var valuesFn = $parse(match[8]);
25785
25786    var locals = {};
25787    var getLocals = keyName ? function(value, key) {
25788      locals[keyName] = key;
25789      locals[valueName] = value;
25790      return locals;
25791    } : function(value) {
25792      locals[valueName] = value;
25793      return locals;
25794    };
25795
25796
25797    function Option(selectValue, viewValue, label, group, disabled) {
25798      this.selectValue = selectValue;
25799      this.viewValue = viewValue;
25800      this.label = label;
25801      this.group = group;
25802      this.disabled = disabled;
25803    }
25804
25805    return {
25806      trackBy: trackBy,
25807      getTrackByValue: getTrackByValue,
25808      getWatchables: $parse(valuesFn, function(values) {
25809        // Create a collection of things that we would like to watch (watchedArray)
25810        // so that they can all be watched using a single $watchCollection
25811        // that only runs the handler once if anything changes
25812        var watchedArray = [];
25813        values = values || [];
25814
25815        Object.keys(values).forEach(function getWatchable(key) {
25816          var locals = getLocals(values[key], key);
25817          var selectValue = getTrackByValueFn(values[key], locals);
25818          watchedArray.push(selectValue);
25819
25820          // Only need to watch the displayFn if there is a specific label expression
25821          if (match[2] || match[1]) {
25822            var label = displayFn(scope, locals);
25823            watchedArray.push(label);
25824          }
25825
25826          // Only need to watch the disableWhenFn if there is a specific disable expression
25827          if (match[4]) {
25828            var disableWhen = disableWhenFn(scope, locals);
25829            watchedArray.push(disableWhen);
25830          }
25831        });
25832        return watchedArray;
25833      }),
25834
25835      getOptions: function() {
25836
25837        var optionItems = [];
25838        var selectValueMap = {};
25839
25840        // The option values were already computed in the `getWatchables` fn,
25841        // which must have been called to trigger `getOptions`
25842        var optionValues = valuesFn(scope) || [];
25843        var optionValuesKeys;
25844
25845
25846        if (!keyName && isArrayLike(optionValues)) {
25847          optionValuesKeys = optionValues;
25848        } else {
25849          // if object, extract keys, in enumeration order, unsorted
25850          optionValuesKeys = [];
25851          for (var itemKey in optionValues) {
25852            if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
25853              optionValuesKeys.push(itemKey);
25854            }
25855          }
25856        }
25857
25858        var optionValuesLength = optionValuesKeys.length;
25859
25860        for (var index = 0; index < optionValuesLength; index++) {
25861          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
25862          var value = optionValues[key];
25863          var locals = getLocals(value, key);
25864          var viewValue = viewValueFn(scope, locals);
25865          var selectValue = getTrackByValueFn(viewValue, locals);
25866          var label = displayFn(scope, locals);
25867          var group = groupByFn(scope, locals);
25868          var disabled = disableWhenFn(scope, locals);
25869          var optionItem = new Option(selectValue, viewValue, label, group, disabled);
25870
25871          optionItems.push(optionItem);
25872          selectValueMap[selectValue] = optionItem;
25873        }
25874
25875        return {
25876          items: optionItems,
25877          selectValueMap: selectValueMap,
25878          getOptionFromViewValue: function(value) {
25879            return selectValueMap[getTrackByValue(value)];
25880          },
25881          getViewValueFromOption: function(option) {
25882            // If the viewValue could be an object that may be mutated by the application,
25883            // we need to make a copy and not return the reference to the value on the option.
25884            return trackBy ? angular.copy(option.viewValue) : option.viewValue;
25885          }
25886        };
25887      }
25888    };
25889  }
25890
25891
25892  // we can't just jqLite('<option>') since jqLite is not smart enough
25893  // to create it in <select> and IE barfs otherwise.
25894  var optionTemplate = document.createElement('option'),
25895      optGroupTemplate = document.createElement('optgroup');
25896
25897  return {
25898    restrict: 'A',
25899    terminal: true,
25900    require: ['select', '?ngModel'],
25901    link: function(scope, selectElement, attr, ctrls) {
25902
25903      // if ngModel is not defined, we don't need to do anything
25904      var ngModelCtrl = ctrls[1];
25905      if (!ngModelCtrl) return;
25906
25907      var selectCtrl = ctrls[0];
25908      var multiple = attr.multiple;
25909
25910      // The emptyOption allows the application developer to provide their own custom "empty"
25911      // option when the viewValue does not match any of the option values.
25912      var emptyOption;
25913      for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
25914        if (children[i].value === '') {
25915          emptyOption = children.eq(i);
25916          break;
25917        }
25918      }
25919
25920      var providedEmptyOption = !!emptyOption;
25921
25922      var unknownOption = jqLite(optionTemplate.cloneNode(false));
25923      unknownOption.val('?');
25924
25925      var options;
25926      var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
25927
25928
25929      var renderEmptyOption = function() {
25930        if (!providedEmptyOption) {
25931          selectElement.prepend(emptyOption);
25932        }
25933        selectElement.val('');
25934        emptyOption.prop('selected', true); // needed for IE
25935        emptyOption.attr('selected', true);
25936      };
25937
25938      var removeEmptyOption = function() {
25939        if (!providedEmptyOption) {
25940          emptyOption.remove();
25941        }
25942      };
25943
25944
25945      var renderUnknownOption = function() {
25946        selectElement.prepend(unknownOption);
25947        selectElement.val('?');
25948        unknownOption.prop('selected', true); // needed for IE
25949        unknownOption.attr('selected', true);
25950      };
25951
25952      var removeUnknownOption = function() {
25953        unknownOption.remove();
25954      };
25955
25956
25957      // Update the controller methods for multiple selectable options
25958      if (!multiple) {
25959
25960        selectCtrl.writeValue = function writeNgOptionsValue(value) {
25961          var option = options.getOptionFromViewValue(value);
25962
25963          if (option && !option.disabled) {
25964            if (selectElement[0].value !== option.selectValue) {
25965              removeUnknownOption();
25966              removeEmptyOption();
25967
25968              selectElement[0].value = option.selectValue;
25969              option.element.selected = true;
25970              option.element.setAttribute('selected', 'selected');
25971            }
25972          } else {
25973            if (value === null || providedEmptyOption) {
25974              removeUnknownOption();
25975              renderEmptyOption();
25976            } else {
25977              removeEmptyOption();
25978              renderUnknownOption();
25979            }
25980          }
25981        };
25982
25983        selectCtrl.readValue = function readNgOptionsValue() {
25984
25985          var selectedOption = options.selectValueMap[selectElement.val()];
25986
25987          if (selectedOption && !selectedOption.disabled) {
25988            removeEmptyOption();
25989            removeUnknownOption();
25990            return options.getViewValueFromOption(selectedOption);
25991          }
25992          return null;
25993        };
25994
25995        // If we are using `track by` then we must watch the tracked value on the model
25996        // since ngModel only watches for object identity change
25997        if (ngOptions.trackBy) {
25998          scope.$watch(
25999            function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
26000            function() { ngModelCtrl.$render(); }
26001          );
26002        }
26003
26004      } else {
26005
26006        ngModelCtrl.$isEmpty = function(value) {
26007          return !value || value.length === 0;
26008        };
26009
26010
26011        selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
26012          options.items.forEach(function(option) {
26013            option.element.selected = false;
26014          });
26015
26016          if (value) {
26017            value.forEach(function(item) {
26018              var option = options.getOptionFromViewValue(item);
26019              if (option && !option.disabled) option.element.selected = true;
26020            });
26021          }
26022        };
26023
26024
26025        selectCtrl.readValue = function readNgOptionsMultiple() {
26026          var selectedValues = selectElement.val() || [],
26027              selections = [];
26028
26029          forEach(selectedValues, function(value) {
26030            var option = options.selectValueMap[value];
26031            if (!option.disabled) selections.push(options.getViewValueFromOption(option));
26032          });
26033
26034          return selections;
26035        };
26036
26037        // If we are using `track by` then we must watch these tracked values on the model
26038        // since ngModel only watches for object identity change
26039        if (ngOptions.trackBy) {
26040
26041          scope.$watchCollection(function() {
26042            if (isArray(ngModelCtrl.$viewValue)) {
26043              return ngModelCtrl.$viewValue.map(function(value) {
26044                return ngOptions.getTrackByValue(value);
26045              });
26046            }
26047          }, function() {
26048            ngModelCtrl.$render();
26049          });
26050
26051        }
26052      }
26053
26054
26055      if (providedEmptyOption) {
26056
26057        // we need to remove it before calling selectElement.empty() because otherwise IE will
26058        // remove the label from the element. wtf?
26059        emptyOption.remove();
26060
26061        // compile the element since there might be bindings in it
26062        $compile(emptyOption)(scope);
26063
26064        // remove the class, which is added automatically because we recompile the element and it
26065        // becomes the compilation root
26066        emptyOption.removeClass('ng-scope');
26067      } else {
26068        emptyOption = jqLite(optionTemplate.cloneNode(false));
26069      }
26070
26071      // We need to do this here to ensure that the options object is defined
26072      // when we first hit it in writeNgOptionsValue
26073      updateOptions();
26074
26075      // We will re-render the option elements if the option values or labels change
26076      scope.$watchCollection(ngOptions.getWatchables, updateOptions);
26077
26078      // ------------------------------------------------------------------ //
26079
26080
26081      function updateOptionElement(option, element) {
26082        option.element = element;
26083        element.disabled = option.disabled;
26084        if (option.value !== element.value) element.value = option.selectValue;
26085        if (option.label !== element.label) {
26086          element.label = option.label;
26087          element.textContent = option.label;
26088        }
26089      }
26090
26091      function addOrReuseElement(parent, current, type, templateElement) {
26092        var element;
26093        // Check whether we can reuse the next element
26094        if (current && lowercase(current.nodeName) === type) {
26095          // The next element is the right type so reuse it
26096          element = current;
26097        } else {
26098          // The next element is not the right type so create a new one
26099          element = templateElement.cloneNode(false);
26100          if (!current) {
26101            // There are no more elements so just append it to the select
26102            parent.appendChild(element);
26103          } else {
26104            // The next element is not a group so insert the new one
26105            parent.insertBefore(element, current);
26106          }
26107        }
26108        return element;
26109      }
26110
26111
26112      function removeExcessElements(current) {
26113        var next;
26114        while (current) {
26115          next = current.nextSibling;
26116          jqLiteRemove(current);
26117          current = next;
26118        }
26119      }
26120
26121
26122      function skipEmptyAndUnknownOptions(current) {
26123        var emptyOption_ = emptyOption && emptyOption[0];
26124        var unknownOption_ = unknownOption && unknownOption[0];
26125
26126        if (emptyOption_ || unknownOption_) {
26127          while (current &&
26128                (current === emptyOption_ ||
26129                current === unknownOption_)) {
26130            current = current.nextSibling;
26131          }
26132        }
26133        return current;
26134      }
26135
26136
26137      function updateOptions() {
26138
26139        var previousValue = options && selectCtrl.readValue();
26140
26141        options = ngOptions.getOptions();
26142
26143        var groupMap = {};
26144        var currentElement = selectElement[0].firstChild;
26145
26146        // Ensure that the empty option is always there if it was explicitly provided
26147        if (providedEmptyOption) {
26148          selectElement.prepend(emptyOption);
26149        }
26150
26151        currentElement = skipEmptyAndUnknownOptions(currentElement);
26152
26153        options.items.forEach(function updateOption(option) {
26154          var group;
26155          var groupElement;
26156          var optionElement;
26157
26158          if (option.group) {
26159
26160            // This option is to live in a group
26161            // See if we have already created this group
26162            group = groupMap[option.group];
26163
26164            if (!group) {
26165
26166              // We have not already created this group
26167              groupElement = addOrReuseElement(selectElement[0],
26168                                               currentElement,
26169                                               'optgroup',
26170                                               optGroupTemplate);
26171              // Move to the next element
26172              currentElement = groupElement.nextSibling;
26173
26174              // Update the label on the group element
26175              groupElement.label = option.group;
26176
26177              // Store it for use later
26178              group = groupMap[option.group] = {
26179                groupElement: groupElement,
26180                currentOptionElement: groupElement.firstChild
26181              };
26182
26183            }
26184
26185            // So now we have a group for this option we add the option to the group
26186            optionElement = addOrReuseElement(group.groupElement,
26187                                              group.currentOptionElement,
26188                                              'option',
26189                                              optionTemplate);
26190            updateOptionElement(option, optionElement);
26191            // Move to the next element
26192            group.currentOptionElement = optionElement.nextSibling;
26193
26194          } else {
26195
26196            // This option is not in a group
26197            optionElement = addOrReuseElement(selectElement[0],
26198                                              currentElement,
26199                                              'option',
26200                                              optionTemplate);
26201            updateOptionElement(option, optionElement);
26202            // Move to the next element
26203            currentElement = optionElement.nextSibling;
26204          }
26205        });
26206
26207
26208        // Now remove all excess options and group
26209        Object.keys(groupMap).forEach(function(key) {
26210          removeExcessElements(groupMap[key].currentOptionElement);
26211        });
26212        removeExcessElements(currentElement);
26213
26214        ngModelCtrl.$render();
26215
26216        // Check to see if the value has changed due to the update to the options
26217        if (!ngModelCtrl.$isEmpty(previousValue)) {
26218          var nextValue = selectCtrl.readValue();
26219          if (ngOptions.trackBy && !equals(previousValue, nextValue) ||
26220                previousValue !== nextValue) {
26221            ngModelCtrl.$setViewValue(nextValue);
26222            ngModelCtrl.$render();
26223          }
26224        }
26225
26226      }
26227
26228    }
26229  };
26230}];
26231
26232/**
26233 * @ngdoc directive
26234 * @name ngPluralize
26235 * @restrict EA
26236 *
26237 * @description
26238 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
26239 * These rules are bundled with angular.js, but can be overridden
26240 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
26241 * by specifying the mappings between
26242 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26243 * and the strings to be displayed.
26244 *
26245 * # Plural categories and explicit number rules
26246 * There are two
26247 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
26248 * in Angular's default en-US locale: "one" and "other".
26249 *
26250 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
26251 * any number that is not 1), an explicit number rule can only match one number. For example, the
26252 * explicit number rule for "3" matches the number 3. There are examples of plural categories
26253 * and explicit number rules throughout the rest of this documentation.
26254 *
26255 * # Configuring ngPluralize
26256 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
26257 * You can also provide an optional attribute, `offset`.
26258 *
26259 * The value of the `count` attribute can be either a string or an {@link guide/expression
26260 * Angular expression}; these are evaluated on the current scope for its bound value.
26261 *
26262 * The `when` attribute specifies the mappings between plural categories and the actual
26263 * string to be displayed. The value of the attribute should be a JSON object.
26264 *
26265 * The following example shows how to configure ngPluralize:
26266 *
26267 * ```html
26268 * <ng-pluralize count="personCount"
26269                 when="{'0': 'Nobody is viewing.',
26270 *                      'one': '1 person is viewing.',
26271 *                      'other': '{} people are viewing.'}">
26272 * </ng-pluralize>
26273 *```
26274 *
26275 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
26276 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
26277 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
26278 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
26279 * show "a dozen people are viewing".
26280 *
26281 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
26282 * into pluralized strings. In the previous example, Angular will replace `{}` with
26283 * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
26284 * for <span ng-non-bindable>{{numberExpression}}</span>.
26285 *
26286 * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
26287 * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
26288 *
26289 * # Configuring ngPluralize with offset
26290 * The `offset` attribute allows further customization of pluralized text, which can result in
26291 * a better user experience. For example, instead of the message "4 people are viewing this document",
26292 * you might display "John, Kate and 2 others are viewing this document".
26293 * The offset attribute allows you to offset a number by any desired value.
26294 * Let's take a look at an example:
26295 *
26296 * ```html
26297 * <ng-pluralize count="personCount" offset=2
26298 *               when="{'0': 'Nobody is viewing.',
26299 *                      '1': '{{person1}} is viewing.',
26300 *                      '2': '{{person1}} and {{person2}} are viewing.',
26301 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
26302 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26303 * </ng-pluralize>
26304 * ```
26305 *
26306 * Notice that we are still using two plural categories(one, other), but we added
26307 * three explicit number rules 0, 1 and 2.
26308 * When one person, perhaps John, views the document, "John is viewing" will be shown.
26309 * When three people view the document, no explicit number rule is found, so
26310 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
26311 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
26312 * is shown.
26313 *
26314 * Note that when you specify offsets, you must provide explicit number rules for
26315 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
26316 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
26317 * plural categories "one" and "other".
26318 *
26319 * @param {string|expression} count The variable to be bound to.
26320 * @param {string} when The mapping between plural category to its corresponding strings.
26321 * @param {number=} offset Offset to deduct from the total number.
26322 *
26323 * @example
26324    <example module="pluralizeExampl
vendor: 4,913 bytes, lines 26324-26438
26324e">
26325      <file name="index.html">
26326        <script>
26327          angular.module('pluralizeExample', [])
26328            .controller('ExampleController', ['$scope', function($scope) {
26329              $scope.person1 = 'Igor';
26330              $scope.person2 = 'Misko';
26331              $scope.personCount = 1;
26332            }]);
26333        </script>
26334        <div ng-controller="ExampleController">
26335          <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
26336          <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
26337          <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
26338
26339          <!--- Example with simple pluralization rules for en locale --->
26340          Without Offset:
26341          <ng-pluralize count="personCount"
26342                        when="{'0': 'Nobody is viewing.',
26343                               'one': '1 person is viewing.',
26344                               'other': '{} people are viewing.'}">
26345          </ng-pluralize><br>
26346
26347          <!--- Example with offset --->
26348          With Offset(2):
26349          <ng-pluralize count="personCount" offset=2
26350                        when="{'0': 'Nobody is viewing.',
26351                               '1': '{{person1}} is viewing.',
26352                               '2': '{{person1}} and {{person2}} are viewing.',
26353                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
26354                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
26355          </ng-pluralize>
26356        </div>
26357      </file>
26358      <file name="protractor.js" type="protractor">
26359        it('should show correct pluralized string', function() {
26360          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
26361          var withOffset = element.all(by.css('ng-pluralize')).get(1);
26362          var countInput = element(by.model('personCount'));
26363
26364          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
26365          expect(withOffset.getText()).toEqual('Igor is viewing.');
26366
26367          countInput.clear();
26368          countInput.sendKeys('0');
26369
26370          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
26371          expect(withOffset.getText()).toEqual('Nobody is viewing.');
26372
26373          countInput.clear();
26374          countInput.sendKeys('2');
26375
26376          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
26377          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
26378
26379          countInput.clear();
26380          countInput.sendKeys('3');
26381
26382          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
26383          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
26384
26385          countInput.clear();
26386          countInput.sendKeys('4');
26387
26388          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
26389          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
26390        });
26391        it('should show data-bound names', function() {
26392          var withOffset = element.all(by.css('ng-pluralize')).get(1);
26393          var personCount = element(by.model('personCount'));
26394          var person1 = element(by.model('person1'));
26395          var person2 = element(by.model('person2'));
26396          personCount.clear();
26397          personCount.sendKeys('4');
26398          person1.clear();
26399          person1.sendKeys('Di');
26400          person2.clear();
26401          person2.sendKeys('Vojta');
26402          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
26403        });
26404      </file>
26405    </example>
26406 */
26407var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
26408  var BRACE = /{}/g,
26409      IS_WHEN = /^when(Minus)?(.+)$/;
26410
26411  return {
26412    link: function(scope, element, attr) {
26413      var numberExp = attr.count,
26414          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
26415          offset = attr.offset || 0,
26416          whens = scope.$eval(whenExp) || {},
26417          whensExpFns = {},
26418          startSymbol = $interpolate.startSymbol(),
26419          endSymbol = $interpolate.endSymbol(),
26420          braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
26421          watchRemover = angular.noop,
26422          lastCount;
26423
26424      forEach(attr, function(expression, attributeName) {
26425        var tmpMatch = IS_WHEN.exec(attributeName);
26426        if (tmpMatch) {
26427          var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
26428          whens[whenKey] = element.attr(attr.$attr[attributeName]);
26429        }
26430      });
26431      forEach(whens, function(expression, key) {
26432        whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
26433
26434      });
26435
26436      scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
26437        var count = parseFloat(newVal);
26438        var countIsNaN = isN
vendor: 10,458 bytes, lines 26438-26664
26438aN(count);
26439
26440        if (!countIsNaN && !(count in whens)) {
26441          // If an explicit number rule such as 1, 2, 3... is defined, just use it.
26442          // Otherwise, check it against pluralization rules in $locale service.
26443          count = $locale.pluralCat(count - offset);
26444        }
26445
26446        // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
26447        // In JS `NaN !== NaN`, so we have to exlicitly check.
26448        if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
26449          watchRemover();
26450          var whenExpFn = whensExpFns[count];
26451          if (isUndefined(whenExpFn)) {
26452            if (newVal != null) {
26453              $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
26454            }
26455            watchRemover = noop;
26456            updateElementText();
26457          } else {
26458            watchRemover = scope.$watch(whenExpFn, updateElementText);
26459          }
26460          lastCount = count;
26461        }
26462      });
26463
26464      function updateElementText(newText) {
26465        element.text(newText || '');
26466      }
26467    }
26468  };
26469}];
26470
26471/**
26472 * @ngdoc directive
26473 * @name ngRepeat
26474 *
26475 * @description
26476 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
26477 * instance gets its own scope, where the given loop variable is set to the current collection item,
26478 * and `$index` is set to the item index or key.
26479 *
26480 * Special properties are exposed on the local scope of each template instance, including:
26481 *
26482 * | Variable  | Type            | Details                                                                     |
26483 * |-----------|-----------------|-----------------------------------------------------------------------------|
26484 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
26485 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
26486 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
26487 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
26488 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
26489 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
26490 *
26491 * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
26492 * This may be useful when, for instance, nesting ngRepeats.
26493 *
26494 *
26495 * # Iterating over object properties
26496 *
26497 * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
26498 * syntax:
26499 *
26500 * ```js
26501 * <div ng-repeat="(key, value) in myObj"> ... </div>
26502 * ```
26503 *
26504 * You need to be aware that the JavaScript specification does not define the order of keys
26505 * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
26506 * used to sort the keys alphabetically.)
26507 *
26508 * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
26509 * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
26510 * keys in the order in which they were defined, although there are exceptions when keys are deleted
26511 * and reinstated. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
26512 *
26513 * If this is not desired, the recommended workaround is to convert your object into an array
26514 * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
26515 * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
26516 * or implement a `$watch` on the object yourself.
26517 *
26518 *
26519 * # Tracking and Duplicates
26520 *
26521 * When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
26522 *
26523 * * When an item is added, a new instance of the template is added to the DOM.
26524 * * When an item is removed, its template instance is removed from the DOM.
26525 * * When items are reordered, their respective templates are reordered in the DOM.
26526 *
26527 * By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
26528 * there are duplicates, it is not possible to maintain a one-to-one mapping between collection
26529 * items and DOM elements.
26530 *
26531 * If you do need to repeat duplicate items, you can substitute the default tracking behavior
26532 * with your own using the `track by` expression.
26533 *
26534 * For example, you may track items by the index of each item in the collection, using the
26535 * special scope property `$index`:
26536 * ```html
26537 *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
26538 *      {{n}}
26539 *    </div>
26540 * ```
26541 *
26542 * You may use arbitrary expressions in `track by`, including references to custom functions
26543 * on the scope:
26544 * ```html
26545 *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
26546 *      {{n}}
26547 *    </div>
26548 * ```
26549 *
26550 * If you are working with objects that have an identifier property, you can track
26551 * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
26552 * will not have to rebuild the DOM elements for items it has already rendered, even if the
26553 * JavaScript objects in the collection have been substituted for new ones:
26554 * ```html
26555 *    <div ng-repeat="model in collection track by model.id">
26556 *      {{model.name}}
26557 *    </div>
26558 * ```
26559 *
26560 * When no `track by` expression is provided, it is equivalent to tracking by the built-in
26561 * `$id` function, which tracks items by their identity:
26562 * ```html
26563 *    <div ng-repeat="obj in collection track by $id(obj)">
26564 *      {{obj.prop}}
26565 *    </div>
26566 * ```
26567 *
26568 * # Special repeat start and end points
26569 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
26570 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
26571 * 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)
26572 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
26573 *
26574 * The example below makes use of this feature:
26575 * ```html
26576 *   <header ng-repeat-start="item in items">
26577 *     Header {{ item }}
26578 *   </header>
26579 *   <div class="body">
26580 *     Body {{ item }}
26581 *   </div>
26582 *   <footer ng-repeat-end>
26583 *     Footer {{ item }}
26584 *   </footer>
26585 * ```
26586 *
26587 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
26588 * ```html
26589 *   <header>
26590 *     Header A
26591 *   </header>
26592 *   <div class="body">
26593 *     Body A
26594 *   </div>
26595 *   <footer>
26596 *     Footer A
26597 *   </footer>
26598 *   <header>
26599 *     Header B
26600 *   </header>
26601 *   <div class="body">
26602 *     Body B
26603 *   </div>
26604 *   <footer>
26605 *     Footer B
26606 *   </footer>
26607 * ```
26608 *
26609 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
26610 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
26611 *
26612 * @animations
26613 * **.enter** - when a new item is added to the list or when an item is revealed after a filter
26614 *
26615 * **.leave** - when an item is removed from the list or when an item is filtered out
26616 *
26617 * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
26618 *
26619 * @element ANY
26620 * @scope
26621 * @priority 1000
26622 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
26623 *   formats are currently supported:
26624 *
26625 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
26626 *     is a scope expression giving the collection to enumerate.
26627 *
26628 *     For example: `album in artist.albums`.
26629 *
26630 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
26631 *     and `expression` is the scope expression giving the collection to enumerate.
26632 *
26633 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
26634 *
26635 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
26636 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
26637 *     is specified, ng-repeat associates elements by identity. It is an error to have
26638 *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
26639 *     mapped to the same DOM element, which is not possible.)  If filters are used in the expression, they should be
26640 *     applied before the tracking expression.
26641 *
26642 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
26643 *     will be associated by item identity in the array.
26644 *
26645 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
26646 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
26647 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
26648 *     element in the same way in the DOM.
26649 *
26650 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
26651 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
26652 *     property is same.
26653 *
26654 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
26655 *     to items in conjunction with a tracking expression.
26656 *
26657 *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
26658 *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
26659 *     when a filter is active on the repeater, but the filtered result set is empty.
26660 *
26661 *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
26662 *     the items have been processed through the filter.
26663 *
26664 *     Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax s
26664o it can be used only at the end
26665 *     (and not as operator, inside an expression).
26666 *
26667 *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
26668 *
26669 * @example
26670 * This example initializes the scope to a list of names and
26671 * then uses `ngRepeat` to display every person:
26672  <example module="ngAnimate" deps="angular-animate.js" animations="true">
26673    <file name="index.html">
26674      <div ng-init="friends = [
26675        {name:'John', age:25, gender:'boy'},
26676        {name:'Jessie', age:30, gender:'girl'},
26677        {name:'Johanna', age:28, gender:'girl'},
26678        {name:'Joy', age:15, gender:'girl'},
26679        {name:'Mary', age:28, gender:'girl'},
26680        {name:'Peter', age:95, gender:'boy'},
26681        {name:'Sebastian', age:50, gender:'boy'},
26682        {name:'Erika', age:27, gender:'girl'},
26683        {name:'Patrick', age:40, gender:'boy'},
26684        {name:'Samantha', age:60, gender:'girl'}
26685      ]">
26686        I have {{friends.length}} friends. They are:
26687        <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
26688        <ul class="example-animate-container">
26689          <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
26690            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
26691          </li>
26692          <li class="animate-repeat" ng-if="results.length == 0">
26693            <strong>No results found...</strong>
26694          </li>
26695        </ul>
26696      </div>
26697    </file>
26698    <file name="animations.css">
26699      .example-animate-container {
26700        background:white;
26701        border:1px solid black;
26702        list-style:none;
26703        margin:0;
26704        padding:0 10px;
26705      }
26706
26707      .animate-repeat {
26708        line-height:40px;
26709        list-style:none;
26710        box-sizing:border-box;
26711      }
26712
26713      .animate-repeat.ng-move,
26714      .animate-repeat.ng-enter,
26715      .animate-repeat.ng-leave {
26716        -webkit-transition:all linear 0.5s;
26717        transition:all linear 0.5s;
26718      }
26719
26720      .animate-repeat.ng-leave.ng-leave-active,
26721      .animate-repeat.ng-move,
26722      .animate-repeat.ng-enter {
26723        opacity:0;
26724        max-height:0;
26725      }
26726
26727      .animate-repeat.ng-leave,
26728      .animate-repeat.ng-move.ng-move-active,
26729      .animate-repeat.ng-enter.ng-enter-active {
26730        opacity:1;
26731        max-height:40px;
26732      }
26733    </file>
26734    <file name="protractor.js" type="protractor">
26735      var friends = element.all(by.repeater('friend in friends'));
26736
26737      it('should render initial data set', function() {
26738        expect(friends.count()).toBe(10);
26739        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
26740        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
26741        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
26742        expect(element(by.binding('friends.length')).getText())
26743            .toMatch("I have 10 friends. They are:");
26744      });
26745
26746       it('should update repeater when filter predicate changes', function() {
26747         expect(friends.count()).toBe(10);
26748
26749         element(by.model('q')).sendKeys('ma');
26750
26751         expect(friends.count()).toBe(2);
26752         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
26753         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
26754       });
26755      </file>
26756    </example>
26757 */
26758var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
26759  var NG_REMOVED = '$$NG_REMOVED';
26760  var ngRepeatMinErr = minErr('ngRepeat');
26761
26762  var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
26763    // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
26764    scope[valueIdentifier] = value;
26765    if (keyIdentifier) scope[keyIdentifier] = key;
26766    scope.$index = index;
26767    scope.$first = (index === 0);
26768    scope.$last = (index === (arrayLength - 1));
26769    scope.$middle = !(scope.$first || scope.$last);
26770    // jshint bitwise: false
26771    scope.$odd = !(scope.$even = (index&1) === 0);
26772    // jshint bitwise: true
26773  };
26774
26775  var getBlockStart = function(block) {
26776    return block.clone[0];
26777  };
26778
26779  var getBlockEnd = function(block) {
26780    return block.clone[block.clone.length - 1];
26781  };
26782
26783
26784  return {
26785    restrict: 'A',
26786    multiElement: true,
26787    transclude: 'element',
26788    priority: 1000,
26789    terminal: true,
26790    $$tlb: true,
26791    compile: function ngRepeatCompile($element, $attr) {
26792      var expression = $attr.ngRepeat;
26793      var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
26794
26795      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*$/);
26796
26797      if (!match) {
26798        throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
26799            expression);
26800      }
26801
26802      var lhs = match[1];
26803      var rhs = match[2];
26804      var aliasAs = match[3];
26805      var trackByExp = match[4];
26806
26807      match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
26808
26809      if (!match) {
26810        throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
26811            lhs);
26812      }
26813      var valueIdentifier = match[3] || match[1];
26814      var keyIdentifier = match[2];
26815
26816      if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
26817          /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
26818        throw ngRepeatMinErr('badident', "alias '{0}
vendor: 11,910 bytes, lines 26818-27089
26818' is invalid --- must be a valid JS identifier which is not a reserved name.",
26819          aliasAs);
26820      }
26821
26822      var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
26823      var hashFnLocals = {$id: hashKey};
26824
26825      if (trackByExp) {
26826        trackByExpGetter = $parse(trackByExp);
26827      } else {
26828        trackByIdArrayFn = function(key, value) {
26829          return hashKey(value);
26830        };
26831        trackByIdObjFn = function(key) {
26832          return key;
26833        };
26834      }
26835
26836      return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
26837
26838        if (trackByExpGetter) {
26839          trackByIdExpFn = function(key, value, index) {
26840            // assign key, value, and $index to the locals so that they can be used in hash functions
26841            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
26842            hashFnLocals[valueIdentifier] = value;
26843            hashFnLocals.$index = index;
26844            return trackByExpGetter($scope, hashFnLocals);
26845          };
26846        }
26847
26848        // Store a list of elements from previous run. This is a hash where key is the item from the
26849        // iterator, and the value is objects with following properties.
26850        //   - scope: bound scope
26851        //   - element: previous element.
26852        //   - index: position
26853        //
26854        // We are using no-proto object so that we don't need to guard against inherited props via
26855        // hasOwnProperty.
26856        var lastBlockMap = createMap();
26857
26858        //watch props
26859        $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
26860          var index, length,
26861              previousNode = $element[0],     // node that cloned nodes should be inserted after
26862                                              // initialized to the comment node anchor
26863              nextNode,
26864              // Same as lastBlockMap but it has the current state. It will become the
26865              // lastBlockMap on the next iteration.
26866              nextBlockMap = createMap(),
26867              collectionLength,
26868              key, value, // key/value of iteration
26869              trackById,
26870              trackByIdFn,
26871              collectionKeys,
26872              block,       // last object information {scope, element, id}
26873              nextBlockOrder,
26874              elementsToRemove;
26875
26876          if (aliasAs) {
26877            $scope[aliasAs] = collection;
26878          }
26879
26880          if (isArrayLike(collection)) {
26881            collectionKeys = collection;
26882            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
26883          } else {
26884            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
26885            // if object, extract keys, in enumeration order, unsorted
26886            collectionKeys = [];
26887            for (var itemKey in collection) {
26888              if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
26889                collectionKeys.push(itemKey);
26890              }
26891            }
26892          }
26893
26894          collectionLength = collectionKeys.length;
26895          nextBlockOrder = new Array(collectionLength);
26896
26897          // locate existing items
26898          for (index = 0; index < collectionLength; index++) {
26899            key = (collection === collectionKeys) ? index : collectionKeys[index];
26900            value = collection[key];
26901            trackById = trackByIdFn(key, value, index);
26902            if (lastBlockMap[trackById]) {
26903              // found previously seen block
26904              block = lastBlockMap[trackById];
26905              delete lastBlockMap[trackById];
26906              nextBlockMap[trackById] = block;
26907              nextBlockOrder[index] = block;
26908            } else if (nextBlockMap[trackById]) {
26909              // if collision detected. restore lastBlockMap and throw an error
26910              forEach(nextBlockOrder, function(block) {
26911                if (block && block.scope) lastBlockMap[block.id] = block;
26912              });
26913              throw ngRepeatMinErr('dupes',
26914                  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
26915                  expression, trackById, value);
26916            } else {
26917              // new never before seen block
26918              nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
26919              nextBlockMap[trackById] = true;
26920            }
26921          }
26922
26923          // remove leftover items
26924          for (var blockKey in lastBlockMap) {
26925            block = lastBlockMap[blockKey];
26926            elementsToRemove = getBlockNodes(block.clone);
26927            $animate.leave(elementsToRemove);
26928            if (elementsToRemove[0].parentNode) {
26929              // if the element was not removed yet because of pending animation, mark it as deleted
26930              // so that we can ignore it later
26931              for (index = 0, length = elementsToRemove.length; index < length; index++) {
26932                elementsToRemove[index][NG_REMOVED] = true;
26933              }
26934            }
26935            block.scope.$destroy();
26936          }
26937
26938          // we are not using forEach for perf reasons (trying to avoid #call)
26939          for (index = 0; index < collectionLength; index++) {
26940            key = (collection === collectionKeys) ? index : collectionKeys[index];
26941            value = collection[key];
26942            block = nextBlockOrder[index];
26943
26944            if (block.scope) {
26945              // if we have already seen this object, then we need to reuse the
26946              // associated scope/element
26947
26948              nextNode = previousNode;
26949
26950              // skip nodes that are already pending removal via leave animation
26951              do {
26952                nextNode = nextNode.nextSibling;
26953              } while (nextNode && nextNode[NG_REMOVED]);
26954
26955              if (getBlockStart(block) != nextNode) {
26956                // existing item which got moved
26957                $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
26958              }
26959              previousNode = getBlockEnd(block);
26960              updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
26961            } else {
26962              // new item which we don't know about
26963              $transclude(function ngRepeatTransclude(clone, scope) {
26964                block.scope = scope;
26965                // http://jsperf.com/clone-vs-createcomment
26966                var endNode = ngRepeatEndComment.cloneNode(false);
26967                clone[clone.length++] = endNode;
26968
26969                // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
26970                $animate.enter(clone, null, jqLite(previousNode));
26971                previousNode = endNode;
26972                // Note: We only need the first/last node of the cloned nodes.
26973                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
26974                // by a directive with templateUrl when its template arrives.
26975                block.clone = clone;
26976                nextBlockMap[block.id] = block;
26977                updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
26978              });
26979            }
26980          }
26981          lastBlockMap = nextBlockMap;
26982        });
26983      };
26984    }
26985  };
26986}];
26987
26988var NG_HIDE_CLASS = 'ng-hide';
26989var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
26990/**
26991 * @ngdoc directive
26992 * @name ngShow
26993 *
26994 * @description
26995 * The `ngShow` directive shows or hides the given HTML element based on the expression
26996 * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
26997 * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
26998 * in AngularJS and sets the display style to none (using an !important flag).
26999 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27000 *
27001 * ```html
27002 * <!-- when $scope.myValue is truthy (element is visible) -->
27003 * <div ng-show="myValue"></div>
27004 *
27005 * <!-- when $scope.myValue is falsy (element is hidden) -->
27006 * <div ng-show="myValue" class="ng-hide"></div>
27007 * ```
27008 *
27009 * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
27010 * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
27011 * from the element causing the element not to appear hidden.
27012 *
27013 * ## Why is !important used?
27014 *
27015 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27016 * can be easily overridden by heavier selectors. For example, something as simple
27017 * as changing the display style on a HTML list item would make hidden elements appear visible.
27018 * This also becomes a bigger issue when dealing with CSS frameworks.
27019 *
27020 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27021 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27022 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27023 *
27024 * ### Overriding `.ng-hide`
27025 *
27026 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27027 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27028 * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
27029 * with extra animation classes that can be added.
27030 *
27031 * ```css
27032 * .ng-hide:not(.ng-hide-animate) {
27033 *   /&#42; this is just another form of hiding an element &#42;/
27034 *   display: block!important;
27035 *   position: absolute;
27036 *   top: -9999px;
27037 *   left: -9999px;
27038 * }
27039 * ```
27040 *
27041 * By default you don't need to override in CSS anything and the animations will work around the display style.
27042 *
27043 * ## A note about animations with `ngShow`
27044 *
27045 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27046 * is true and false. This system works like the animation system present with ngClass except that
27047 * you must also include the !important flag to override the display property
27048 * so that you can perform an animation when the element is hidden during the time of the animation.
27049 *
27050 * ```css
27051 * //
27052 * //a working example can be found at the bottom of this page
27053 * //
27054 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27055 *   /&#42; this is required as of 1.3x to properly
27056 *      apply all styling in a show/hide animation &#42;/
27057 *   transition: 0s linear all;
27058 * }
27059 *
27060 * .my-element.ng-hide-add-active,
27061 * .my-element.ng-hide-remove-active {
27062 *   /&#42; the transition is defined in the active class &#42;/
27063 *   transition: 1s linear all;
27064 * }
27065 *
27066 * .my-element.ng-hide-add { ... }
27067 * .my-element.ng-hide-add.ng-hide-add-active { ... }
27068 * .my-element.ng-hide-remove { ... }
27069 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27070 * ```
27071 *
27072 * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27073 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27074 *
27075 * @animations
27076 * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
27077 * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
27078 *
27079 * @element ANY
27080 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
27081 *     then the element is shown or hidden respectively.
27082 *
27083 * @example
27084  <example module="ngAnimate" deps="angular-animate.js" animations="true">
27085    <file name="index.html">
27086      Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
27087      <div>
27088        Show:
27089        <div class="check-element animate-show" ng-show="checked">
27090          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27091        </div>
27092      </div>
27093      <div>
27094        Hide:
27095        <div class="check-element animate-show" ng-hide="checked">
27096          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27097        </div>
27098      </div>
27099    </file>
27100    <file name="glyphicons.css">
27101      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27102    </file>
27103    <file name="animations.css">
27104      .animate-show {
27105        line-height: 20px;
27106        opacity: 1;
27107        padding: 10px;
27108        border: 1px solid black;
27109        background: white;
27110      }
27111
27112      .animate-show.ng-hide-add.ng-hide-add-active,
27113      .animate-show.ng-hide-remove.ng-hide-remove-active {
27114        -webkit-transition: all linear 0.5s;
27115        transition: all linear 0.5s;
27116      }
27117
27118      .animate-show.ng-hide {
27119        line-height: 0;
27120        opacity: 0;
27121        padding: 0 10px;
27122      }
27123
27124      .check-element {
27125        padding: 10px;
27126        border: 1px solid black;
27127        background: white;
27128      }
27129    </file>
27130    <file name="protractor.js" type="protractor">
27131      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27132      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27133
27134      it('should check ng-show / ng-hide', function() {
27135        expect(thumbsUp.isDisplayed()).toBeFalsy();
27136        expect(thumbsDown.isDisplayed()).toBeTruthy();
27137
27138        element(by.model('checked')).click();
27139
27140        expect(thumbsUp.isDisplayed()).toBeTruthy();
27141        expect(thumbsDown.isDisplayed()).toBeFalsy();
27142      });
27143    </file>
27144  </example>
27145 */
27146var ngShowDirective = ['$animate', function($animate) {
27147  return {
27148    restrict: 'A',
27149    multiElement: true,
27150    link: function(scope, element, attr) {
27151      scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
27152        // we're adding a temporary, animation-specific class for ng-hide since this way
27153        // we can control when the element is actually displayed on screen without having
27154        // to have a global/greedy CSS selector that breaks when other animations are run.
27155        // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
27156        $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
27157          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27158        });
27159      });
27160    }
27161  };
27162}];
27163
27164
27165/**
27166 * @ngdoc directive
27167 * @name ngHide
27168 *
27169 * @description
27170 * The `ngHide` directive shows or hides the given HTML element based on the expression
27171 * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
27172 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
27173 * in AngularJS and sets the display style to none (using an !important flag).
27174 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
27175 *
27176 * ```html
27177 * <!-- when $scope.myValue is truthy (element is hidden) -->
27178 * <div ng-hide="myValue" class="ng-hide"></div>
27179 *
27180 * <!-- when $scope.myValue is falsy (element is visible) -->
27181 * <div ng-hide="myValue"></div>
27182 * ```
27183 *
27184 * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
27185 * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
27186 * from the element causing the element not to appear hidden.
27187 *
27188 * ## Why is !important used?
27189 *
27190 * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
27191 * can be easily overridden by heavier selectors. For example, something as simple
27192 * as changing the display style on a HTML list item would make hidden elements appear visible.
27193 * This also becomes a bigger issue when dealing with CSS frameworks.
27194 *
27195 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
27196 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
27197 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
27198 *
27199 * ### Overriding `.ng-hide`
27200 *
27201 * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
27202 * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
27203 * class in CSS:
27204 *
27205 * ```css
27206 * .ng-hide {
27207 *   /&#42; this is just another form of hiding an element &#42;/
27208 *   display: block!important;
27209 *   position: absolute;
27210 *   top: -9999px;
27211 *   left: -9999px;
27212 * }
27213 * ```
27214 *
27215 * By default you don't need to override in CSS anything and the animations will work around the display style.
27216 *
27217 * ## A note about animations with `ngHide`
27218 *
27219 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
27220 * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
27221 * CSS class is added and removed for you instead of your own CSS class.
27222 *
27223 * ```css
27224 * //
27225 * //a working example can be found at the bottom of this page
27226 * //
27227 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
27228 *   transition: 0.5s linear all;
27229 * }
27230 *
27231 * .my-element.ng-hide-add { ... }
27232 * .my-element.ng-hide-add.ng-hide-add-active { ... }
27233 * .my-element.ng-hide-remove { ... }
27234 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
27235 * ```
27236 *
27237 * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
27238 * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
27239 *
27240 * @animations
27241 * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
27242 * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
27243 *
27244 * @element ANY
27245 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
27246 *     the element is shown or hidden respectively.
27247 *
27248 * @example
27249  <example module="ngAnimate" deps="angular-animate.js" animations="true">
27250    <file name="index.html">
27251      Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
27252      <div>
27253        Show:
27254        <div class="check-element animate-hide" ng-show="checked">
27255          <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
27256        </div>
27257      </div>
27258      <div>
27259        Hide:
27260        <div class="check-element animate-hide" ng-hide="checked">
27261          <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
27262        </div>
27263      </div>
27264    </file>
27265    <file name="glyphicons.css">
27266      @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
27267    </file>
27268    <file name="animations.css">
27269      .animate-hide {
27270        -webkit-transition: all linear 0.5s;
27271        transition: all linear 0.5s;
27272        line-height: 20px;
27273        opacity: 1;
27274        padding: 10px;
27275        border: 1px solid black;
27276        background: white;
27277      }
27278
27279      .animate-hide.ng-hide {
27280        line-height: 0;
27281        opacity: 0;
27282        padding: 0 10px;
27283      }
27284
27285      .check-element {
27286        padding: 10px;
27287        border: 1px solid black;
27288        background: white;
27289      }
27290    </file>
27291    <file name="protractor.js" type="protractor">
27292      var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
27293      var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
27294
27295      it('should check ng-show / ng-hide', function() {
27296        expect(thumbsUp.isDisplayed()).toBeFalsy();
27297        expect(thumbsDown.isDisplayed()).toBeTruthy();
27298
27299        element(by.model('checked')).click();
27300
27301        expect(thumbsUp.isDisplayed()).toBeTruthy();
27302        expect(thumbsDown.isDisplayed()).toBeFalsy();
27303      });
27304    </file>
27305  </example>
27306 */
27307var ngHideDirective = ['$animate', function($animate) {
27308  return {
27309    restrict: 'A',
27310    multiElement: true,
27311    link: function(scope, element, attr) {
27312      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
27313        // The comment inside of the ngShowDirective explains why we add and
27314        // remove a temporary class for the show/hide animation
27315        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
27316          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
27317        });
27318      });
27319    }
27320  };
27321}];
27322
27323/**
27324 * @ngdoc directive
27325 * @name ngStyle
27326 * @restrict AC
27327 *
27328 * @description
27329 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
27330 *
27331 * @element ANY
27332 * @param {expression} ngStyle
27333 *
27334 * {@link guide/expression Expression} which evals to an
27335 * object whose keys are CSS style names and values are corresponding values for those CSS
27336 * keys.
27337 *
27338 * Since some CSS style names are not valid keys for an object, they must be quoted.
27339 * See the 'background-color' style in the example below.
27340 *
27341 * @example
27342   <example>
27343     <file name="index.html">
27344        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
27345        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
27346        <input type="button" value="clear" ng-click="myStyle={}">
27347        <br/>
27348        <span ng-style="myStyle">Sample Text</span>
27349        <pre>myStyle={{myStyle}}</pre>
27350     </file>
27351     <file name="style.css">
27352       span {
27353         color: black;
27354       }
27355     </file>
27356     <file name="protractor.js" type="protractor">
27357       var colorSpan = element(by.css('span'));
27358
27359       it('should check ng-style', function() {
27360         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
27361         element(by.css('input[value=\'set color\']')).click();
27362         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
27363         element(by.css('input[value=clear]')).click();
27364         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
27365       });
27366     </file>
27367   </example>
27368 */
27369var ngStyleDirective = ngDirective(function(scope, element, attr) {
27370  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
27371    if (oldStyles && (newStyles !== oldStyles)) {
27372      forEach(oldStyles, function(val, style) { element.css(style, '');});
27373    }
27374    if (newStyles) element.css(newStyles);
27375  }, true);
27376});
27377
27378/**
27379 * @ngdoc directive
27380 * @name ngSwitch
27381 * @restrict EA
27382 *
27383 * @description
27384 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
27385 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
27386 * as specified in the template.
27387 *
27388 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
27389 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
27390 * matches the value obtained from the evaluated expression. In other words, you define a container element
27391 * (where you place the directive), place an expression on the **`on="..."` attribute**
27392 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
27393 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
27394 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
27395 * attribute is displayed.
27396 *
27397 * <div class="alert alert-info">
27398 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
27399 * as literal string values to match against.
27400 * For example, **`ng-switch-when="someVal"`** will match against the string `"s
27400omeVal"` not against the
27401 * value of the expression `$scope.someVal`.
27402 * </div>
27403
27404 * @animations
27405 * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
27406 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
27407 *
27408 * @usage
27409 *
27410 * ```
27411 * <ANY ng-switch="expression">
27412 *   <ANY ng-switch-when="matchValue1">...</ANY>
27413 *   <ANY ng-switch-when="matchValue2">...</ANY>
27414 *   <ANY ng-switch-default>...</ANY>
27415 * </ANY>
27416 * ```
27417 *
27418 *
27419 * @scope
27420 * @priority 1200
27421 * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
27422 * On child elements add:
27423 *
27424 * * `ngSwitchWhen`: the case statement to match against. If match then this
27425 *   case will be displayed. If the same match appears multiple times, all the
27426 *   elements will be displayed.
27427 * * `ngSwitchDefault`: the default case when no other case match. If there
27428 *   are multiple default cases, all of them will be displayed when no other
27429 *   case match.
27430 *
27431 *
27432 * @example
27433  <example module="switchExample" deps="angular-animate.js" animations="true">
27434    <file name="index.html">
27435      <div ng-controller="ExampleController">
27436        <select ng-model="selection" ng-options="item for item in items">
27437        </select>
27438        <code>selection={{selection}}</code>
27439        <hr/>
27440        <div class="animate-switch-container"
27441          ng-switch on="selection">
27442            <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
27443            <div class="animate-switch" ng-switch-when="home">Home Span</div>
27444            <div class="animate-switch" ng-switch-default>default</div>
27445        </div>
27446      </div>
27447    </file>
27448    <file name="script.js">
27449      angular.module('switchExample', ['ngAnimate'])
27450        .controller('ExampleController', ['$scope', function($scope) {
27451          $scope.items = ['settings', 'home', 'other'];
27452          $scope.selection = $scope.items[0];
27453        }]);
27454    </file>
27455    <file name="animations.css">
27456      .animate-switch-container {
27457        position:relative;
27458        background:white;
27459        border:1px solid black;
27460        height:40px;
27461        overflow:hidden;
27462      }
27463
27464      .animate-switch {
27465        padding:10px;
27466      }
27467
27468      .animate-switch.ng-animate {
27469        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
27470        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
27471
27472        position:absolute;
27473        top:0;
27474        left:0;
27475        right:0;
27476        bottom:0;
27477      }
27478
27479      .animate-switch.ng-leave.ng-leave-active,
27480      .animate-switch.ng-enter {
27481        top:-50px;
27482      }
27483      .animate-switch.ng-leave,
27484      .animate-switch.ng-enter.ng-enter-active {
27485        top:0;
27486      }
27487    </file>
27488    <file name="protractor.js" type="protractor">
27489      var switchElem = element(by.css('[ng-switch]'));
27490      var select = element(by.model('selection'));
27491
27492      it('should start in settings', function() {
27493        expect(switchElem.getText()).toMatch(/Settings Div/);
27494      });
27495      it('should change to home', function() {
27496        select.all(by.css('option')).get(1).click();
27497        expect(switchElem.getText()).toMatch(/Home Span/);
27498      });
27499      it('should select default', function() {
27500        select.all(by.css('option')).get(2).click();
27501        expect(switchElem.getText()).toMatch(/default/);
27502      });
27503    </file>
27504  </example>
27505 */
27506var ngSwitchDirective = ['$animate', function($animate) {
27507  return {
27508    require: 'ngSwitch',
27509
27510    // asks for $scope to fool the BC controller module
27511    controller: ['$scope', function ngSwitchController() {
27512     this.cases = {};
27513    }],
27514    link: function(scope, element, attr, ngSwitchController) {
27515      var watchExpr = attr.ngSwitch || attr.on,
27516          selectedTranscludes = [],
27517          selectedElements = [],
27518          previousLeaveAnimations = [],
27519          selectedScopes = [];
27520
27521      var spliceFactory = function(array, index) {
27522          return function() { array.splice(index, 1); };
27523      };
27524
27525      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
27526        var i, ii;
27527        for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
27528          $animate.cancel(previousLeaveAnimations[i]);
27529        }
27530        previousLeaveAnimations.length = 0;
27531
27532        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
27533          var selected = getBlockNodes(selectedElements[i].clone);
27534          selectedScopes[i].$destroy();
27535          var promise = previousLeaveAnimations[i] = $animate.leave(selected);
27536          promise.then(spliceFactory(previousLeaveAnimations, i));
27537        }
27538
27539        selectedElements.length = 0;
27540        selectedScopes.length = 0;
27541
27542        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
27543          forEach(selectedTranscludes, function(selectedTransclude) {
27544            selectedTransclude.transclude(function(caseElement, selectedScope) {
27545              selectedScopes.push(selectedScope);
27546              var anchor = selectedTransclude.element;
27547              caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
27548              var block = { clone: caseElement };
27549
27550              selectedElements.push(block);
27551              $animate.enter(caseElement, anchor.parent(), anchor);
27552            });
27553          });
27554        }
27555      });
27556    }
27557  };
27558}];
27559
27560var ngSwitchWhenDirective = ngDirective({
27561  transclude: 'element',
27562  priority: 1200,
27563  require: '^ngSwitch',
27564  multiElement: true,
27565  link: function(scope, element, attrs, ctrl, $transclude) {
27566    ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
27567    ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
27568  }
27569});
27570
27571var ngSwitchDefaultDirective = ngDirective({
27572  transclude: 'element',
27573  priority: 1200,
27574  require: '^ngSwitch',
27575  multiElement: true,
27576  link: function(scope, element, attr, ctrl, $transclude) {
27577    ctrl.cases['?'] = (ctrl.cases['?'] || []);
27578    ctrl.cases['?'].push({ transclude: $transclude, element: element });
27579   }
27580});
27581
27582/**
27583 * @ngdoc directive
27584 * @name ngTransclude
27585 * @restrict EAC
27586 *
27587 * @description
27588 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
27589 *
27590 * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
27591 *
27592 * @element ANY
27593 *
27594 * @example
27595   <example module="transcludeExample">
27596     <file name="index.html">
27597       <script>
27598         angular.module('transcludeExample', [])
27599          .directive('pane', function(){
27600             return {
27601               restrict: 'E',
27602               transclude: true,
27603               scope: { title:'@' },
27604               template: '<div style="border: 1px solid black;">' +
27605                           '<div style="background-color: gray">{{title}}</div>' +
27606                           '<ng-transclude></ng-transclude>' +
27607                         '</div>'
27608             };
27609         })
27610         .controller('ExampleController', ['$scope', function($scope) {
27611           $scope.title = 'Lorem Ipsum';
27612           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
27613         }]);
27614       </script>
27615       <div ng-controller="ExampleController">
27616         <input ng-model="title" aria-label="title"> <br/>
27617         <textarea ng-model="text" aria-label="text"></textarea> <br/>
27618         <pane title="{{title}}">{{text}}</pane>
27619       </div>
27620     </file>
27621     <file name="protractor.js" type="protractor">
27622        it('should have transcluded', function() {
27623          var titleElement = element(by.model('title'));
27624          titleElement.clear();
27625          titleElement.sendKeys('TITLE');
27626          var textElement = element(by.model('text'));
27627          textElement.clear();
27628          textElement.sendKeys('TEXT');
27629          expect(element(by.binding('title')).getText()).toEqual('TITLE');
27630          expect(element(by.binding('text')).getText()).toEqual('TEXT');
27631        });
27632     </file>
27633   </example>
27634 *
27635 */
27636var ngTranscludeDirective = ngDirective({
27637  restrict: 'EAC',
27638  link: function($scope, $element, $attrs, controller, $transclude) {
27639    if (!$transclude) {
27640      throw minErr('ngTransclude')('orphan',
27641       'Illegal use of ngTransclude directive in the template! ' +
27642       'No parent directive that requires a transclusion found. ' +
27643       'Element: {0}',
27644       startingTag($element));
27645    }
27646
27647    $transclude(function(clone) {
27648      $element.empty();
27649      $element.append(clone);
27650    });
27651  }
27652});
27653
27654/**
27655 * @ngdoc directive
27656 * @name script
27657 * @restrict E
27658 *
27659 * @description
27660 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
27661 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
27662 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
27663 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
27664 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
27665 *
27666 * @param {string} type Must be set to `'text/ng-template'`.
27667 * @param {string} id Cache name of the template.
27668 *
27669 * @example
27670  <example>
27671    <file name="index.html">
27672      <script type="text/ng-template" id="/tpl.html">
27673        Content of the template.
27674      </script>
27675
27676      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
27677      <div id="tpl-content" ng-include src="currentTpl"></div>
27678    </file>
27679    <file name="protractor.js" type="protractor">
27680      it('should load template defined inside script tag', function() {
27681        element(by.css('#tpl-link')).click();
27682        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
27683      });
27684    </file>
27685  </example>
27686 */
27687var scriptDirective = ['$templateCache', function($templateCache) {
27688  return {
27689    restrict: 'E',
27690    terminal: true,
27691    compile: function(element, attr) {
27692      if (attr.type == 'text/ng-template') {
27693        var templateUrl = attr.id,
27694            text = element[0].text;
27695
27696        $templateCache.put(templateUrl, text);
27697      }
27698    }
27699  };
27700}];
27701
27702var noopNgModelController = { $setViewValue: noop, $render: noop };
27703
27704/**
27705 * @ngdoc type
27706 * @name  select.SelectController
27707 * @description
27708 * The controller for the `<select>` directive. This provides support for reading
27709 * and writing the selected value(s) of the control and also coordinates dynamically
27710 * added `<option>` elements, perhaps by an `ngRepeat` directive.
27711 */
27712var SelectController =
27713        ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
27714
27715  var self = this,
27716      optionsMap = new HashMap();
27717
27718  // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
27719  self.ngModelCtrl = noopNgModelController;
27720
27721  // The "unknown" option is one that is prepended to the list if the viewValue
27722  // does not match any of the options. When it is rendered the value of the unknown
27723  // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
27724  //
27725  // We can't just jqLite('<option>') since jqLite is not smart enough
27726  // to create it in <select> and IE barfs otherwise.
27727  self.unknownOption = jqLite(document.createElement('option'));
27728  self.renderUnknownOption = function(val) {
27729    var unknownVal = '? ' + hashKey(val) + ' ?';
27730    self.unknownOption.val(unknownVal);
27731    $element.prepend(self.unknownOption);
27732    $element.val(unknownVal);
27733  };
27734
27735  $scope.$on('$destroy', function() {
27736    // disable unknown option so that we don't do work when the whole select is being destroyed
27737    self.renderUnknownOption = noop;
27738  });
27739
27740  self.removeUnknownOption = function() {
27741    if (self.unknownOption.parent()) self.unknownOption.remove();
27742  };
27743
27744
27745  // Read the value of the select control, the implementation of this changes depending
27746  // upon whether the select can have multiple values and whether ngOptions is at work.
27747  self.readValue = function readSingleValue() {
27748    self.removeUnknownOption();
27749    return $element.val();
27750  };
27751
27752
27753  // Write the value to the select control, the implementation of this changes depending
27754  // upon whether the select can have multiple values and whether ngOptions is at work.
27755  self.writeValue = function writeSingleValue(value) {
27756    if (self.hasOption(value)) {
27757      self.removeUnknownOption();
27758      $element.val(value);
27759      if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
27760    } else {
27761      if (value == null && self.emptyOption) {
27762        self.removeUnknownOption();
27763        $element.val('');
27764      } else {
27765        self.renderUnknownOption(value);
27766      }
27767    }
27768  };
27769
27770
27771  // Tell the select control that an option, with the given value, has been added
27772  self.addOption = function(value, element) {
27773    assertNotHasOwnProperty(value, '"option value"');
27774    if (value === '') {
27775      self.emptyOption = element;
27776    }
27777    var count = optionsMap.get(value) || 0;
27778    optionsMap.put(value, count + 1);
27779  };
27780
27781  // Tell the select control that an option, with the given value, has been removed
27782  self.removeOption = function(value) {
27783    var count = optionsMap.get(value);
27784    if (count) {
27785      if (count === 1) {
27786        optionsMap.remove(value);
27787        if (value === '') {
27788          self.emptyOption = undefined;
27789        }
27790      } else {
27791        optionsMap.put(value, count - 1);
27792      }
27793    }
27794  };
27795
27796  // Check whether the select control has an option matching the given value
27797  self.hasOption = function(value) {
27798    return !!optionsMap.get(value);
27799  };
27800}];
27801
27802/**
27803 * @ngdoc directive
27804 * @name select
27805 * @restrict E
27806 *
27807 * @description
27808 * HTML `SELECT` element with angular data-binding.
27809 *
27810 * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
27811 * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits such as reducing
27812 * memory and increasing speed by not creating a new scope for each repeated instance, as well as providing
27813 * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
27814 * comprehension expression.
27815 *
27816 * When an item in the `<select>` menu is selected, the array element or object property
27817 * represented by the selected option will be bound to the model identified by the `ngModel`
27818 * directive.
27819 *
27820 * If the viewValue contains a value that doesn't match any of the options then the control
27821 * will automatically add an "unknown" option, which it then removes when this is resolved.
27822 *
27823 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
27824 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
27825 * option. See example below for demonstration.
27826 *
27827 * <div class="alert alert-info">
27828 * The value of a `select` directive used without `ngOptions` is always a string.
27829 * When the model needs to be bound to a non-string value, you must either explictly convert it
27830 * using a directive (see example below) or use `ngOptions` to specify the set of options.
27831 * This is because an option element can only be bound to string values at present.
27832 * </div>
27833 *
27834 * ### Example (binding `select` to a non-string value)
27835 *
27836 * <example name="select-with-non-string-options" module="nonStringSelect">
27837 *   <file name="index.html">
27838 *     <select ng-model="model.id" convert-to-number>
27839 *       <option value="0">Zero</option>
27840 *       <option value="1">One</option>
27841 *       <option value="2">Two</option>
27842 *     </select>
27843 *     {{ model }}
27844 *   </file>
27845 *   <file name="app.js">
27846 *     angular.module('nonStringSelect', [])
27847 *       .run(function($rootScope) {
27848 *         $rootScope.model = { id: 2 };
27849 *       })
27850 *       .directive('convertToNumber', function() {
27851 *         return {
27852 *           require: 'ngModel',
27853 *           link: function(scope, element, attrs, ngModel) {
27854 *             ngModel.$parsers.push(function(val) {
27855 *               return parseInt(val, 10);
27856 *             });
27857 *             ngModel.$formatters.push(function(val) {
27858 *               return '' + val;
27859 *             });
27860 *           }
27861 *         };
27862 *       });
27863 *   </file>
27864 *   <file name="protractor.js" type="protractor">
27865 *     it('should initialize to model', function() {
27866 *       var select = element(by.css('select'));
27867 *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
27868 *     });
27869 *   </file>
27870 * </example>
27871 *
27872 */
27873var selectDirective = function() {
27874
27875  return {
27876    restrict: 'E',
27877    require: ['select', '?ngModel'],
27878    controller: SelectController,
27879    link: function(scope, element, attr, ctrls) {
27880
27881      // if ngModel is not defined, we don't need to do anything
27882      var ngModelCtrl = ctrls[1];
27883      if (!ngModelCtrl) return;
27884
27885      var selectCtrl = ctrls[0];
27886
27887      selectCtrl.ngModelCtrl = ngModelCtrl;
27888
27889      // We delegate rendering to the `writeValue` method, which can be changed
27890      // if the select can have multiple selected values or if the options are being
27891      // generated by `ngOptions`
27892      ngModelCtrl.$render = function() {
27893        selectCtrl.writeValue(ngModelCtrl.$viewValue);
27894      };
27895
27896      // When the selected item(s) changes we delegate getting the value of the select control
27897      // to the `readValue` method, which can be changed if the select can have multiple
27898      // selected values or if the options are being generated by `ngOptions`
27899      element.on('change', function() {
27900        scope.$apply(function() {
27901          ngModelCtrl.$setViewValue(selectCtrl.readValue());
27902        });
27903      });
27904
27905      // If the select allows multiple values then we need to modify how we read and write
27906      // values from and to the control; also what it means for the value to be empty and
27907      // we have to add an extra watch since ngModel doesn't work well with arrays - it
27908      // doesn't trigger rendering if only an item in the array changes.
27909      if (attr.multiple) {
27910
27911        // Read value now needs to check each option to see if it is selected
27912        selectCtrl.readValue = function readMultipleValue() {
27913          var array = [];
27914          forEach(element.find('option'), function(option) {
27915            if (option.selected) {
27916              array.push(option.value);
27917            }
27918          });
27919          return array;
27920        };
27921
27922        // Write value now needs to set the selected property of each matching option
27923        selectCtrl.writeValue = function writeMultipleValue(value) {
27924          var items = new HashMap(value);
27925          forEach(element.find('option'), function(option) {
27926            option.selected = isDefined(items.get(option.value));
27927          });
27928        };
27929
27930        // we have to do it on each watch since ngModel watches reference, but
27931        // we need to work of an array, so we need to see if anything was inserted/removed
27932        var lastView, lastViewRef = NaN;
27933        scope.$watch(function selectMultipleWatch() {
27934          if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
27935            lastView = shallowCopy(ngModelCtrl.$viewValue);
27936            ngModelCtrl.$render();
27937          }
27938          lastViewRef = ngModelCtrl.$viewValue;
27939        });
27940
27941        // If we are a multiple select then value is now a collection
27942        // so the meaning of $isEmpty changes
27943        ngModelCtrl.$isEmpty = function(value) {
27944          return !value || value.length === 0;
27945        };
27946
27947      }
27948    }
27949  };
27950};
27951
27952
27953// The option directive is purely designed to communicate the existence (or lack of)
27954// of dynamically created (and destroyed) option elements to their containing select
27955// directive via its controller.
27956var optionDirective = ['$interpolate', function($interpolate) {
27957
27958  function chromeHack(optionElement) {
27959    // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
27960    // Adding an <option selected="selected"> element to a <select required="required"> should
27961    // automatically select the new element
27962    if (optionElement[0].hasAttribute('selected')) {
27963      optionElement[0].selected = true;
27964    }
27965  }
27966
27967  return {
27968    restrict: 'E',
27969    priority: 100,
27970    compile: function(element, attr) {
27971
27972      // If the value attribute is not defined then we fall back to the
27973      // text content of the option element, which may be interpolated
27974      if (isUndefined(attr.value)) {
27975        var interpolateFn = $interpolate(element.text(), true);
27976        if (!interpolateFn) {
27977          attr.$set('value', element.text());
27978        }
27979      }
27980
27981      return function(scope, element, attr) {
27982
27983        // This is an optimization over using ^^ since we don't want to have to search
27984        // all the way to the root of the DOM for every single option element
27985        var selectCtrlName = '$selectController',
27986            parent = element.parent(),
27987            selectCtrl = parent.data(selectCtrlName) ||
27988              parent.parent().data(selectCtrlName); // in case we are in optgroup
27989
27990        // Only update trigger option updates if this is an option within a `select`
27991        // that also has `ngModel` attached
27992        if (selectCtrl && selectCtrl.ngModelCtrl) {
27993
27994          if (interpolateFn) {
27995            scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
27996              attr.$set('value', newVal);
27997              if (oldVal !== newVal) {
27998                selectCtrl.removeOption(oldVal);
27999              }
28000              selectCtrl.addOption(newVal, element);
28001              selectCtrl.ngModelCtrl.$render();
28002              chromeHack(element);
28003            });
28004          } else {
28005            selectCtrl.addOption(attr.value, element);
28006            selectCtrl.ngModelCtrl.$render();
28007            chromeHack(element);
28008          }
28009
28010          element.on('$destroy', function() {
28011            selectCtrl.removeOption(attr.value);
28012            selectCtrl.ngModelCtrl.$render();
28013          });
28014        }
28015      };
28016    }
28017  };
28018}];
28019
28020var styleDirective = valueFn({
28021  restrict: 'E',
28022  terminal: false
28023});
28024
28025var requiredDirective = function() {
28026  return {
28027    restrict: 'A',
28028    require: '?ngModel',
28029    link: function(scope, elm, attr, ctrl) {
28030      if (!ctrl) return;
28031      attr.required = true; // force truthy in case we are on non input element
28032
28033      ctrl.$validators.required = function(modelValue, viewValue) {
28034        return !attr.required || !ctrl.$isEmpty(viewValue);
28035      };
28036
28037      attr.$observe('required', function() {
28038        ctrl.$validate();
28039      });
28040    }
28041  };
28042};
28043
28044
28045var patternDirective = function() {
28046  return {
28047    restrict: 'A',
28048    require: '?ngModel',
28049    link: function(scope, elm, attr, ctrl) {
28050      if (!ctrl) return;
28051
28052      var regexp, patternExp = attr.ngPattern || attr.pattern;
28053      attr.$observe('pattern', function(regex) {
28054        if (isString(regex) && regex.length > 0) {
28055          regex = new RegExp('^' + regex + '$');
28056        }
28057
28058        if (regex && !regex.test) {
28059          throw minErr('ngPattern')('noregexp',
28060            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
28061            regex, startingTag(elm));
28062        }
28063
28064        regexp = regex || undefined;
28065        ctrl.$validate();
28066      });
28067
28068      ctrl.$validators.pattern = function(value) {
28069        return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
28070      };
28071    }
28072  };
28073};
28074
28075
28076var maxlengthDirective = function() {
28077  return {
28078    restrict: 'A',
28079    require: '?ngModel',
28080    link: function(scope, elm, attr, ctrl) {
28081      if (!ctrl) return;
28082
28083      var maxlength = -1;
28084      attr.$observe('maxlength', function(value) {
28085        var intVal = toInt(value);
28086        maxlength = isNaN(intVal) ? -1 : intVal;
28087        ctrl.$validate();
28088      });
28089      ctrl.$validators.maxlength = function(modelValue, viewValue) {
28090        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
28091      };
28092    }
28093  };
28094};
28095
28096var minlengthDirective = function() {
28097  return {
28098    restrict: 'A',
28099    require: '?ngModel',
28100    link: function(scope, elm, attr, ctrl) {
28101      if (!ctrl) return;
28102
28103      var minlength = 0;
28104      attr.$observe('minlength', function(value) {
28105        minlength = toInt(value) || 0;
28106        ctrl.$validate();
28107      });
28108      ctrl.$validators.minlength = function(modelValue, viewValue) {
28109        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
28110      };
28111    }
28112  };
28113};
28114
28115  if (window.angular.bootstrap) {
28116    //AngularJS is already loaded, so we can return here...
28117    console.log('WARNING: Tried to load angular more than once.');
28118    return;
28119  }
28120
28121  //try to bind to jquery now so that one can write jqLite(document).ready()
28122  //but we will rebind on bootstrap again.
28123  bindJQuery();
28124
28125  publishExternalAPI(angular);
28126
28127  jqLite(document).ready(function() {
28128    angularInit(document, bootstrap);
28129  });
28130
28131})(window, document);
28132
28133!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;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</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.