PageSourceSearch

https://deepamtravels.com/scripts/angular1.js?760

js deepamtravels.com collected 2026-10-02 01:27:18 UTC 623,914 bytes, 17,902 lines download raw bytes

1/**
2 * @license AngularJS v1.2.0rc1
3 * (c) 2010-2012 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window, document, undefined) {'use strict';
7
8/**
9 * @description
10 *
11 * This object provides a utility for producing rich Error messages within
12 * Angular. It can be called as follows:
13 *
14 * var exampleMinErr = minErr('example');
15 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16 *
17 * The above creates an instance of minErr in the example namespace. The
18 * resulting error will have a namespaced error code of example.one.  The
19 * resulting error will replace {0} with the value of foo, and {1} with the
20 * value of bar. The object is not restricted in the number of arguments it can
21 * take.
22 *
23 * If fewer arguments are specified than necessary for interpolation, the extra
24 * interpolation markers will be preserved in the final string.
25 *
26 * Since data will be parsed statically during a build step, some restrictions
27 * are applied with respect to how minErr instances are created and called.
28 * Instances should have names of the form namespaceMinErr for a minErr created
29 * using minErr('namespace') . Error codes, namespaces and template strings
30 * should all be static strings, not variables or general expressions.
31 *
32 * @param {string} module The namespace to use for the new minErr instance.
33 * @returns {function(string, string, ...): Error} instance
34 */
35
36function minErr(module) {
37  return function () {
38    var prefix = '[' + (module ? module + ':' : '') + arguments[0] + '] ',
39      template = arguments[1],
40      templateArgs = arguments,
41      message;
42
43    message = prefix + template.replace(/\{\d+\}/g, function (match) {
44      var index = +match.slice(1, -1), arg;
45
46      if (index + 2 < templateArgs.length) {
47        arg = templateArgs[index + 2];
48        if (isFunction(arg)) {
49          return arg.toString().replace(/ ?\{[\s\S]*$/, '');
50        } else if (isUndefined(arg)) {
51          return 'undefined';
52        } else if (!isString(arg)) {
53          return toJson(arg);
54        }
55        return arg;
56      }
57      return match;
58    });
59
60    return new Error(message);
61  };
62}
63
64////////////////////////////////////
65
66/**
67 * hasOwnProperty may be overwritten by a property of the same name, or entirely
68 * absent from an object that does not inherit Object.prototype; this copy is
69 * used instead
70 */
71var hasOwnPropertyFn = Object.prototype.hasOwnProperty;
72var hasOwnPropertyLocal = function(obj, key) {
73  return hasOwnPropertyFn.call(obj, key);
74};
75
76/**
77 * @ngdoc function
78 * @name angular.lowercase
79 * @function
80 *
81 * @description Converts the specified string to lowercase.
82 * @param {string} string String to be converted to lowercase.
83 * @returns {string} Lowercased string.
84 */
85var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
86
87
88/**
89 * @ngdoc function
90 * @name angular.uppercase
91 * @function
92 *
93 * @description Converts the specified string to uppercase.
94 * @param {string} string String to be converted to uppercase.
95 * @returns {string} Uppercased string.
96 */
97var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
98
99
100var manualLowercase = function(s) {
101  return isString(s)
102      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
103      : s;
104};
105var manualUppercase = function(s) {
106  return isString(s)
107      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
108      : s;
109};
110
111
112// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
113// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
114// with correct but slower alternatives.
115if ('i' !== 'I'.toLowerCase()) {
116  lowercase = manualLowercase;
117  uppercase = manualUppercase;
118}
119
120
121var /** holds major version number for IE or NaN for real browsers */
122    msie              = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
123    jqLite,           // delay binding since jQuery could be loaded after us.
124    jQuery,           // delay binding
125    slice             = [].slice,
126    push              = [].push,
127    toString          = Object.prototype.toString,
128    ngMinErr          = minErr('ng'),
129
130
131    _angular          = window.angular,
132    /** @name angular */
133    angular           = window.angular || (window.angular = {}),
134    angularModule,
135    nodeName_,
136    uid               = ['0', '0', '0'];
137
138/**
139 * @private
140 * @param {*} obj
141 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
142 */
143function isArrayLike(obj) {
144  if (obj == null || isWindow(obj)) {
145    return false;
146  }
147  
148  var length = obj.length;
149
150  if (obj.nodeType === 1 && length) {
151    return true;
152  }
153
154  return isArray(obj) || !isFunction(obj) && (
155    length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj
156  );
157}
158
159/**
160 * @ngdoc function
161 * @name angular.forEach
162 * @function
163 *
164 * @description
165 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
166 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
167 * is the value of an object property or an array element and `key` is the object property key or
168 * array element index. Specifying a `context` for the function is optional.
169 *
170 * Note: this function was previously known as `angular.foreach`.
171 *
172   <pre>
173     var values = {name: 'misko', gender: 'male'};
174     var log = [];
175     angular.forEach(values, function(value, key){
176       this.push(key + ': ' + value);
177     }, log);
178     expect(log).toEqual(['name: misko', 'gender:male']);
179   </pre>
180 *
181 * @param {Object|Array} obj Object to iterate over.
182 * @param {Function} iterator Iterator function.
183 * @param {Object=} context Object to become context (`this`) for the iterator function.
184 * @returns {Object|Array} Reference to `obj`.
185 */
186function forEach(obj, iterator, context) {
187  var key;
188  if (obj) {
189    if (isFunction(obj)){
190      for (key in obj) {
191        if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
192          iterator.call(context, obj[key], key);
193        }
194      }
195    } else if (obj.forEach && obj.forEach !== forEach) {
196      obj.forEach(iterator, context);
197    } else if (isArrayLike(obj)) {
198      for (key = 0; key < obj.length; key++)
199        iterator.call(context, obj[key], key);
200    } else {
201      for (key in obj) {
202        if (obj.hasOwnProperty(key)) {
203          iterator.call(context, obj[key], key);
204        }
205      }
206    }
207  }
208  return obj;
209}
210
211function sortedKeys(obj) {
212  var keys = [];
213  for (var key in obj) {
214    if (obj.hasOwnProperty(key)) {
215      keys.push(key);
216    }
217  }
218  return keys.sort();
219}
220
221function forEachSorted(obj, iterator, context) {
222  var keys = sortedKeys(obj);
223  for ( var i = 0; i < keys.length; i++) {
224    iterator.call(context, obj[keys[i]], keys[i]);
225  }
226  return keys;
227}
228
229
230/**
231 * when using forEach the params are value, key, but it is often useful to have key, value.
232 * @param {function(string, *)} iteratorFn
233 * @returns {function(*, string)}
234 */
235function reverseParams(iteratorFn) {
236  return function(value, key) { iteratorFn(key, value) };
237}
238
239/**
240 * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
241 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
242 * the number string gets longer over time, and it can also overflow, where as the nextId
243 * will grow much slower, it is a string, and it will never overflow.
244 *
245 * @returns an unique alpha-numeric string
246 */
247function nextUid() {
248  var index = uid.length;
249  var digit;
250
251  while(index) {
252    index--;
253    digit = uid[index].charCodeAt(0);
254    if (digit == 57 /*'9'*/) {
255      uid[index] = 'A';
256      return uid.join('');
257    }
258    if (digit == 90  /*'Z'*/) {
259      uid[index] = '0';
260    } else {
261      uid[index] = String.fromCharCode(digit + 1);
262      return uid.join('');
263    }
264  }
265  uid.unshift('0');
266  return uid.join('');
267}
268
269
270/**
271 * Set or clear the hashkey for an object.
272 * @param obj object
273 * @param h the hashkey (!truthy to delete the hashkey)
274 */
275function setHashKey(obj, h) {
276  if (h) {
277    obj.$$hashKey = h;
278  }
279  else {
280    delete obj.$$hashKey;
281  }
282}
283
284/**
285 * @ngdoc function
286 * @name angular.extend
287 * @function
288 *
289 * @description
290 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
291 * to `dst`. You can specify multiple `src` objects.
292 *
293 * @param {Object} dst Destination object.
294 * @param {...Object} src Source object(s).
295 * @returns {Object} Reference to `dst`.
296 */
297function extend(dst) {
298  var h = dst.$$hashKey;
299  forEach(arguments, function(obj){
300    if (obj !== dst) {
301      forEach(obj, function(value, key){
302        dst[key] = value;
303      });
304    }
305  });
306
307  setHashKey(dst,h);
308  return dst;
309}
310
311function int(str) {
312  return parseInt(str, 10);
313}
314
315
316function inherit(parent, extra) {
317  return extend(new (extend(function() {}, {prototype:parent}))(), extra);
318}
319
320/**
321 * @ngdoc function
322 * @name angular.noop
323 * @function
324 *
325 * @description
326 * A function that performs no operations. This function can be useful when writing code in the
327 * functional style.
328   <pre>
329     function foo(callback) {
330       var result = calculateResult();
331       (callback || angular.noop)(result);
332     }
333   </pre>
334 */
335function noop() {}
336noop.$inject = [];
337
338
339/**
340 * @ngdoc function
341 * @name angular.identity
342 * @function
343 *
344 * @description
345 * A function that returns its first argument. This function is useful when writing code in the
346 * functional style.
347 *
348   <pre>
349     function transformer(transformationFn, value) {
350       return (transformationFn || angular.identity)(value);
351     };
352   </pre>
353 */
354function identity($) {return $;}
355identity.$inject = [];
356
357
358function valueFn(value) {return function() {return value;};}
359
360/**
361 * @ngdoc function
362 * @name angular.isUndefined
363 * @function
364 *
365 * @description
366 * Determines if a reference is undefined.
367 *
368 * @param {*} value Reference to check.
369 * @returns {boolean} True if `value` is undefined.
370 */
371function isUndefined(value){return typeof value == 'undefined';}
372
373
374/**
375 * @ngdoc function
376 * @name angular.isDefined
377 * @function
378 *
379 * @description
380 * Determines if a reference is defined.
381 *
382 * @param {*} value Reference to check.
383 * @returns {boolean} True if `value` is defined.
384 */
385function isDefined(value){return typeof value != 'undefined';}
386
387
388/**
389 * @ngdoc function
390 * @name angular.isObject
391 * @function
392 *
393 * @description
394 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
395 * considered to be objects.
396 *
397 * @param {*} value Reference to check.
398 * @returns {boolean} True if `value` is an `Object` but not `null`.
399 */
400function isObject(value){return value != null && typeof value == 'object';}
401
402
403/**
404 * @ngdoc function
405 * @name angular.isString
406 * @function
407 *
408 * @description
409 * Determines if a reference is a `String`.
410 *
411 * @param {*} value Reference to check.
412 * @returns {boolean} True if `value` is a `String`.
413 */
414function isString(value){return typeof value == 'string';}
415
416
417/**
418 * @ngdoc function
419 * @name angular.isNumber
420 * @function
421 *
422 * @description
423 * Determines if a reference is a `Number`.
424 *
425 * @param {*} value Reference to check.
426 * @returns {boolean} True if `value` is a `Number`.
427 */
428function isNumber(value){return typeof value == 'number';}
429
430
431/**
432 * @ngdoc function
433 * @name angular.isDate
434 * @function
435 *
436 * @description
437 * Determines if a value is a date.
438 *
439 * @param {*} value Reference to check.
440 * @returns {boolean} True if `value` is a `Date`.
441 */
442function isDate(value){
443  return toString.apply(value) == '[object Date]';
444}
445
446
447/**
448 * @ngdoc function
449 * @name angular.isArray
450 * @function
451 *
452 * @description
453 * Determines if a reference is an `Array`.
454 *
455 * @param {*} value Reference to check.
456 * @returns {boolean} True if `value` is an `Array`.
457 */
458function isArray(value) {
459  return toString.apply(value) == '[object Array]';
460}
461
462
463/**
464 * @ngdoc function
465 * @name angular.isFunction
466 * @function
467 *
468 * @description
469 * Determines if a reference is a `Function`.
470 *
471 * @param {*} value Reference to check.
472 * @returns {boolean} True if `value` is a `Function`.
473 */
474function isFunction(value){return typeof value == 'function';}
475
476
477/**
478 * Determines if a value is a regular expression object.
479 *
480 * @private
481 * @param {*} value Reference to check.
482 * @returns {boolean} True if `value` is a `RegExp`.
483 */
484function isRegExp(value) {
485  return toString.apply(value) == '[object RegExp]';
486}
487
488
489/**
490 * Checks if `obj` is a window object.
491 *
492 * @private
493 * @param {*} obj Object to check
494 * @returns {boolean} True if `obj` is a window obj.
495 */
496function isWindow(obj) {
497  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
498}
499
500
501function isScope(obj) {
502  return obj && obj.$evalAsync && obj.$watch;
503}
504
505
506function isFile(obj) {
507  return toString.apply(obj) === '[object File]';
508}
509
510
511function isBoolean(value) {
512  return typeof value == 'boolean';
513}
514
515
516var trim = (function() {
517  // native trim is way faster: http://jsperf.com/angular-trim-test
518  // but IE doesn't have it... :-(
519  // TODO: we should move this into IE/ES5 polyfill
520  if (!String.prototype.trim) {
521    return function(value) {
522      return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
523    };
524  }
525  return function(value) {
526    return isString(value) ? value.trim() : value;
527  };
528})();
529
530
531/**
532 * @ngdoc function
533 * @name angular.isElement
534 * @function
535 *
536 * @description
537 * Determines if a reference is a DOM element (or wrapped jQuery element).
538 *
539 * @param {*} value Reference to check.
540 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
541 */
542function isElement(node) {
543  return node &&
544    (node.nodeName  // we are a direct element
545    || (node.on && node.find));  // we have an on and find method part of jQuery API
546}
547
548/**
549 * @param str 'key1,key2,...'
550 * @returns {object} in the form of {key1:true, key2:true, ...}
551 */
552function makeMap(str){
553  var obj = {}, items = str.split(","), i;
554  for ( i = 0; i < items.length; i++ )
555    obj[ items[i] ] = true;
556  return obj;
557}
558
559
560if (msie < 9) {
561  nodeName_ = function(element) {
562    element = element.nodeName ? element : element[0];
563    return (element.scopeName && element.scopeName != 'HTML')
564      ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
565  };
566} else {
567  nodeName_ = function(element) {
568    return element.nodeName ? element.nodeName : element[0].nodeName;
569  };
570}
571
572
573function map(obj, iterator, context) {
574  var results = [];
575  forEach(obj, function(value, index, list) {
576    results.push(iterator.call(context, value, index, list));
577  });
578  return results;
579}
580
581
582/**
583 * @description
584 * Determines the number of elements in an array, the number of properties an object has, or
585 * the length of a string.
586 *
587 * Note: This function is used to augment the Object type in Angular expressions. See
588 * {@link angular.Object} for more information about Angular arrays.
589 *
590 * @param {Object|Array|string} obj Object, array, or string to inspect.
591 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
592 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
593 */
594function size(obj, ownPropsOnly) {
595  var size = 0, key;
596
597  if (isArray(obj) || isString(obj)) {
598    return obj.length;
599  } else if (isObject(obj)){
600    for (key in obj)
601      if (!ownPropsOnly || obj.hasOwnProperty(key))
602        size++;
603  }
604
605  return size;
606}
607
608
609function includes(array, obj) {
610  return indexOf(array, obj) != -1;
611}
612
613function indexOf(array, obj) {
614  if (array.indexOf) return array.indexOf(obj);
615
616  for ( var i = 0; i < array.length; i++) {
617    if (obj === array[i]) return i;
618  }
619  return -1;
620}
621
622function arrayRemove(array, value) {
623  var index = indexOf(array, value);
624  if (index >=0)
625    array.splice(index, 1);
626  return value;
627}
628
629function isLeafNode (node) {
630  if (node) {
631    switch (node.nodeName) {
632    case "OPTION":
633    case "PRE":
634    case "TITLE":
635      return true;
636    }
637  }
638  return false;
639}
640
641/**
642 * @ngdoc function
643 * @name angular.copy
644 * @function
645 *
646 * @description
647 * Creates a deep copy of `source`, which should be an object or an array.
648 *
649 * * If no destination is supplied, a copy of the object or array is created.
650 * * If a destination is provided, all of its elements (for array) or properties (for objects)
651 *   are deleted and then all elements/properties from the source are copied to it.
652 * * If  `source` is not an object or array, `source` is returned.
653 *
654 * Note: this function is used to augment the Object type in Angular expressions. See
655 * {@link ng.$filter} for more information about Angular arrays.
656 *
657 * @param {*} source The source that will be used to make a copy.
658 *                   Can be any type, including primitives, `null`, and `undefined`.
659 * @param {(Object|Array)=} destination Destination into which the source is copied. If
660 *     provided, must be of the same type as `source`.
661 * @returns {*} The copy or updated `destination`, if `destination` was specified.
662 */
663function copy(source, destination){
664  if (isWindow(source) || isScope(source)) {
665    throw ngMinErr('cpws', "Can't copy! Making copies of Window or Scope instances is not supported.");
666  }
667
668  if (!destination) {
669    destination = source;
670    if (source) {
671      if (isArray(source)) {
672        destination = copy(source, []);
673      } else if (isDate(source)) {
674        destination = new Date(source.getTime());
675      } else if (isRegExp(source)) {
676        destination = new RegExp(source.source);
677      } else if (isObject(source)) {
678        destination = copy(source, {});
679      }
680    }
681  } else {
682    if (source === destination) throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
683    if (isArray(source)) {
684      destination.length = 0;
685      for ( var i = 0; i < source.length; i++) {
686        destination.push(copy(source[i]));
687      }
688    } else {
689      var h = destination.$$hashKey;
690      forEach(destination, function(value, key){
691        delete destination[key];
692      });
693      for ( var key in source) {
694        destination[key] = copy(source[key]);
695      }
696      setHashKey(destination,h);
697    }
698  }
699  return destination;
700}
701
702/**
703 * Create a shallow copy of an object
704 */
705function shallowCopy(src, dst) {
706  dst = dst || {};
707
708  for(var key in src) {
709    if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
710      dst[key] = src[key];
711    }
712  }
713
714  return dst;
715}
716
717
718/**
719 * @ngdoc function
720 * @name angular.equals
721 * @function
722 *
723 * @description
724 * Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and
725 * objects.
726 *
727 * Two objects or values are considered equivalent if at least one of the following is true:
728 *
729 * * Both objects or values pass `===` comparison.
730 * * Both objects or values are of the same type and all of their properties pass `===` comparison.
731 * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
732 * * Both values represent the same regular expression (In JavasScript,
733 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
734 *   representation matches).
735 *
736 * During a property comparison, properties of `function` type and properties with names
737 * that begin with `$` are ignored.
738 *
739 * Scope and DOMWindow objects are being compared only by identify (`===`).
740 *
741 * @param {*} o1 Object or value to compare.
742 * @param {*} o2 Object or value to compare.
743 * @returns {boolean} True if arguments are equal.
744 */
745function equals(o1, o2) {
746  if (o1 === o2) return true;
747  if (o1 === null || o2 === null) return false;
748  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
749  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
750  if (t1 == t2) {
751    if (t1 == 'object') {
752      if (isArray(o1)) {
753        if (!isArray(o2)) return false;
754        if ((length = o1.length) == o2.length) {
755          for(key=0; key<length; key++) {
756            if (!equals(o1[key], o2[key])) return false;
757          }
758          return true;
759        }
760      } else if (isDate(o1)) {
761        return isDate(o2) && o1.getTime() == o2.getTime();
762      } else if (isRegExp(o1) && isRegExp(o2)) {
763        return o1.toString() == o2.toString();
764      } else {
765        if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
766        keySet = {};
767        for(key in o1) {
768          if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
769          if (!equals(o1[key], o2[key])) return false;
770          keySet[key] = true;
771        }
772        for(key in o2) {
773          if (!keySet.hasOwnProperty(key) &&
774              key.charAt(0) !== '$' &&
775              o2[key] !== undefined &&
776              !isFunction(o2[key])) return false;
777        }
778        return true;
779      }
780    }
781  }
782  return false;
783}
784
785
786function concat(array1, array2, index) {
787  return array1.concat(slice.call(array2, index));
788}
789
790function sliceArgs(args, startIndex) {
791  return slice.call(args, startIndex || 0);
792}
793
794
795/**
796 * @ngdoc function
797 * @name angular.bind
798 * @function
799 *
800 * @description
801 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
802 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
803 * known as [function currying](http://en.wikipedia.org/wiki/Currying).
804 *
805 * @param {Object} self Context which `fn` should be evaluated in.
806 * @param {function()} fn Function to be bound.
807 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
808 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
809 */
810function bind(self, fn) {
811  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
812  if (isFunction(fn) && !(fn instanceof RegExp)) {
813    return curryArgs.length
814      ? function() {
815          return arguments.length
816            ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
817            : fn.apply(self, curryArgs);
818        }
819      : function() {
820          return arguments.length
821            ? fn.apply(self, arguments)
822            : fn.call(self);
823        };
824  } else {
825    // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
826    return fn;
827  }
828}
829
830
831function toJsonReplacer(key, value) {
832  var val = value;
833
834  if (/^\$+/.test(key)) {
835    val = undefined;
836  } else if (isWindow(value)) {
837    val = '$WINDOW';
838  } else if (value &&  document === value) {
839    val = '$DOCUMENT';
840  } else if (isScope(value)) {
841    val = '$SCOPE';
842  }
843
844  return val;
845}
846
847
848/**
849 * @ngdoc function
850 * @name angular.toJson
851 * @function
852 *
853 * @description
854 * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
855 * stripped since angular uses this notation internally.
856 *
857 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
858 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
859 * @returns {string|undefined} JSON-ified string representing `obj`.
860 */
861function toJson(obj, pretty) {
862  if (typeof obj === 'undefined') return undefined;
863  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
864}
865
866
867/**
868 * @ngdoc function
869 * @name angular.fromJson
870 * @function
871 *
872 * @description
873 * Deserializes a JSON string.
874 *
875 * @param {string}
875 json JSON string to deserialize.
876 * @returns {Object|Array|Date|string|number} Deserialized thingy.
877 */
878function fromJson(json) {
879  return isString(json)
880      ? JSON.parse(json)
881      : json;
882}
883
884
885function toBoolean(value) {
886  if (value && value.length !== 0) {
887    var v = lowercase("" + value);
888    value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
889  } else {
890    value = false;
891  }
892  return value;
893}
894
895/**
896 * @returns {string} Returns the string representation of the element.
897 */
898function startingTag(element) {
899  element = jqLite(element).clone();
900  try {
901    // turns out IE does not let you set .html() on elements which
902    // are not allowed to have children. So we just ignore it.
903    element.html('');
904  } catch(e) {}
905  // As Per DOM Standards
906  var TEXT_NODE = 3;
907  var elemHtml = jqLite('<div>').append(element).html();
908  try {
909    return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
910        elemHtml.
911          match(/^(<[^>]+>)/)[1].
912          replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
913  } catch(e) {
914    return lowercase(elemHtml);
915  }
916
917}
918
919
920/////////////////////////////////////////////////
921
922/**
923 * Tries to decode the URI component without throwing an exception.
924 *
925 * @private
926 * @param str value potential URI component to check.
927 * @returns {boolean} True if `value` can be decoded
928 * with the decodeURIComponent function.
929 */
930function tryDecodeURIComponent(value) {
931  try {
932    return decodeURIComponent(value);
933  } catch(e) {
934    // Ignore any invalid uri component
935  }
936}
937
938
939/**
940 * Parses an escaped url query string into key-value pairs.
941 * @returns Object.<(string|boolean)>
942 */
943function parseKeyValue(/**string*/keyValue) {
944  var obj = {}, key_value, key;
945  forEach((keyValue || "").split('&'), function(keyValue){
946    if ( keyValue ) {
947      key_value = keyValue.split('=');
948      key = tryDecodeURIComponent(key_value[0]);
949      if ( isDefined(key) ) {
950        var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
951        if (!obj[key]) {
952          obj[key] = val;
953        } else if(isArray(obj[key])) {
954          obj[key].push(val);
955        } else {
956          obj[key] = [obj[key],val];
957        }
958      }
959    }
960  });
961  return obj;
962}
963
964function toKeyValue(obj) {
965  var parts = [];
966  forEach(obj, function(value, key) {
967    if (isArray(value)) {
968      forEach(value, function(arrayValue) {
969        parts.push(encodeUriQuery(key, true) + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
970      });
971    } else {
972    parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
973    }
974  });
975  return parts.length ? parts.join('&') : '';
976}
977
978
979/**
980 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
981 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
982 * segments:
983 *    segment       = *pchar
984 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
985 *    pct-encoded   = "%" HEXDIG HEXDIG
986 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
987 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
988 *                     / "*" / "+" / "," / ";" / "="
989 */
990function encodeUriSegment(val) {
991  return encodeUriQuery(val, true).
992             replace(/%26/gi, '&').
993             replace(/%3D/gi, '=').
994             replace(/%2B/gi, '+');
995}
996
997
998/**
999 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1000 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1001 * encoded per http://tools.ietf.org/html/rfc3986:
1002 *    query       = *( pchar / "/" / "?" )
1003 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1004 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1005 *    pct-encoded   = "%" HEXDIG HEXDIG
1006 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1007 *                     / "*" / "+" / "," / ";" / "="
1008 */
1009function encodeUriQuery(val, pctEncodeSpaces) {
1010  return encodeURIComponent(val).
1011             replace(/%40/gi, '@').
1012             replace(/%3A/gi, ':').
1013             replace(/%24/g, '$').
1014             replace(/%2C/gi, ',').
1015             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1016}
1017
1018
1019/**
1020 * @ngdoc directive
1021 * @name ng.directive:ngApp
1022 *
1023 * @element ANY
1024 * @param {angular.Module} ngApp an optional application
1025 *   {@link angular.module module} name to load.
1026 *
1027 * @description
1028 *
1029 * Use this directive to auto-bootstrap an application. Only
1030 * one ngApp directive can be used per HTML document. The directive
1031 * designates the root of the application and is typically placed
1032 * at the root of the page.
1033 *
1034 * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
1035 * HTML document you must manually bootstrap them using {@link angular.bootstrap}.
1036 * Applications cannot be nested.
1037 *
1038 * In the example below if the `ngApp` directive would not be placed
1039 * on the `html` element then the document would not be compiled
1040 * and the `{{ 1+2 }}` would not be resolved to `3`.
1041 *
1042 * `ngApp` is the easiest way to bootstrap an application.
1043 *
1044 <doc:example>
1045   <doc:source>
1046    I can add: 1 + 2 =  {{ 1+2 }}
1047   </doc:source>
1048 </doc:example>
1049 *
1050 */
1051function angularInit(element, bootstrap) {
1052  var elements = [element],
1053      appElement,
1054      module,
1055      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1056      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1057
1058  function append(element) {
1059    element && elements.push(element);
1060  }
1061
1062  forEach(names, function(name) {
1063    names[name] = true;
1064    append(document.getElementById(name));
1065    name = name.replace(':', '\\:');
1066    if (element.querySelectorAll) {
1067      forEach(element.querySelectorAll('.' + name), append);
1068      forEach(element.querySelectorAll('.' + name + '\\:'), append);
1069      forEach(element.querySelectorAll('[' + name + ']'), append);
1070    }
1071  });
1072
1073  forEach(elements, function(element) {
1074    if (!appElement) {
1075      var className = ' ' + element.className + ' ';
1076      var match = NG_APP_CLASS_REGEXP.exec(className);
1077      if (match) {
1078        appElement = element;
1079        module = (match[2] || '').replace(/\s+/g, ',');
1080      } else {
1081        forEach(element.attributes, function(attr) {
1082          if (!appElement && names[attr.name]) {
1083            appElement = element;
1084            module = attr.value;
1085          }
1086        });
1087      }
1088    }
1089  });
1090  if (appElement) {
1091    bootstrap(appElement, module ? [module] : []);
1092  }
1093}
1094
1095/**
1096 * @ngdoc function
1097 * @name angular.bootstrap
1098 * @description
1099 * Use this function to manually start up angular application.
1100 *
1101 * See: {@link guide/bootstrap Bootstrap}
1102 *
1103 * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1104 * They must use {@link api/ng.directive:ngApp ngApp}.
1105 *
1106 * @param {Element} element DOM element which is the root of angular application.
1107 * @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
1108 * @returns {AUTO.$injector} Returns the newly created injector for this app.
1109 */
1110function bootstrap(element, modules) {
1111  var doBootstrap = function() {
1112    element = jqLite(element);
1113
1114    if (element.injector()) {
1115      var tag = (element[0] === document) ? 'document' : startingTag(element);
1116      throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1117    }
1118
1119    modules = modules || [];
1120    modules.unshift(['$provide', function($provide) {
1121      $provide.value('$rootElement', element);
1122    }]);
1123    modules.unshift('ng');
1124    var injector = createInjector(modules);
1125    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1126       function(scope, element, compile, injector, animate) {
1127        scope.$apply(function() {
1128          element.data('$injector', injector);
1129          compile(element)(scope);
1130        });
1131        animate.enabled(true);
1132      }]
1133    );
1134    return injector;
1135  };
1136
1137  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1138
1139  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1140    return doBootstrap();
1141  }
1142
1143  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1144  angular.resumeBootstrap = function(extraModules) {
1145    forEach(extraModules, function(module) {
1146      modules.push(module);
1147    });
1148    doBootstrap();
1149  };
1150}
1151
1152var SNAKE_CASE_REGEXP = /[A-Z]/g;
1153function snake_case(name, separator){
1154  separator = separator || '_';
1155  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1156    return (pos ? separator : '') + letter.toLowerCase();
1157  });
1158}
1159
1160function bindJQuery() {
1161  // bind to jQuery if present;
1162  jQuery = window.jQuery;
1163  // reset to jQuery or default to us.
1164  if (jQuery) {
1165    jqLite = jQuery;
1166    extend(jQuery.fn, {
1167      scope: JQLitePrototype.scope,
1168      controller: JQLitePrototype.controller,
1169      injector: JQLitePrototype.injector,
1170      inheritedData: JQLitePrototype.inheritedData
1171    });
1172    // Method signature: JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1173    JQLitePatchJQueryRemove('remove', true, true, false);
1174    JQLitePatchJQueryRemove('empty', false, false, false);
1175    JQLitePatchJQueryRemove('html', false, false, true);
1176  } else {
1177    jqLite = JQLite;
1178  }
1179  angular.element = jqLite;
1180}
1181
1182/**
1183 * throw error if the argument is falsy.
1184 */
1185function assertArg(arg, name, reason) {
1186  if (!arg) {
1187    throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1188  }
1189  return arg;
1190}
1191
1192function assertArgFn(arg, name, acceptArrayAnnotation) {
1193  if (acceptArrayAnnotation && isArray(arg)) {
1194      arg = arg[arg.length - 1];
1195  }
1196
1197  assertArg(isFunction(arg), name, 'not a function, got ' +
1198      (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
1199  return arg;
1200}
1201
1202/**
1203 * Return the value accessible from the object by path. Any undefined traversals are ignored
1204 * @param {Object} obj starting object
1205 * @param {string} path path to traverse
1206 * @param {boolean=true} bindFnToScope
1207 * @returns value as accessible by path
1208 */
1209//TODO(misko): this function needs to be removed
1210function getter(obj, path, bindFnToScope) {
1211  if (!path) return obj;
1212  var keys = path.split('.');
1213  var key;
1214  var lastInstance = obj;
1215  var len = keys.length;
1216
1217  for (var i = 0; i < len; i++) {
1218    key = keys[i];
1219    if (obj) {
1220      obj = (lastInstance = obj)[key];
1221    }
1222  }
1223  if (!bindFnToScope && isFunction(obj)) {
1224    return bind(lastInstance, obj);
1225  }
1226  return obj;
1227}
1228
1229/**
1230 * @ngdoc interface
1231 * @name angular.Module
1232 * @description
1233 *
1234 * Interface for configuring angular {@link angular.module modules}.
1235 */
1236
1237function setupModuleLoader(window) {
1238
1239  function ensure(obj, name, factory) {
1240    return obj[name] || (obj[name] = factory());
1241  }
1242
1243  return ensure(ensure(window, 'angular', Object), 'module', function() {
1244    /** @type {Object.<string, angular.Module>} */
1245    var modules = {};
1246
1247    /**
1248     * @ngdoc function
1249     * @name angular.module
1250     * @description
1251     *
1252     * The `angular.module` is a global place for creating and registering Angular modules. All
1253     * modules (angular core or 3rd party) that should be available to an application must be
1254     * registered using this mechanism.
1255     *
1256     *
1257     * # Module
1258     *
1259     * A module is a collection of services, directives, filters, and configuration information.
1260     * `angular.module` is used to configure the {@link AUTO.$injector $injector}.
1261     *
1262     * <pre>
1263     * // Create a new module
1264     * var myModule = angular.module('myModule', []);
1265     *
1266     * // register a new service
1267     * myModule.value('appName', 'MyCoolApp');
1268     *
1269     * // configure existing services inside initialization blocks.
1270     * myModule.config(function($locationProvider) {
1271     *   // Configure existing providers
1272     *   $locationProvider.hashPrefix('!');
1273     * });
1274     * </pre>
1275     *
1276     * Then you can create an injector and load your modules like this:
1277     *
1278     * <pre>
1279     * var injector = angular.injector(['ng', 'MyModule'])
1280     * </pre>
1281     *
1282     * However it's more likely that you'll just use
1283     * {@link ng.directive:ngApp ngApp} or
1284     * {@link angular.bootstrap} to simplify this process for you.
1285     *
1286     * @param {!string} name The name of the module to create or retrieve.
1287     * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
1288     *        the module is being retrieved for further configuration.
1289     * @param {Function} configFn Optional configuration function for the module. Same as
1290     *        {@link angular.Module#config Module#config()}.
1291     * @returns {module} new module with the {@link angular.Module} api.
1292     */
1293    return function module(name, requires, configFn) {
1294      if (requires && modules.hasOwnProperty(name)) {
1295        modules[name] = null;
1296      }
1297      return ensure(modules, name, function() {
1298        if (!requires) {
1299          throw minErr('$injector')('nomod', "Module '{0}' is not available! You either misspelled the module name " +
1300              "or forgot to load it. If registering a module ensure that you specify the dependencies as the second " +
1301              "argument.", name);
1302        }
1303
1304        /** @type {!Array.<Array.<*>>} */
1305        var invokeQueue = [];
1306
1307        /** @type {!Array.<Function>} */
1308        var runBlocks = [];
1309
1310        var config = invokeLater('$injector', 'invoke');
1311
1312        /** @type {angular.Module} */
1313        var moduleInstance = {
1314          // Private state
1315          _invokeQueue: invokeQueue,
1316          _runBlocks: runBlocks,
1317
1318          /**
1319           * @ngdoc property
1320           * @name angular.Module#requires
1321           * @propertyOf angular.Module
1322           * @returns {Array.<string>} List of module names which must be loaded before this module.
1323           * @description
1324           * Holds the list of modules which the injector will load before the current module is loaded.
1325           */
1326          requires: requires,
1327
1328          /**
1329           * @ngdoc property
1330           * @name angular.Module#name
1331           * @propertyOf angular.Module
1332           * @returns {string} Name of the module.
1333           * @description
1334           */
1335          name: name,
1336
1337
1338          /**
1339           * @ngdoc method
1340           * @name angular.Module#provider
1341           * @methodOf angular.Module
1342           * @param {string} name service name
1343           * @param {Function} providerType Construction function for creating new instance of the service.
1344           * @description
1345           * See {@link AUTO.$provide#provider $provide.provider()}.
1346           */
1347          provider: invokeLater('$provide', 'provider'),
1348
1349          /**
1350           * @ngdoc method
1351           * @name angular.Module#factory
1352           * @methodOf angular.Module
1353           * @param {string} name service name
1354           * @param {Function} providerFunction Function for creating new instance of the service.
1355           * @description
1356           * See {@link AUTO.$provide#factory $provide.factory()}.
1357           */
1358          factory: invokeLater('$provide', 'factory'),
1359
1360          /**
1361           * @ngdoc method
1362           * @name angular.Module#service
1363           * @methodOf angular.Module
1364           * @param {string} name service name
1365           * @param {Function} constructor A constructor function that will be instantiated.
1366           * @description
1367           * See {@link AUTO.$provide#service $provide.service()}.
1368           */
1369          service: invokeLater('$provide', 'service'),
1370
1371          /**
1372           * @ngdoc method
1373           * @name angular.Module#value
1374           * @methodOf angular.Module
1375           * @param {string} name service name
1376           * @param {*} object Service instance object.
1377           * @description
1378           * See {@link AUTO.$provide#value $provide.value()}.
1379           */
1380          value: invokeLater('$provide', 'value'),
1381
1382          /**
1383           * @ngdoc method
1384           * @name angular.Module#constant
1385           * @methodOf angular.Module
1386           * @param {string} name constant name
1387           * @param {*} object Constant value.
1388           * @description
1389           * Because the constant are fixed, they get applied before other provide methods.
1390           * See {@link AUTO.$provide#constant $provide.constant()}.
1391           */
1392          constant: invokeLater('$provide', 'constant', 'unshift'),
1393
1394          /**
1395           * @ngdoc method
1396           * @name angular.Module#animation
1397           * @methodOf angular.Module
1398           * @param {string} name animation name
1399           * @param {Function} animationFactory Factory function for creating new instance of an animation.
1400           * @description
1401           *
1402           * **NOTE**: animations are take effect only if the **ngAnimate** module is loaded.
1403           *
1404           *
1405           * Defines an animation hook that can be later used with {@link ngAnimate.$animate $animate} service and
1406           * directives that use this service.
1407           *
1408           * <pre>
1409           * module.animation('.animation-name', function($inject1, $inject2) {
1410           *   return {
1411           *     eventName : function(element, done) {
1412           *       //code to run the animation
1413           *       //once complete, then run done()
1414           *       return function cancellationFunction(element) {
1415           *         //code to cancel the animation
1416           *       }
1417           *     }
1418           *   }
1419           * })
1420           * </pre>
1421           *
1422           * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1423           * {@link ngAnimate ngAnimate module} for more information.
1424           */
1425          animation: invokeLater('$animateProvider', 'register'),
1426
1427          /**
1428           * @ngdoc method
1429           * @name angular.Module#filter
1430           * @methodOf angular.Module
1431           * @param {string} name Filter name.
1432           * @param {Function} filterFactory Factory function for creating new instance of filter.
1433           * @description
1434           * See {@link ng.$filterProvider#register $filterProvider.register()}.
1435           */
1436          filter: invokeLater('$filterProvider', 'register'),
1437
1438          /**
1439           * @ngdoc method
1440           * @name angular.Module#controller
1441           * @methodOf angular.Module
1442           * @param {string} name Controller name.
1443           * @param {Function} constructor Controller constructor function.
1444           * @description
1445           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1446           */
1447          controller: invokeLater('$controllerProvider', 'register'),
1448
1449          /**
1450           * @ngdoc method
1451           * @name angular.Module#directive
1452           * @methodOf angular.Module
1453           * @param {string} name directive name
1454           * @param {Function} directiveFactory Factory function for creating new instance of
1455           * directives.
1456           * @description
1457           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1458           */
1459          directive: invokeLater('$compileProvider', 'directive'),
1460
1461          /**
1462           * @ngdoc method
1463           * @name angular.Module#config
1464           * @methodOf angular.Module
1465           * @param {Function} configFn Execute this function on module load. Useful for service
1466           *    configuration.
1467           * @description
1468           * Use this method to register work which needs to be performed on module loading.
1469           */
1470          config: config,
1471
1472          /**
1473           * @ngdoc method
1474           * @name angular.Module#run
1475           * @methodOf angular.Module
1476           * @param {Function} initializationFn Execute this function after injector creation.
1477           *    Useful for application initialization.
1478           * @description
1479           * Use this method to register work which should be performed when the injector is done
1480           * loading all modules.
1481           */
1482          run: function(block) {
1483            runBlocks.push(block);
1484            return this;
1485          }
1486        };
1487
1488        if (configFn) {
1489          config(configFn);
1490        }
1491
1492        return  moduleInstance;
1493
1494        /**
1495         * @param {string} provider
1496         * @param {string} method
1497         * @param {String=} insertMethod
1498         * @returns {angular.Module}
1499         */
1500        function invokeLater(provider, method, insertMethod) {
1501          return function() {
1502            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1503            return moduleInstance;
1504          }
1505        }
1506      });
1507    };
1508  });
1509
1510}
1511
1512/**
1513 * @ngdoc property
1514 * @name angular.version
1515 * @description
1516 * An object that contains information about the current AngularJS version. This object has the
1517 * following properties:
1518 *
1519 * - `full` – `{string}` – Full version string, such as "0.9.18".
1520 * - `major` – `{number}` – Major version number, such as "0".
1521 * - `minor` – `{number}` – Minor version number, such as "9".
1522 * - `dot` – `{number}` – Dot version number, such as "18".
1523 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1524 */
1525var version = {
1526  full: '1.2.0rc1',    // all of these placeholder strings will be replaced by grunt's
1527  major: 1,    // package task
1528  minor: 2,
1529  dot: 0,
1530  codeName: 'spooky-giraffe'
1531};
1532
1533
1534function publishExternalAPI(angular){
1535  extend(angular, {
1536    'bootstrap': bootstrap,
1537    'copy': copy,
1538    'extend': extend,
1539    'equals': equals,
1540    'element': jqLite,
1541    'forEach': forEach,
1542    'injector': createInjector,
1543    'noop':noop,
1544    'bind':bind,
1545    'toJson': toJson,
1546    'fromJson': fromJson,
1547    'identity':identity,
1548    'isUndefined': isUndefined,
1549    'isDefined': isDefined,
1550    'isString': isString,
1551    'isFunction': isFunction,
1552    'isObject': isObject,
1553    'isNumber': isNumber,
1554    'isElement': isElement,
1555    'isArray': isArray,
1556    '$$minErr': minErr,
1557    'version': version,
1558    'isDate': isDate,
1559    'lowercase': lowercase,
1560    'uppercase': uppercase,
1561    'callbacks': {counter: 0}
1562  });
1563
1564  angularModule = setupModuleLoader(window);
1565  try {
1566    angularModule('ngLocale');
1567  } catch (e) {
1568    angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
1569  }
1570
1571  angularModule('ng', ['ngLocale'], ['$provide',
1572    function ngModule($provide) {
1573      $provide.provider('$compile', $CompileProvider).
1574        directive({
1575            a: htmlAnchorDirective,
1576            input: inputDirective,
1577            textarea: inputDirective,
1578            form: formDirective,
1579            script: scriptDirective,
1580            select: selectDirective,
1581            style: styleDirective,
1582            option: optionDirective,
1583            ngBind: ngBindDirective,
1584            ngBindHtml: ngBindHtmlDirective,
1585            ngBindTemplate: ngBindTemplateDirective,
1586            ngClass: ngClassDirective,
1587            ngClassEven: ngClassEvenDirective,
1588            ngClassOdd: ngClassOddDirective,
1589            ngCsp: ngCspDirective,
1590            ngCloak: ngCloakDirective,
1591            ngController: ngControllerDirective,
1592            ngForm: ngFormDirective,
1593            ngHide: ngHideDirective,
1594            ngIf: ngIfDirective,
1595            ngInclude: ngIncludeDirective,
1596            ngInit: ngInitDirective,
1597            ngNonBindable: ngNonBindableDirective,
1598            ngPluralize: ngPluralizeDirective,
1599            ngRepeat: ngRepeatDirective,
1600            ngShow: ngShowDirective,
1601            ngStyle: ngStyleDirective,
1602            ngSwitch: ngSwitchDirective,
1603            ngSwitchWhen: ngSwitchWhenDirective,
1604            ngSwitchDefault: ngSwitchDefaultDirective,
1605            ngOptions: ngOptionsDirective,
1606            ngTransclude: ngTranscludeDirective,
1607            ngModel: ngModelDirective,
1608            ngList: ngListDirective,
1609            ngChange: ngChangeDirective,
1610            required: requiredDirective,
1611            ngRequired: requiredDirective,
1612            ngValue: ngValueDirective
1613        }).
1614        directive(ngAttributeAliasDirectives).
1615        directive(ngEventDirectives);
1616      $provide.provider({
1617        $anchorScroll: $AnchorScrollProvider,
1618        $animate: $AnimateProvider,
1619        $browser: $BrowserProvider,
1620        $cacheFactory: $CacheFactoryProvider,
1621        $controller: $ControllerProvider,
1622        $document: $DocumentProvider,
1623        $exceptionHandler: $ExceptionHandlerProvider,
1624        $filter: $FilterProvider,
1625        $interpolate: $InterpolateProvider,
1626        $http: $HttpProvider,
1627        $httpBackend: $HttpBackendProvider,
1628        $location: $LocationProvider,
1629        $log: $LogProvider,
1630        $parse: $ParseProvider,
1631        $rootScope: $RootScopeProvider,
1632        $q: $QProvider,
1633        $sce: $SceProvider,
1634        $sceDelegate: $SceDelegateProvider,
1635        $sniffer: $SnifferProvider,
1636        $templateCache: $TemplateCacheProvider,
1637        $timeout: $TimeoutProvider,
1638        $window: $WindowProvider,
1639        $$urlUtils: $$UrlUtilsProvider
1640      });
1641    }
1642  ]);
1643}
1644
1645//////////////////////////////////
1646//JQLite
1647//////////////////////////////////
1648
1649/**
1650 * @ngdoc function
1651 * @name angular.element
1652 * @function
1653 *
1654 * @description
1655 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
1656 * `angular.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
1657 * jQuery is available, or a function that wraps the element or string in Angular's jQuery lite
1658 * implementation (commonly referred to as jqLite).
1659 *
1660 * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
1661 * event fired.
1662 *
1663 * jqLite is a tiny, API-compatible subset of jQuery that allows
1664 * Angular to manipulate the DOM. jqLite implements only the most commonly needed functionality
1665 * within a very small footprint, so only a subset of the jQuery API - methods, arguments and
1666 * invocation styles - are supported.
1667 *
1668 * Note: All element references in Angular are always wrapped with jQuery or jqLite; they are never
1669 * raw DOM references.
1670 *
1671 * ## Angular's jqLite
1672 * Angular's lite version of jQuery provides only the following jQuery methods:
1673 *
1674 * - [addClass()](http://api.jquery.com/addClass/)
1675 * - [after()](http://api.jquery.com/after/)
1676 * - [append()](http://api.jquery.com/append/)
1677 * - [attr()](http://api.jquery.com/attr/)
1678 * - [bind()](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
1679 * - [children()](http://api.jquery.com/children/) - Does not support selectors
1680 * - [clone()](http://api.jquery.com/clone/)
1681 * - [contents()](http://api.jquery.com/contents/)
1682 * - [css()](http://api.jquery.com/css/)
1683 * - [data()](http://api.jquery.com/data/)
1684 * - [eq()](http://api.jquery.com/eq/)
1685 * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name
1686 * - [hasClass()](http://api.jquery.com/hasClass/)
1687 * - [html()](http://api.jquery.com/html/)
1688 * - [next()](http://api.jquery.com/next/) - Does not support selectors
1689 * - [on()](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
1690 * - [off()](http://api.jquery.com/off/) - Does not support namespaces or selectors
1691 * - [parent()](http://api.jquery.com/parent/) - Does not support selectors
1692 * - [prepend()](http://api.jquery.com/prepend/)
1693 * - [prop()](http://api.jquery.com/prop/)
1694 * - [ready()](http://api.jquery.com/ready/)
1695 * - [remove()](http://api.jquery.com/remove/)
1696 * - [removeAttr()](http://api.jquery.com/removeAttr/)
1697 * - [removeClass()](http://api.jquery.com/removeClass/)
1698 * - [removeData()](http://api.jquery.com/removeData/)
1699 * - [replaceWith()](http://api.jquery.com/replaceWith/)
1700 * - [text()](http://api.jquery.com/text/)
1701 * - [toggleClass()](http://api.jquery.com/toggleClass/)
1702 * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
1703 * - [unbind()](http://api.jquery.com/off/) - Does not support namespaces
1704 * - [val()](http://api.jquery.com/val/)
1705 * - [wrap()](http://api.jquery.com/wrap/)
1706 *
1707 * ## jQuery/jqLite Extras
1708 * Angular also provides the following additional methods and events to both jQuery and jqLite:
1709 *
1710 * ### Events
1711 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
1712 *    on all DOM nodes being removed.  This can be used to clean up and 3rd party bindings to the DOM
1713 *    element before it is removed.
1714 * ### Methods
1715 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
1716 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
1717 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
1718 *   `'ngModel'`).
1719 * - `injector()` - retrieves the injector of the current element or its parent.
1720 * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
1721 *   element or its parent.
1722 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
1723 *   parent element is reached.
1724 *
1725 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
1726 * @returns {Object} jQuery object.
1727 */
1728
1729var jqCache = JQLite.cache = {},
1730    jqName = JQLite.expando = 'ng-' + new Date().getTime(),
1731    jqId = 1,
1732    addEventListenerFn = (window.document.addEventListener
1733      ? function(element, type, fn) {element.addEventListener(type, fn, false);}
1734      : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
1735    removeEventListenerFn = (window.document.removeEventListener
1736      ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
1737      : function(element, type, fn) {element.detachEvent('on' + type, fn); });
1738
1739function jqNextId() { return ++jqId; }
1740
1741
1742var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
1743var MOZ_HACK_REGEXP = /^moz([A-Z])/;
1744var jqLiteMinErr = minErr('jqLite');
1745
1746/**
1747 * Converts snake_case to camelCase.
1748 * Also there is special case for Moz prefix starting with upper case letter.
1749 * @param name Name to normalize
1750 */
1751function camelCase(name) {
1752  return name.
1753    replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
1754      return offset ? letter.toUpperCase() : letter;
1755    }).
1756    replace(MOZ_HACK_REGEXP, 'Moz$1');
1757}
1758
1759/////////////////////////////////////////////
1760// jQuery mutation patch
1761//
1762// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
1763// $destroy event on all DOM nodes being removed.
1764//
1765/////////////////////////////////////////////
1766
1767function JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
1768  var originalJqFn = jQuery.fn[name];
1769  originalJqFn = originalJqFn.$original || originalJqFn;
1770  removePatch.$original = originalJqFn;
1771  jQuery.fn[name] = removePatch;
1772
1773  function removePatch(param) {
1774    var list = filterElems && param ? [this.filter(param)] : [this],
1775        fireEvent = dispatchThis,
1776        set, setIndex, setLength,
1777        element, childIndex, childLength, children;
1778
1779    if (!getterIfNoArguments || param != null) {
1780      while(list.length) {
1781        set = list.shift();
1782        for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
1783          element = jqLite(set[setIndex]);
1784          if (fireEvent) {
1785            element.triggerHandler('$destroy');
1786          } else {
1787            fireEvent = !fireEvent;
1788          }
1789          for(childIndex = 0, childLength = (children = element.children()).length;
1790              childIndex < childLength;
1791              childIndex++) {
1792            list.push(jQuery(children[childIndex]));
1793          }
1794        }
1795      }
1796    }
1797    return originalJqFn.apply(this, arguments);
1798  }
1799}
1800
1801/////////////////////////////////////////////
1802function JQLite(element) {
1803  if (element instanceof JQLite) {
1804    return element;
1805  }
1806  if (!(this instanceof JQLite)) {
1807    if (isString(element) && element.charAt(0) != '<') {
1808      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
1809    }
1810    return new JQLite(element);
1811  }
1812
1813  if (isString(element)) {
1814    var div = document.createElement('div');
1815    // Read about the NoScope elements here:
1816    // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
1817    div.innerHTML = '<div>&#160;</div>' + element; // IE insanity to make NoScope elements work!
1818    div.removeChild(div.firstChild); // remove the superfluous div
1819    JQLiteAddNodes(this, div.childNodes);
1820    var fragment = jqLite(document.createDocumentFragment());
1821    fragment.append(this); // detach the elements from the temporary DOM div.
1822  } else {
1823    JQLiteAddNodes(this, element);
1824  }
1825}
1826
1827function JQLiteClone(element) {
1828  return element.cloneNode(true);
1829}
1830
1831function JQLiteDealoc(element){
1832  JQLiteRemoveData(element);
1833  for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
1834    JQLiteDealoc(children[i]);
1835  }
1836}
1837
1838function JQLiteOff(element, type, fn, unsupported) {
1839  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
1840
1841  var events = JQLiteExpandoStore(element, 'events'),
1842      handle = JQLiteExpandoStore(element, 'handle');
1843
1844  if (!handle) return; //no listeners registered
1845
1846  if (isUndefined(type)) {
1847    forEach(events, function(eventHandler, type) {
1848      removeEventListenerFn(element, type, eventHandler);
1849      delete events[type];
1850    });
1851  } else {
1852    forEach(type.split(' '), function(type) {
1853      if (isUndefined(fn)) {
1854        removeEventListenerFn(element, type, events[type]);
1855        delete events[type];
1856      } else {
1857        arrayRemove(events[type] || [], fn);
1858      }
1859    });
1860  }
1861}
1862
1863function JQLiteRemoveData(element, name) {
1864  var expandoId = element[jqName],
1865      expandoStore = jqCache[expandoId];
1866
1867  if (expandoStore) {
1868    if (name) {
1869      delete jqCache[expandoId].data[name];
1870      return;
1871    }
1872
1873    if (expandoStore.handle) {
1874      expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
1875      JQLiteOff(element);
1876    }
1877    delete jqCache[expandoId];
1878    element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
1879  }
1880}
1881
1882function JQLiteExpandoStore(element, key, value) {
1883  var expandoId = element[jqName],
1884      expandoStore = jqCache[expandoId || -1];
1885
1886  if (isDefined(value)) {
1887    if (!expandoStore) {
1888      element[jqName] = expandoId = jqNextId();
1889      expandoStore = jqCache[expandoId] = {};
1890    }
1891    expandoStore[key] = value;
1892  } else {
1893    return expandoStore && expandoStore[key];
1894  }
1895}
1896
1897function JQLiteData(element, key, value) {
1898  var data = JQLiteExpandoStore(element, 'data'),
1899      isSetter = isDefined(value),
1900      keyDefined = !isSetter && isDefined(key),
1901      isSimpleGetter = keyDefined && !isObject(key);
1902
1903  if (!data && !isSimpleGetter) {
1904    JQLiteExpandoStore(element, 'data', data = {});
1905  }
1906
1907  if (isSetter) {
1908    data[key] = value;
1909  } else {
1910    if (keyDefined) {
1911      if (isSimpleGetter) {
1912        // don't create data in this case.
1913        return data && data[key];
1914      } else {
1915        extend(data, key);
1916      }
1917    } else {
1918      return data;
1919    }
1920  }
1921}
1922
1923function JQLiteHasClass(element, selector) {
1924  return ((" " + element.className + " ").replace(/[\n\t]/g, " ").
1925      indexOf( " " + selector + " " ) > -1);
1926}
1927
1928function JQLiteRemoveClass(element, cssClasses) {
1929  if (cssClasses) {
1930    forEach(cssClasses.split(' '), function(cssClass) {
1931      element.className = trim(
1932          (" " + element.className + " ")
1933          .replace(/[\n\t]/g, " ")
1934          .replace(" " + trim(cssClass) + " ", " ")
1935      );
1936    });
1937  }
1938}
1939
1940function JQLiteAddClass(element, cssClasses) {
1941  if (cssClasses) {
1942    forEach(cssClasses.split(' '), function(cssClass) {
1943      if (!JQLiteHasClass(element, cssClass)) {
1944        element.className = trim(element.className + ' ' + trim(cssClass));
1945      }
1946    });
1947  }
1948}
1949
1950function JQLiteAddNodes(root, elements) {
1951  if (elements) {
1952    elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
1953      ? elements
1954      : [ elements ];
1955    for(var i=0; i < elements.length; i++) {
1956      root.push(elements[i]);
1957    }
1958  }
1959}
1960
1961function JQLiteController(element, name) {
1962  return JQLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
1963}
1964
1965function JQLiteInheritedData(element, name, value) {
1966  element = jqLite(element);
1967
1968  // if element is the document object work with the html element instead
1969  // this makes $(document).scope() possible
1970  if(element[0].nodeType == 9) {
1971    element = element.find('html');
1972  }
1973
1974  while (element.length) {
1975    if ((value = element.data(name)) !== undefined) return value;
1976    element = element.parent();
1977  }
1978}
1979
1980//////////////////////////////////////////
1981// Functions which are declared directly.
1982//////////////////////////////////////////
1983var JQLitePrototype = JQLite.prototype = {
1984  ready: function(fn) {
1985    var fired = false;
1986
1987    function trigger() {
1988      if (fired) return;
1989      fired = true;
1990      fn();
1991    }
1992
1993    // check if document already is loaded
1994    if (document.readyState === 'complete'){
1995      setTimeout(trigger);
1996    } else {
1997      this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
1998      // we can not use jqLite since we are not done loading and jQuery could be loaded later.
1999      JQLite(window).on('load', trigger); // fallback to window.onload for others
2000    }
2001  },
2002  toString: function() {
2003    var value = [];
2004    forEach(this, function(e){ value.push('' + e);});
2005    return '[' + value.join(', ') + ']';
2006  },
2007
2008  eq: function(index) {
2009      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2010  },
2011
2012  length: 0,
2013  push: push,
2014  sort: [].sort,
2015  splice: [].splice
2016};
2017
2018//////////////////////////////////////////
2019// Functions iterating getter/setters.
2020// these functions return self on setter and
2021// value on get.
2022//////////////////////////////////////////
2023var BOOLEAN_ATTR = {};
2024forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
2025  BOOLEAN_ATTR[lowercase(value)] = value;
2026});
2027var BOOLEAN_ELEMENTS = {};
2028forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2029  BOOLEAN_ELEMENTS[uppercase(value)] = true;
2030});
2031
2032function getBooleanAttrName(element, name) {
2033  // check dom last since we will most likely fail on name
2034  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2035
2036  // booleanAttr is here twice to minimize DOM access
2037  return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2038}
2039
2040forEach({
2041  data: JQLiteData,
2042  inheritedData: JQLiteInheritedData,
2043
2044  scope: function(element) {
2045    return JQLiteInheritedData(element, '$scope');
2046  },
2047
2048  controller: JQLiteController ,
2049
2050  injector: function(element) {
2051    return JQLiteInheritedData(element, '$injector');
2052  },
2053
2054  removeAttr: function(element,name) {
2055    element.removeAttribute(name);
2056  },
2057
2058  hasClass: JQLiteHasClass,
2059
2060  css: function(element, name, value) {
2061    name = camelCase(name);
2062
2063    if (isDefined(value)) {
2064      element.style[name] = value;
2065    } else {
2066      var val;
2067
2068      if (msie <= 8) {
2069        // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2070        val = element.currentStyle && element.currentStyle[name];
2071        if (val === '') val = 'auto';
2072      }
2073
2074      val = val || element.style[name];
2075
2076      if (msie <= 8) {
2077        // jquery weirdness :-/
2078        val = (val === '') ? undefined : val;
2079      }
2080
2081      return  val;
2082    }
2083  },
2084
2085  attr: function(element, name, value){
2086    var lowercasedName = lowercase(name);
2087    if (BOOLEAN_ATTR[lowercasedName]) {
2088      if (isDefined(value)) {
2089        if (!!value) {
2090          element[name] = true;
2091          element.setAttribute(name, lowercasedName);
2092        } else {
2093          element[name] = false;
2094          element.removeAttribute(lowercasedName);
2095        }
2096      } else {
2097        return (element[name] ||
2098                 (element.attributes.getNamedItem(name)|| noop).specified)
2099               ? lowercasedName
2100               : undefined;
2101      }
2102    } else if (isDefined(value)) {
2103      element.setAttribute(name, value);
2104    } else if (element.getAttribute) {
2105      // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2106      // some elements (e.g. Document) don't have get attribute, so return undefined
2107      var ret = element.getAttribute(name, 2);
2108      // normalize non-existing attributes to undefined (as jQuery)
2109      return ret === null ? undefined : ret;
2110    }
2111  },
2112
2113  prop: function(element, name, value) {
2114    if (isDefined(value)) {
2115      element[name] = value;
2116    } else {
2117      return element[name];
2118    }
2119  },
2120
2121  text: (function() {
2122    var NODE_TYPE_TEXT_PROPERTY = [];
2123    if (msie < 9) {
2124      NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';    /** Element **/
2125      NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';    /** Text **/
2126    } else {
2127      NODE_TYPE_TEXT_PROPERTY[1] =                 /** Element **/
2128      NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';  /** Text **/
2129    }
2130    getText.$dv = '';
2131    return getText;
2132
2133    function getText(element, value) {
2134      var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]
2135      if (isUndefined(value)) {
2136        return textProp ? element[textProp] : '';
2137      }
2138      element[textProp] = value;
2139    }
2140  })(),
2141
2142  val: function(element, value) {
2143    if (isUndefined(value)) {
2144      if (nodeName_(element) === 'SELECT' && element.multiple) {
2145        var result = [];
2146        forEach(element.options, function (option) {
2147          if (option.selected) {
2148            result.push(option.value || option.text);
2149          }
2150        });
2151        return result.length === 0 ? null : result;
2152      }
2153      return element.value;
2154    }
2155    element.value = value;
2156  },
2157
2158  html: function(element, value) {
2159    if (isUndefined(value)) {
2160      return element.innerHTML;
2161    }
2162    for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2163      JQLiteDealoc(childNodes[i]);
2164    }
2165    element.innerHTML = value;
2166  }
2167}, function(fn, name){
2168  /**
2169   * Properties: writes return selection, reads return first value
2170   */
2171  JQLite.prototype[name] = function(arg1, arg2) {
2172    var i, key;
2173
2174    // JQLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2175    // in a way that survives minification.
2176    if (((fn.length == 2 && (fn !== JQLiteHasClass && fn !== JQLiteController)) ? arg1 : arg2) === undefined) {
2177      if (isObject(arg1)) {
2178
2179        // we are a write, but the object properties are the key/values
2180        for(i=0; i < this.length; i++) {
2181          if (fn === JQLiteData) {
2182            // data() takes the whole object in jQuery
2183            fn(this[i], arg1);
2184          } else {
2185            for (key in arg1) {
2186              fn(this[i], key, arg1[key]);
2187            }
2188          }
2189        }
2190        // return self for chaining
2191        return this;
2192      } else {
2193        // we are a read, so read the first child.
2194        var value = fn.$dv;
2195        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2196        var jj = value == undefined ? Math.min(this.length, 1) : this.length;
2197        for (var j = 0; j < jj; j++) {
2198          var nodeValue = fn(this[j], arg1, arg2);
2199          value = value ? value + nodeValue : nodeValue;
2200        }
2201        return value;
2202      }
2203    } else {
2204      // we are a write, so apply to all children
2205      for(i=0; i < this.length; i++) {
2206        fn(this[i], arg1, arg2);
2207      }
2208      // return self for chaining
2209      return this;
2210    }
2211  };
2212});
2213
2214function createEventHandler(element, events) {
2215  var eventHandler = function (event, type) {
2216    if (!event.preventDefault) {
2217      event.preventDefault = function() {
2218        event.returnValue = false; //ie
2219      };
2220    }
2221
2222    if (!event.stopPropagation) {
2223      event.stopPropagation = function() {
2224        event.cancelBubble = true; //ie
2225      };
2226    }
2227
2228    if (!event.target) {
2229      event.target = event.srcElement || document;
2230    }
2231
2232    if (isUndefined(event.defaultPrevented)) {
2233      var prevent = event.preventDefault;
2234      event.preventDefault = function() {
2235        event.defaultPrevented = true;
2236        prevent.call(event);
2237      };
2238      event.defaultPrevented = false;
2239    }
2240
2241    event.isDefaultPrevented = function() {
2242      return event.defaultPrevented || event.returnValue == false;
2243    };
2244
2245    forEach(events[type || event.type], function(fn) {
2246      fn.call(element, event);
2247    });
2248
2249    // Remove monkey-patched methods (IE),
2250    // as they would cause memory leaks in IE8.
2251    if (msie <= 8) {
2252      // IE7/8 does not allow to delete property on native object
2253      event.preventDefault = null;
2254      event.stopPropagation = null;
2255      event.isDefaultPrevented = null;
2256    } else {
2257      // It shouldn't affect normal browsers (native methods are defined on prototype).
2258      delete event.preventDefault;
2259      delete event.stopPropagation;
2260      delete event.isDefaultPrevented;
2261    }
2262  };
2263  eventHandler.elem = element;
2264  return eventHandler;
2265}
2266
2267//////////////////////////////////////////
2268// Functions iterating traversal.
2269// These functions chain results into a single
2270// selector.
2271//////////////////////////////////////////
2272forEach({
2273  removeData: JQLiteRemoveData,
2274
2275  dealoc: JQLiteDealoc,
2276
2277  on: function onFn(element, type, fn, unsupported){
2278    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2279
2280    var events = JQLiteExpandoStore(element, 'events'),
2281        handle = JQLiteExpandoStore(element, 'handle');
2282
2283    if (!events) JQLiteExpandoStore(element, 'events', events = {});
2284    if (!handle) JQLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2285
2286    forEach(type.split(' '), function(type){
2287      var eventFns = events[type];
2288
2289      if (!eventFns) {
2290        if (type == 'mouseenter' || type == 'mouseleave') {
2291          var contains = document.body.contains || document.body.compareDocumentPosition ?
2292          function( a, b ) {
2293            var adown = a.nodeType === 9 ? a.documentElement : a,
2294            bup = b && b.parentNode;
2295            return a === bup || !!( bup && bup.nodeType === 1 && (
2296              adown.contains ?
2297              adown.contains( bup ) :
2298              a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
2299              ));
2300            } :
2301            function( a, b ) {
2302              if ( b ) {
2303                while ( (b = b.parentNode) ) {
2304                  if ( b === a ) {
2305                    return true;
2306                  }
2307                }
2308              }
2309              return false;
2310            };
2311
2312          events[type] = [];
2313
2314          // Refer to jQuery's implementation of mouseenter & mouseleave
2315          // Read about mouseenter and mouseleave:
2316          // http://www.quirksmode.org/js/events_mouse.html#link8
2317          var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
2318
2319          onFn(element, eventmap[type], function(event) {
2320            var target = this, related = event.relatedTarget;
2321            // For mousenter/leave call the handler if related is outside the target.
2322            // NB: No relatedTarget if the mouse left/entered the browser window
2323            if ( !related || (related !== target && !contains(target, related)) ){
2324              handle(event, type);
2325            }
2326          });
2327
2328        } else {
2329          addEventListenerFn(element, type, handle);
2330          events[type] = [];
2331        }
2332        eventFns = events[type]
2333      }
2334      eventFns.push(fn);
2335    });
2336  },
2337
2338  off: JQLiteOff,
2339
2340  replaceWith: function(element, replaceNode) {
2341    var index, parent = element.parentNode;
2342    JQLiteDealoc(element);
2343    forEach(new JQLite(replaceNode), function(node){
2344      if (index) {
2345        parent.insertBefore(node, index.nextSibling);
2346      } else {
2347        parent.replaceChild(node, element);
2348      }
2349      index = node;
2350    });
2351  },
2352
2353  children: function(element) {
2354    var children = [];
2355    forEach(element.childNodes, function(element){
2356      if (element.nodeType === 1)
2357        children.push(element);
2358    });
2359    return children;
2360  },
2361
2362  contents: function(element) {
2363    return element.childNodes || [];
2364  },
2365
2366  append: function(element, node) {
2367    forEach(new JQLite(node), function(child){
2368      if (element.nodeType === 1 || element.nodeType === 11) {
2369        element.appendChild(child);
2370      }
2371    });
2372  },
2373
2374  prepend: function(element, node) {
2375    if (element.nodeType === 1) {
2376      var index = element.firstChild;
2377      forEach(new JQLite(node), function(child){
2378        element.insertBefore(child, index);
2379      });
2380    }
2381  },
2382
2383  wrap: function(element, wrapNode) {
2384    wrapNode = jqLite(wrapNode)[0];
2385    var parent = element.parentNode;
2386    if (parent) {
2387      parent.replaceChild(wrapNode, element);
2388    }
2389    wrapNode.appendChild(element);
2390  },
2391
2392  remove: function(element) {
2393    JQLiteDealoc(element);
2394    var parent = element.parentNode;
2395    if (parent) parent.removeChild(element);
2396  },
2397
2398  after: function(element, newElement) {
2399    var index = element, parent = element.parentNode;
2400    forEach(new JQLite(newElement), function(node){
2401      parent.insertBefore(node, index.nextSibling);
2402      index = node;
2403    });
2404  },
2405
2406  addClass: JQLiteAddClass,
2407  removeClass: JQLiteRemoveClass,
2408
2409  toggleClass: function(element, selector, condition) {
2410    if (isUndefined(condition)) {
2411      condition = !JQLiteHasClass(element, selector);
2412    }
2413    (condition ? JQLiteAddClass : JQLiteRemoveClass)(element, selector);
2414  },
2415
2416  parent: function(element) {
2417    var parent = element.parentNode;
2418    return parent && parent.nodeType !== 11 ? parent : null;
2419  },
2420
2421  next: function(element) {
2422    if (element.nextElementSibling) {
2423      return element.nextElementSibling;
2424    }
2425
2426    // IE8 doesn't have nextElementSibling
2427    var elm = element.nextSibling;
2428    while (elm != null && elm.nodeType !== 1) {
2429      elm = elm.nextSibling;
2430    }
2431    return elm;
2432  },
2433
2434  find: function(element, selector) {
2435    return element.getElementsByTagName(selector);
2436  },
2437
2438  clone: JQLiteClone,
2439
2440  triggerHandler: function(element, eventName, eventData) {
2441    var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
2442    eventData = eventData || {
2443      preventDefault: noop,
2444      stopPropagation: noop
2445    };
2446
2447    forEach(eventFns, function(fn) {
2448      fn.call(element, eventData);
2449    });
2450  }
2451}, function(fn, name){
2452  /**
2453   * chaining functions
2454   */
2455  JQLite.prototype[name] = function(arg1, arg2, arg3) {
2456    var value;
2457    for(var i=0; i < this.length; i++) {
2458      if (value == undefined) {
2459        value = fn(this[i], arg1, arg2, arg3);
2460        if (value !== undefined) {
2461          // any function which returns a value needs to be wrapped
2462          value = jqLite(value);
2463        }
2464      } else {
2465        JQLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
2466      }
2467    }
2468    return value == undefined ? this : value;
2469  };
2470
2471  // bind legacy bind/unbind to on/off
2472  JQLite.prototype.bind = JQLite.prototype.on;
2473  JQLite.prototype.unbind = JQLite.prototype.off;
2474});
2475
2476/**
2477 * Computes a hash of an 'obj'.
2478 * Hash of a:
2479 *  string is string
2480 *  number is number as string
2481 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
2482 *         that is also assigned to the $$hashKey property of the object.
2483 *
2484 * @param obj
2485 * @returns {string} hash string such that the same input will have the same hash string.
2486 *         The resulting string key is in 'type:hashKey' format.
2487 */
2488function hashKey(obj) {
2489  var objType = typeof obj,
2490      key;
2491
2492  if (objType == 'object' && obj !== null) {
2493    if (typeof (key = obj.$$hashKey) == 'function') {
2494      // must invoke on object to keep the right this
2495      key = obj.$$hashKey();
2496    } else if (key === undefined) {
2497      key = obj.$$hashKey = nextUid();
2498    }
2499  } else {
2500    key = obj;
2501  }
2502
2503  return objType + ':' + key;
2504}
2505
2506/**
2507 * HashMap which can use objects as keys
2508 */
2509function HashMap(array){
2510  forEach(array, this.put, this);
2511}
2512HashMap.prototype = {
2513  /**
2514   * Store key value pair
2515   * @param key key to store can be any type
2516   * @param value value to store can be any type
2517   */
2518  put: function(key, value) {
2519    this[hashKey(key)] = value;
2520  },
2521
2522  /**
2523   * @param key
2524   * @returns the value for the key
2525   */
2526  get: function(key) {
2527    return this[hashKey(key)];
2528  },
2529
2530  /**
2531   * Remove the key/value pair
2532   * @param key
2533   */
2534  remove: function(key) {
2535    var value = this[key = hashKey(key)];
2536    delete this[key];
2537    return value;
2538  }
2539};
2540
2541/**
2542 * @ngdoc function
2543 * @name angular.injector
2544 * @function
2545 *
2546 * @description
2547 * Creates an injector function that can be used for retrieving services as well as for
2548 * dependency injection (see {@link guide/di dependency injection}).
2549 *
2550
2551 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
2552 *        {@link angular.module}. The `ng` module must be explicitly added.
2553 * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
2554 *
2555 * @example
2556 * Typical usage
2557 * <pre>
2558 *   // create an injector
2559 *   var $injector = angular.injector(['ng']);
2560 *
2561 *   // use the injector to kick off your application
2562 *   // use the type inference to auto inject arguments, or use impl
2562icit injection
2563 *   $injector.invoke(function($rootScope, $compile, $document){
2564 *     $compile($document)($rootScope);
2565 *     $rootScope.$digest();
2566 *   });
2567 * </pre>
2568 */
2569
2570
2571/**
2572 * @ngdoc overview
2573 * @name AUTO
2574 * @description
2575 *
2576 * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
2577 */
2578
2579var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
2580var FN_ARG_SPLIT = /,/;
2581var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
2582var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
2583var $injectorMinErr = minErr('$injector');
2584function annotate(fn) {
2585  var $inject,
2586      fnText,
2587      argDecl,
2588      last;
2589
2590  if (typeof fn == 'function') {
2591    if (!($inject = fn.$inject)) {
2592      $inject = [];
2593      fnText = fn.toString().replace(STRIP_COMMENTS, '');
2594      argDecl = fnText.match(FN_ARGS);
2595      forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
2596        arg.replace(FN_ARG, function(all, underscore, name){
2597          $inject.push(name);
2598        });
2599      });
2600      fn.$inject = $inject;
2601    }
2602  } else if (isArray(fn)) {
2603    last = fn.length - 1;
2604    assertArgFn(fn[last], 'fn');
2605    $inject = fn.slice(0, last);
2606  } else {
2607    assertArgFn(fn, 'fn', true);
2608  }
2609  return $inject;
2610}
2611
2612///////////////////////////////////////
2613
2614/**
2615 * @ngdoc object
2616 * @name AUTO.$injector
2617 * @function
2618 *
2619 * @description
2620 *
2621 * `$injector` is used to retrieve object instances as defined by
2622 * {@link AUTO.$provide provider}, instantiate types, invoke methods,
2623 * and load modules.
2624 *
2625 * The following always holds true:
2626 *
2627 * <pre>
2628 *   var $injector = angular.injector();
2629 *   expect($injector.get('$injector')).toBe($injector);
2630 *   expect($injector.invoke(function($injector){
2631 *     return $injector;
2632 *   }).toBe($injector);
2633 * </pre>
2634 *
2635 * # Injection Function Annotation
2636 *
2637 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
2638 * following are all valid ways of annotating function with injection arguments and are equivalent.
2639 *
2640 * <pre>
2641 *   // inferred (only works if code not minified/obfuscated)
2642 *   $injector.invoke(function(serviceA){});
2643 *
2644 *   // annotated
2645 *   function explicit(serviceA) {};
2646 *   explicit.$inject = ['serviceA'];
2647 *   $injector.invoke(explicit);
2648 *
2649 *   // inline
2650 *   $injector.invoke(['serviceA', function(serviceA){}]);
2651 * </pre>
2652 *
2653 * ## Inference
2654 *
2655 * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
2656 * parsed and the function arguments can be extracted. *NOTE:* This does not work with minification, and obfuscation
2657 * tools since these tools change the argument names.
2658 *
2659 * ## `$inject` Annotation
2660 * By adding a `$inject` property onto a function the injection parameters can be specified.
2661 *
2662 * ## Inline
2663 * As an array of injection names, where the last item in the array is the function to call.
2664 */
2665
2666/**
2667 * @ngdoc method
2668 * @name AUTO.$injector#get
2669 * @methodOf AUTO.$injector
2670 *
2671 * @description
2672 * Return an instance of the service.
2673 *
2674 * @param {string} name The name of the instance to retrieve.
2675 * @return {*} The instance.
2676 */
2677
2678/**
2679 * @ngdoc method
2680 * @name AUTO.$injector#invoke
2681 * @methodOf AUTO.$injector
2682 *
2683 * @description
2684 * Invoke the method and supply the method arguments from the `$injector`.
2685 *
2686 * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
2687 * @param {Object=} self The `this` for the invoked method.
2688 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
2689 *   the `$injector` is consulted.
2690 * @returns {*} the value returned by the invoked `fn` function.
2691 */
2692
2693/**
2694 * @ngdoc method
2695 * @name AUTO.$injector#has
2696 * @methodOf AUTO.$injector
2697 *
2698 * @description
2699 * Allows the user to query if the particular service exist.
2700 *
2701 * @param {string} Name of the service to query.
2702 * @returns {boolean} returns true if injector has given service.
2703 */
2704
2705/**
2706 * @ngdoc method
2707 * @name AUTO.$injector#instantiate
2708 * @methodOf AUTO.$injector
2709 * @description
2710 * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
2711 * all of the arguments to the constructor function as specified by the constructor annotation.
2712 *
2713 * @param {function} Type Annotated constructor function.
2714 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
2715 *   the `$injector` is consulted.
2716 * @returns {Object} new instance of `Type`.
2717 */
2718
2719/**
2720 * @ngdoc method
2721 * @name AUTO.$injector#annotate
2722 * @methodOf AUTO.$injector
2723 *
2724 * @description
2725 * Returns an array of service names which the function is requesting for injection. This API is used by the injector
2726 * to determine which services need to be injected into the function when the function is invoked. There are three
2727 * ways in which the function can be annotated with the needed dependencies.
2728 *
2729 * # Argument names
2730 *
2731 * The simplest form is to extract the dependencies from the arguments of the function. This is done by convert
2731ing
2732 * the function into a string using `toString()` method and extracting the argument names.
2733 * <pre>
2734 *   // Given
2735 *   function MyController($scope, $route) {
2736 *     // ...
2737 *   }
2738 *
2739 *   // Then
2740 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
2741 * </pre>
2742 *
2743 * This method does not work with code minification / obfuscation. For this reason the following annotation strategies
2744 * are supported.
2745 *
2746 * # The `$inject` property
2747 *
2748 * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
2749 * services to be injected into the function.
2750 * <pre>
2751 *   // Given
2752 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
2753 *     // ...
2754 *   }
2755 *   // Define function dependencies
2756 *   MyController.$inject = ['$scope', '$route'];
2757 *
2758 *   // Then
2759 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
2760 * </pre>
2761 *
2762 * # The array notation
2763 *
2764 * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
2765 * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
2766 * minification is a better choice:
2767 *
2768 * <pre>
2769 *   // We wish to write this (not minification / obfuscation safe)
2770 *   injector.invoke(function($compile, $rootScope) {
2771 *     // ...
2772 *   });
2773 *
2774 *   // We are forced to write break inlining
2775 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
2776 *     // ...
2777 *   };
2778 *   tmpFn.$inject = ['$compile', '$rootScope'];
2779 *   injector.invoke(tmpFn);
2780 *
2781 *   // To better support inline function the inline annotation is supported
2782 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
2783 *     // ...
2784 *   }]);
2785 *
2786 *   // Therefore
2787 *   expect(injector.annotate(
2788 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
2789 *    ).toEqual(['$compile', '$rootScope']);
2790 * </pre>
2791 *
2792 * @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
2793 *   above.
2794 *
2795 * @returns {Array.<string>} The names of the services which the function requires.
2796 */
2797
2798
2799
2800
2801/**
2802 * @ngdoc object
2803 * @name AUTO.$provide
2804 *
2805 * @description
2806 *
2807 * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
2808 * The providers share the same name as the instance they create with `Provider` suffixed to them.
2809 *
2810 * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
2811 * a service. The Provider can have additional methods which would allow for configuration of the provider.
2812 *
2813 * <pre>
2814 *   function GreetProvider() {
2815 *     var salutation = 'Hello';
2816 *
2817 *     this.salutation = function(text) {
2818 *       salutation = text;
2819 *     };
2820 *
2821 *     this.$get = function() {
2822 *       return function (name) {
2823 *         return salutation + ' ' + name + '!';
2824 *       };
2825 *     };
2826 *   }
2827 *
2828 *   describe('Greeter', function(){
2829 *
2830 *     beforeEach(module(function($provide) {
2831 *       $provide.provider('greet', GreetProvider);
2832 *     }));
2833 *
2834 *     it('should greet', inject(function(greet) {
2835 *       expect(greet('angular')).toEqual('Hello angular!');
2836 *     }));
2837 *
2838 *     it('should allow configuration of salutation', function() {
2839 *       module(function(greetProvider) {
2840 *         greetProvider.salutation('Ahoj');
2841 *       });
2842 *       inject(function(greet) {
2843 *         expect(greet('angular')).toEqual('Ahoj angular!');
2844 *       });
2845 *     });
2846 * </pre>
2847 */
2848
2849/**
2850 * @ngdoc method
2851 * @name AUTO.$provide#provider
2852 * @methodOf AUTO.$provide
2853 * @description
2854 *
2855 * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
2856 *
2857 * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
2858 * @param {(Object|function())} provider If the provider is:
2859 *
2860 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
2861 *               {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
2862 *   - `Constructor`: a new instance of the provider will be created using
2863 *               {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
2864 *
2865 * @returns {Object} registered provider instance
2866 */
2867
2868/**
2869 * @ngdoc method
2870 * @name AUTO.$provide#factory
2871 * @methodOf AUTO.$provide
2872 * @description
2873 *
2874 * A short hand for configuring services if only `$get` method is required.
2875 *
2876 * @param {string} name The name of the instance.
2877 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
2878 * `$provide.provider(name, {$get: $getFn})`.
2879 * @returns {Object} registered provider instance
2880 */
2881
2882
2883/**
2884 * @ngdoc method
2885 * @name AUTO.$provide#service
2886 * @methodOf AUTO.$provide
2887 * @description
2888 *
2889 * A short hand for registering service of given class.
2890 *
2891 * @param {string} name The name of the instance.
2892 * @param {Function} constructor A class (constructor function) that will be instantiated.
2893 * @returns {Object} registered provider instance
2894 */
2895
2896
2897/**
2898 * @ngdoc method
2899 * @name AUTO.$provide#value
2900 * @methodOf AUTO.$provide
2901 * @description
2902 *
2903 * A short hand for configuring services if the `$get` method is a constant.
2904 *
2905 * @param {string} name The name of the instance.
2906 * @param {*} value The value.
2907 * @returns {Object} registered provider instance
2908 */
2909
2910
2911/**
2912 * @ngdoc method
2913 * @name AUTO.$provide#constant
2914 * @methodOf AUTO.$provide
2915 * @description
2916 *
2917 * A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
2918 * into configuration function (other modules) and it is not interceptable by
2919 * {@link AUTO.$provide#decorator decorator}.
2920 *
2921 * @param {string} name The name of the constant.
2922 * @param {*} value The constant value.
2923 * @returns {Object} registered instance
2924 */
2925
2926
2927/**
2928 * @ngdoc method
2929 * @name AUTO.$provide#decorator
2930 * @methodOf AUTO.$provide
2931 * @description
2932 *
2933 * Decoration of service, allows the decorator to intercept the service instance creation. The
2934 * returned instance may be the original instance, or a new instance which delegates to the
2935 * original instance.
2936 *
2937 * @param {string} name The name of the service to decorate.
2938 * @param {function()} decorator This function will be invoked when the service needs to be
2939 *    instantiated. The function is called using the {@link AUTO.$injector#invoke
2940 *    injector.invoke} method and is therefore fully injectable. Local injection arguments:
2941 *
2942 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
2943 *      decorated or delegated to.
2944 */
2945
2946
2947function createInjector(modulesToLoad) {
2948  var INSTANTIATING = {},
2949      providerSuffix = 'Provider',
2950      path = [],
2951      loadedModules = new HashMap(),
2952      providerCache = {
2953        $provide: {
2954            provider: supportObject(provider),
2955            factory: supportObject(factory),
2956            service: supportObject(service),
2957            value: supportObject(value),
2958            constant: supportObject(constant),
2959            decorator: decorator
2960          }
2961      },
2962      providerInjector = (providerCache.$injector =
2963          createInternalInjector(providerCache, function() {
2964            throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
2965          })),
2966      instanceCache = {},
2967      instanceInjector = (instanceCache.$injector =
2968          createInternalInjector(instanceCache, function(servicename) {
2969            var provider = providerInjector.get(servicename + providerSuffix);
2970            return instanceInjector.invoke(provider.$get, provider);
2971          }));
2972
2973
2974  forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
2975
2976  return instanceInjector;
2977
2978  ////////////////////////////////////
2979  // $provider
2980  ////////////////////////////////////
2981
2982  function supportObject(delegate) {
2983    return function(key, value) {
2984      if (isObject(key)) {
2985        forEach(key, reverseParams(delegate));
2986      } else {
2987        return delegate(key, value);
2988      }
2989    }
2990  }
2991
2992  function provider(name, provider_) {
2993    if (isFunction(provider_) || isArray(provider_)) {
2994      provider_ = providerInjector.instantiate(provider_);
2995    }
2996    if (!provider_.$get) {
2997      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
2998    }
2999    return providerCache[name + providerSuffix] = provider_;
3000  }
3001
3002  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
3003
3004  function service(name, constructor) {
3005    return factory(name, ['$injector', function($injector) {
3006      return $injector.instantiate(constructor);
3007    }]);
3008  }
3009
3010  function value(name, value) { return factory(name, valueFn(value)); }
3011
3012  function constant(name, value) {
3013    providerCache[name] = value;
3014    instanceCache[name] = value;
3015  }
3016
3017  function decorator(serviceName, decorFn) {
3018    var origProvider = providerInjector.get(serviceName + providerSuffix),
3019        orig$get = origProvider.$get;
3020
3021    origProvider.$get = function() {
3022      var origInstance = instanceInjector.invoke(orig$get, origProvider);
3023      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3024    };
3025  }
3026
3027  ////////////////////////////////////
3028  // Module Loading
3029  ////////////////////////////////////
3030  function loadModules(modulesToLoad){
3031    var runBlocks = [];
3032    forEach(modulesToLoad, function(module) {
3033      if (loadedModules.get(module)) return;
3034      loadedModules.put(module, true);
3035
3036      try {
3037        if (isString(module)) {
3038          var moduleFn = angularModule(module);
3039          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3040
3041          for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3042            var invokeArgs = invokeQueue[i],
3043                provider = providerInjector.get(invokeArgs[0]);
3044
3045            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3046          }
3047        } else if (isFunction(module)) {
3048            runBlocks.push(providerInjector.invoke(module));
3049        } else if (isArray(module)) {
3050            runBlocks.push(providerInjector.invoke(module));
3051        } else {
3052          assertArgFn(module, 'module');
3053        }
3054      } catch (e) {
3055        if (isArray(module)) {
3056          module = module[module.length - 1];
3057        }
3058        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3059          // Safari & FF's stack traces don't contain error.message content unlike those of Chrome and IE
3060          // So if stack doesn't contain message, we create a new string that contains both.
3061          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3062          e = e.message + '\n' + e.stack;
3063        }
3064        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", module, e.stack || e.message || e);
3065      }
3066    });
3067    return runBlocks;
3068  }
3069
3070  ////////////////////////////////////
3071  // internal Injector
3072  ////////////////////////////////////
3073
3074  function createInternalInjector(cache, factory) {
3075
3076    function getService(serviceName) {
3077      if (cache.hasOwnProperty(serviceName)) {
3078        if (cache[serviceName] === INSTANTIATING) {
3079          throw $injectorMinErr('cdep', 'Circular dependency foun
3079d: {0}', path.join(' <- '));
3080        }
3081        return cache[serviceName];
3082      } else {
3083        try {
3084          path.unshift(serviceName);
3085          cache[serviceName] = INSTANTIATING;
3086          return cache[serviceName] = factory(serviceName);
3087        } finally {
3088          path.shift();
3089        }
3090      }
3091    }
3092
3093    function invoke(fn, self, locals){
3094      var args = [],
3095          $inject = annotate(fn),
3096          length, i,
3097          key;
3098
3099      for(i = 0, length = $inject.length; i < length; i++) {
3100        key = $inject[i];
3101        if (typeof key !== 'string') {
3102          throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key);
3103        }
3104        args.push(
3105          locals && locals.hasOwnProperty(key)
3106          ? locals[key]
3107          : getService(key)
3108        );
3109      }
3110      if (!fn.$inject) {
3111        // this means that we must be an array.
3112        fn = fn[length];
3113      }
3114
3115
3116      // Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
3117      switch (self ? -1 : args.length) {
3118        case  0: return fn();
3119        case  1: return fn(args[0]);
3120        case  2: return fn(args[0], args[1]);
3121        case  3: return fn(args[0], args[1], args[2]);
3122        case  4: return fn(args[0], args[1], args[2], args[3]);
3123        case  5: return fn(args[0], args[1], args[2], args[3], args[4]);
3124        case  6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
3125        case  7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
3126        case  8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
3127        case  9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
3128        case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
3129        default: return fn.apply(self, args);
3130      }
3131    }
3132
3133    function instantiate(Type, locals) {
3134      var Constructor = function() {},
3135          instance, returnedValue;
3136
3137      // Check if Type is annotated and use just the given function at n-1 as parameter
3138      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3139      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3140      instance = new Constructor();
3141      returnedValue = invoke(Type, instance, locals);
3142
3143      return isObject(returnedValue) ? returnedValue : instance;
3144    }
3145
3146    return {
3147      invoke: invoke,
3148      instantiate: instantiate,
3149      get: getService,
3150      annotate: annotate,
3151      has: function(name) {
3152        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3153      }
3154    };
3155  }
3156}
3157
3158/**
3159 * @ngdoc function
3160 * @name ng.$anchorScroll
3161 * @requires $window
3162 * @requires $location
3163 * @requires $rootScope
3164 *
3165 * @description
3166 * When called, it checks current value of `$location.hash()` and scroll to related element,
3167 * according to rules specified in
3168 * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
3169 *
3170 * It also watches the `$location.hash()` and scroll whenever it changes to match any anchor.
3171 * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3172 */
3173function $AnchorScrollProvider() {
3174
3175  var autoScrollingEnabled = true;
3176
3177  this.disableAutoScrolling = function() {
3178    autoScrollingEnabled = false;
3179  };
3180
3181  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
3182    var document = $window.document;
3183
3184    // helper function to get first anchor from a NodeList
3185    // can't use filter.filter, as it accepts only instances of Array
3186    // and IE can't convert NodeList to an array using [].slice
3187    // TODO(vojta): use filter if we change it to accept lists as well
3188    function getFirstAnchor(list) {
3189      var result = null;
3190      forEach(list, function(element) {
3191        if (!result && lowercase(element.nodeName) === 'a') result = element;
3192      });
3193      return result;
3194    }
3195
3196    function scroll() {
3197      var hash = $location.hash(), elm;
3198
3199      // empty hash, scroll to the top of the page
3200      if (!hash) $window.scrollTo(0, 0);
3201
3202      // element with given id
3203      else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
3204
3205      // first anchor with given name :-D
3206      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
3207
3208      // no element and hash == 'top', scroll to the top of the page
3209      else if (hash === 'top') $window.scrollTo(0, 0);
3210    }
3211
3212    // does not scroll when user clicks on anchor link that is currently on
3213    // (no url change, no $location.hash() change), browser native does scroll
3214    if (autoScrollingEnabled) {
3215      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
3216        function autoScrollWatchAction() {
3217          $rootScope.$evalAsync(scroll);
3218        });
3219    }
3220
3221    return scroll;
3222  }];
3223}
3224
3225var $animateMinErr = minErr('$animate');
3226
3227/**
3228 * @ngdoc object
3229 * @name ng.$animateProvider
3230 *
3231 * @description
3232 * Default implementation of $animate that doesn't perform any animations, instead just synchronously performs DOM
3233 * updates and calls done() callbacks.
3234 *
3235 * In order to enable animations the ngAnimate module has to be loaded.
3236 *
3237 * To see the functional implementation check out src/ngAnimate/animate.js
3238 */
3239var $AnimateProvider = ['$provide', function($provide) {
3240
3241  this.$$selectors = {};
3242
3243
3244  /**
3245   * @ngdoc function
3246   * @name ng.$animateProvider#register
3247   * @methodOf ng.$animateProvider
3248   *
3249   * @description
3250   * Registers a new injectable animation factory function. The factory function produces the animation object which
3251   * contains callback functions for each event that is expected to be animated.
3252   *
3253   *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` must be called once the
3254   *   element animation is complete. If a function is returned then the animation service will use this function to
3255   *   cancel the animation whenever a cancel event is triggered.
3256   *
3257   *
3258   *<pre>
3259   *   return {
3260     *     eventFn : function(element, done) {
3261     *       //code to run the animation
3262     *       //once complete, then run done()
3263     *       return function cancellationFunction() {
3264     *         //code to cancel the animation
3265     *       }
3266     *     }
3267     *   }
3268   *</pre>
3269   *
3270   * @param {string} name The name of the animation.
3271   * @param {function} factory The factory function that will be executed to return the animation object.
3272   */
3273  this.register = function(name, factory) {
3274    var key = name + '-animation';
3275    if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
3276        "Expecting class selector starting with '.' got '{0}'.", name);
3277    this.$$selectors[name.substr(1)] = key;
3278    $provide.factory(key, factory);
3279  };
3280
3281  this.$get = ['$timeout', function($timeout) {
3282
3283    /**
3284     * @ngdoc object
3285     * @name ng.$animate
3286     *
3287     * @description
3288     * The $animate service provides rudimentary DOM manipulation functions to insert, remove, move elements within
3289     * the DOM as well as adding and removing classes. This service is the core service used by the ngAnimate $animator
3290     * service which provides high-level animation hooks for CSS and JavaScript. 
3291     *
3292     * $animate is available in the AngularJS core, however, the ngAnimate module must be included to enable full out
3293     * animation support. Otherwise, $animate will only perform simple DOM manipulation operations.
3294     *
3295     * To learn more about enabling animation support, click here to visit the {@link ngAnimate ngAnimate module page}
3296     * as well as the {@link ngAnimate.$animate ngAnimate $animate service page}.
3297     */
3298    return {
3299
3300      /**
3301       * @ngdoc function
3302       * @name ng.$animate#enter
3303       * @methodOf ng.$animate
3304       * @function
3305       *
3306       * @description
3307       * Inserts the element into the DOM either after the `after` element or within the `parent` element. Once complete,
3308       * the done() callback will be fired (if provided).
3309       *
3310       * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
3311       * @param {jQuery/jqLite element} parent the parent element which will append the element as a child (if the after element is not present)
3312       * @param {jQuery/jqLite element} after the sibling element which will append the element after itself
3313       * @param {function=} done callback function that will be called after the element has been inserted into the DOM
3314       */
3315      enter : function(element, parent, after, done) {
3316        var afterNode = after && after[after.length - 1];
3317        var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
3318        // IE does not like undefined so we have to pass null.
3319        var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
3320        forEach(element, function(node) {
3321          parentNode.insertBefore(node, afterNextSibling);
3322        });
3323        $timeout(done || noop, 0, false);
3324      },
3325
3326      /**
3327       * @ngdoc function
3328       * @name ng.$animate#leave
3329       * @methodOf ng.$animate
3330       * @function
3331       *
3332       * @description
3333       * Removes the element from the DOM. Once complete, the done() callback will be fired (if provided).
3334       *
3335       * @param {jQuery/jqLite element} element the element which will be removed from the DOM
3336       * @param {function=} done callback function that will be called after the element has been removed from the DOM
3337       */
3338      leave : function(element, done) {
3339        element.remove();
3340        $timeout(done || noop, 0, false);
3341      },
3342
3343      /**
3344       * @ngdoc function
3345       * @name ng.$animate#move
3346       * @methodOf ng.$animate
3347       * @function
3348       *
3349       * @description
3350       * Moves the position of the provided element within the DOM to be placed either after the `after` element or inside of the `parent` element.
3351       * Once complete, the done() callback will be fired (if provided).
3352       *
3353       * @param {jQuery/jqLite element} element the element which will be moved around within the DOM
3354       * @param {jQuery/jqLite element} parent the parent element where the element will be inserted into (if the after element is not present)
3355       * @param {jQuery/jqLite element} after the sibling element where the element will be positioned next to
3356       * @param {function=} done the callback function (if provided) that will be fired after the element has been moved to it's new position
3357       */
3358      move : function(element, parent, after, done) {
3359        // Do not remove element before insert. Removing will cause data associated with the
3360        // element to be dropped. Insert will implicitly do the remove.
3361        this.enter(element, parent, after, done);
3362      },
3363
3364      /**
3365       * @ngdoc function
3366       * @name ng.$animate#addClass
3367       * @methodOf ng.$animate
3368       * @function
3369       *
3370       * @description
3371       * Adds the provided className CSS class value to the provided element. Once complete, the done() callback will be fired (if provided).
3372       *
3373       * @param {jQuery/jqLite element} element the element which will have the className value added to it
3374       * @param {string} className the CSS class which will be added to the element
3375       * @param {function=} done the callback function (if provided) that will be fired after the className value has been added to the element
3376       */
3377      addClass : function(element, className, done) {
3378        className = isString(className) ?
3379                      className :
3380                      isArray(className) ? className.join(' ') : '';
3381        element.addClass(className);
3382        $timeout(done || noop, 0, false);
3383      },
3384
3385      /**
3386       * @ngdoc function
3387       * @name ng.$animate#removeClass
3388       * @methodOf ng.$animate
3389       * @function
3390       *
3391       * @description
3392       * Removes the provided className CSS class value from the provided element. Once complete, the done() callback will be fired (if provided).
3393       *
3394       * @param {jQuery/jqLite element} element the element which will have the className value removed from it
3395       * @param {string} className the CSS class which will be removed from the element
3396       * @param {function=} done the callback function (if provided) that will be fired after the className value has been removed from the element
3397       */
3398      removeClass : function(element, className, done) {
3399        className = isString(className) ?
3400                      className :
3401                      isArray(className) ? className.join(' ') : '';
3402        element.removeClass(className);
3403        $timeout(done || noop, 0, false);
3404      },
3405
3406      enabled : noop
3407    };
3408  }];
3409}];
3410
3411/**
3412 * ! This is a private undocumented service !
3413 *
3414 * @name ng.$browser
3415 * @requires $log
3416 * @description
3417 * This object has two goals:
3418 *
3419 * - hide all the global state in the browser caused by the window object
3420 * - abstract away all the browser specific features and inconsistencies
3421 *
3422 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
3423 * service, which can be used for convenient testing of the application without the interaction with
3424 * the real browser apis.
3425 */
3426/**
3427 * @param {object} window The global window object.
3428 * @param {object} document jQuery wrapped document.
3429 * @param {function()} XHR XMLHttpRequest constructor.
3430 * @param {object} $log console.log or an object with the same interface.
3431 * @param {object} $sniffer $sniffer service
3432 */
3433function Browser(window, document, $log, $sniffer) {
3434  var self = this,
3435      rawDocument = document[0],
3436      location = window.location,
3437      history = window.history,
3438      setTimeout = window.setTimeout,
3439      clearTimeout = window.clearTimeout,
3440      pendingDeferIds = {};
3441
3442  self.isMock = false;
3443
3444  var outstandingRequestCount = 0;
3445  var outstandingRequestCallbacks = [];
3446
3447  // TODO(vojta): remove this temporary api
3448  self.$$completeOutstandingRequest = completeOutstandingRequest;
3449  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
3450
3451  /**
3452   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
3453   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
3454   */
3455  function completeOutstandingRequest(fn) {
3456    try {
3457      fn.apply(null, sliceArgs(arguments, 1));
3458    } finally {
3459      outstandingRequestCount--;
3460      if (outstandingRequestCount === 0) {
3461        while(outstandingRequestCallbacks.length) {
3462          try {
3463            outstandingRequestCallbacks.pop()();
3464          } catch (e) {
3465            $log.error(e);
3466          }
3467        }
3468      }
3469    }
3470  }
3471
3472  /**
3473   * @private
3474   * Note: this method is used only by scenario runner
3475   * TODO(vojta): prefix this method with $$ ?
3476   * @param {function()} callback Function that will be called when no outstanding request
3477   */
3478  self.notifyWhenNoOutstandingRequests = function(callback) {
3479    // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
3480    // at some deterministic time in respect to the test runner's actions. Leaving things up to the
3481    // regular poller would result in flaky tests.
3482    forEach(pollFns, function(pollFn){ pollFn(); });
3483
3484    if (outstandingRequestCount === 0) {
3485      callback();
3486    } else {
3487      outstandingRequestCallbacks.push(callback);
3488    }
3489  };
3490
3491  //////////////////////////////////////////////////////////////
3492  // Poll Watcher API
3493  //////////////////////////////////////////////////////////////
3494  var pollFns = [],
3495      pollTimeout;
3496
3497  /**
3498   * @name ng.$browser#addPollFn
3499   * @methodOf ng.$browser
3500   *
3501   * @param {function()} fn Poll function to add
3502   *
3503   * @description
3504   * Adds a function to the list of functions that poller periodically executes,
3505   * and starts polling if not started yet.
3506   *
3507   * @returns {function()} the added function
3508   */
3509  self.addPollFn = function(fn) {
3510    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
3511    pollFns.push(fn);
3512    return fn;
3513  };
3514
3515  /**
3516   * @param {number} interval How often should browser call poll functions (ms)
3517   * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
3518   *
3519   * @description
3520   * Configures the poller to run in the specified intervals, using the specified
3521   * setTimeout fn and kicks it off.
3522   */
3523  function startPoller(interval, setTimeout) {
3524    (function check() {
3525      forEach(pollFns, function(pollFn){ pollFn(); });
3526      pollTimeout = setTimeout(check, interval);
3527    })();
3528  }
3529
3530  //////////////////////////////////////////////////////////////
3531  // URL API
3532  //////////////////////////////////////////////////////////////
3533
3534  var lastBrowserUrl = location.href,
3535      baseElement = document.find('base'),
3536      replacedUrl = null;
3537
3538  /**
3539   * @name ng.$browser#url
3540   * @methodOf ng.$browser
3541   *
3542   * @description
3543   * GETTER:
3544   * Without any argument, this method just returns current value of location.href.
3545   *
3546   * SETTER:
3547   * With at least one argument, this method sets url to new value.
3548   * If html5 history api supported, pushState/replaceState is used, otherwise
3549   * location.href/location.replace is used.
3550   * Returns its own instance to allow chaining
3551   *
3552   * NOTE: this api is intended for use only by the $location service. Please use the
3553   * {@link ng.$location $location service} to change url.
3554   *
3555   * @param {string} url New url (when used as setter)
3556   * @param {boolean=} replace Should new url replace current history record ?
3557   */
3558  self.url = function(url, replace) {
3559    // setter
3560    if (url) {
3561      if (lastBrowserUrl == url) return;
3562      lastBrowserUrl = url;
3563      if ($sniffer.history) {
3564        if (replace) history.replaceState(null, '', url);
3565        else {
3566          history.pushState(null, '', url);
3567          // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
3568          baseElement.attr('href', baseElement.attr('href'));
3569        }
3570      } else {
3571        if (replace) {
3572          location.replace(url);
3573          replacedUrl = url;
3574        } else {
3575          location.href = url;
3576          replacedUrl = null;
3577        }
3578      }
3579      return self;
3580    // getter
3581    } else {
3582      // - the replacedUrl is a workaround for an IE8-9 issue with location.replace method that doesn't update
3583      //   location.href synchronously
3584      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
3585      return replacedUrl || location.href.replace(/%27/g,"'");
3586    }
3587  };
3588
3589  var urlChangeListeners = [],
3590      urlChangeInit = false;
3591
3592  function fireUrlChange() {
3593    if (lastBrowserUrl == self.url()) return;
3594
3595    lastBrowserUrl = self.url();
3596    forEach(urlChangeListeners, function(listener) {
3597      listener(self.url());
3598    });
3599  }
3600
3601  /**
3602   * @name ng.$browser#onUrlChange
3603   * @methodOf ng.$browser
3604   * @TODO(vojta): refactor to use node's syntax for events
3605   *
3606   * @description
3607   * Register callback function that will be called, when url changes.
3608   *
3609   * It's only called when the url is changed by outside of angular:
3610   * - user types different url into address bar
3611   * - user clicks on history (forward/back) button
3612   * - user clicks on a link
3613   *
3614   * It's not called when url is changed by $browser.url() method
3615   *
3616   * The listener gets called with new url as parameter.
3617   *
3618   * NOTE: this api is intended for use only by the $location service. Please use the
3619   * {@link ng.$location $location service} to monitor url changes in angular apps.
3620   *
3621   * @param {function(string)} listener Listener function to be called when url changes.
3622   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
3623   */
3624  self.onUrlChange = function(callback) {
3625    if (!urlChangeInit) {
3626      // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
3627      // don't fire popstate when user change the address bar and don't fire hashchange when url
3628      // changed by push/replaceState
3629
3630      // html5 history api - popstate event
3631      if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
3632      // hashchange event
3633      if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
3634      // polling
3635      else self.addPollFn(fireUrlChange);
3636
3637      urlChangeInit = true;
3638    }
3639
3640    urlChangeListeners.push(callback);
3641    return callback;
3642  };
3643
3644  //////////////////////////////////////////////////////////////
3645  // Misc API
3646  //////////////////////////////////////////////////////////////
3647
3648  /**
3649   * Returns current <base href>
3650   * (always relative - without domain)
3651   *
3652   * @returns {string=}
3653   */
3654  self.baseHref = function() {
3655    var href = baseElement.attr('href');
3656    return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
3657  };
3658
3659  //////////////////////////////////////////////////////////////
3660  // Cookies API
3661  //////////////////////////////////////////////////////////////
3662  var lastCookies = {};
3663  var lastCookieString = '';
3664  var cookiePath = self.baseHref();
3665
3666  /**
3667   * @name ng.$browser#cookies
3668   * @methodOf ng.$browser
3669   *
3670   * @param {string=} name Cookie name
3671   * @param {string=} value Cookie value
3672   *
3673   * @description
3674   * The cookies method provides a 'private' low level access to browser cookies.
3675   * It is not meant to be used directly, use the $cookie service instead.
3676   *
3677   * The return values vary depending on the arguments that the method was called with as follows:
3678   * <ul>
3679   *   <li>cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it</li>
3680   *   <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
3681   *   <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
3682   * </ul>
3683   *
3684   * @returns {Object} Hash of all cookies (if called without any parameter)
3685   */
3686  self.cookies = function(name, value) {
3687    var cookieLength, cookieArray, cookie, i, index;
3688
3689    if (name) {
3690      if (value === undefined) {
3691        rawDocument.cookie = escape(name) + "=;
3691path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
3692      } else {
3693        if (isString(value)) {
3694          cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
3695
3696          // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
3697          // - 300 cookies
3698          // - 20 cookies per unique domain
3699          // - 4096 bytes per cookie
3700          if (cookieLength > 4096) {
3701            $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
3702              cookieLength + " > 4096 bytes)!");
3703          }
3704        }
3705      }
3706    } else {
3707      if (rawDocument.cookie !== lastCookieString) {
3708        lastCookieString = rawDocument.cookie;
3709        cookieArray = lastCookieString.split("; ");
3710        lastCookies = {};
3711
3712        for (i = 0; i < cookieArray.length; i++) {
3713          cookie = cookieArray[i];
3714          index = cookie.indexOf('=');
3715          if (index > 0) { //ignore nameless cookies
3716            var name = unescape(cookie.substring(0, index));
3717            // the first value that is seen for a cookie is the most
3718            // specific one.  values for the same cookie name that
3719            // follow are for less specific paths.
3720            if (lastCookies[name] === undefined) {
3721              lastCookies[name] = unescape(cookie.substring(index + 1));
3722            }
3723          }
3724        }
3725      }
3726      return lastCookies;
3727    }
3728  };
3729
3730
3731  /**
3732   * @name ng.$browser#defer
3733   * @methodOf ng.$browser
3734   * @param {function()} fn A function, who's execution should be deferred.
3735   * @param {number=} [delay=0] of milliseconds to defer the function execution.
3736   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
3737   *
3738   * @description
3739   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
3740   *
3741   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
3742   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
3743   * via `$browser.defer.flush()`.
3744   *
3745   */
3746  self.defer = function(fn, delay) {
3747    var timeoutId;
3748    outstandingRequestCount++;
3749    timeoutId = setTimeout(function() {
3750      delete pendingDeferIds[timeoutId];
3751      completeOutstandingRequest(fn);
3752    }, delay || 0);
3753    pendingDeferIds[timeoutId] = true;
3754    return timeoutId;
3755  };
3756
3757
3758  /**
3759   * @name ng.$browser#defer.cancel
3760   * @methodOf ng.$browser.defer
3761   *
3762   * @description
3763   * Cancels a deferred task identified with `deferId`.
3764   *
3765   * @param {*} deferId Token returned by the `$browser.defer` function.
3766   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully canceled.
3767   */
3768  self.defer.cancel = function(deferId) {
3769    if (pendingDeferIds[deferId]) {
3770      delete pendingDeferIds[deferId];
3771      clearTimeout(deferId);
3772      completeOutstandingRequest(noop);
3773      return true;
3774    }
3775    return false;
3776  };
3777
3778}
3779
3780function $BrowserProvider(){
3781  this.$get = ['$window', '$log', '$sniffer', '$document',
3782      function( $window,   $log,   $sniffer,   $document){
3783        return new Browser($window, $document, $log, $sniffer);
3784      }];
3785}
3786
3787/**
3788 * @ngdoc object
3789 * @name ng.$cacheFactory
3790 *
3791 * @description
3792 * Factory that constructs cache objects and gives access to them.
3793 * 
3794 * <pre>
3795 * 
3796 *  var cache = $cacheFactory('cacheId');
3797 *  expect($cacheFactory.get('cacheId')).toBe(cache);
3798 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
3799 *
3800 *  cache.put("key", "value");
3801 *  cache.put("another key", "another value");
3802 * 
3803 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2}); // Since we've specified no options on creation
3804 * 
3805 * </pre>
3806 *
3807 *
3808 * @param {string} cacheId Name or id of the newly created cache.
3809 * @param {object=} options Options object that specifies the cache behavior. Properties:
3810 *
3811 *   - `{number=}` `capacity` — turns the cache into LRU cache.
3812 *
3813 * @returns {object} Newly created cache object with the following set of methods:
3814 *
3815 * - `{object}` `info()` — Returns id, size, and options of cache.
3816 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns it.
3817 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
3818 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
3819 * - `{void}` `removeAll()` — Removes all cached values.
3820 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
3821 *
3822 */
3823function $CacheFactoryProvider() {
3824
3825  this.$get = function() {
3826    var caches = {};
3827
3828    function cacheFactory(cacheId, options) {
3829      if (cacheId in caches) {
3830        throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
3831      }
3832
3833      var size = 0,
3834          stats = extend({}, options, {id: cacheId}),
3835          data = {},
3836          capacity = (options && options.capacity) || Number.MAX_VALUE,
3837          lruHash = {},
3838          freshEnd = null,
3839          staleEnd = null;
3840
3841      return caches[cacheId] = {
3842
3843        put: function(key, value) {
3844          var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
3845
3846          refresh(lruEntry);
3847
3848          if (isUndefined(value)) return;
3849          if (!(key in data)) size++;
3850          data[key] = value;
3851
3852          if (size > capacity) {
3853            this.remove(staleEnd.key);
3854          }
3855
3856          return value;
3857        },
3858
3859
3860        get: function(key) {
3861          var lruEntry = lruHash[key];
3862
3863          if (!lruEntry) return;
3864
3865          refresh(lruEntry);
3866
3867          return data[key];
3868        },
3869
3870
3871        remove: function(key) {
3872          var lruEntry = lruHash[key];
3873
3874          if (!lruEntry) return;
3875
3876          if (lruEntry == freshEnd) freshEnd = lruEntry.p;
3877          if (lruEntry == staleEnd) staleEnd = lruEntry.n;
3878          link(lruEntry.n,lruEntry.p);
3879
3880          delete lruHash[key];
3881          delete data[key];
3882          size--;
3883        },
3884
3885
3886        removeAll: function() {
3887          data = {};
3888          size = 0;
3889          lruHash = {};
3890          freshEnd = staleEnd = null;
3891        },
3892
3893
3894        destroy: function() {
3895          data = null;
3896          stats = null;
3897          lruHash = null;
3898          delete caches[cacheId];
3899        },
3900
3901
3902        info: function() {
3903          return extend({}, stats, {size: size});
3904        }
3905      };
3906
3907
3908      /**
3909       * makes the `entry` the freshEnd of the LRU linked list
3910       */
3911      function refresh(entry) {
3912        if (entry != freshEnd) {
3913          if (!staleEnd) {
3914            staleEnd = entry;
3915          } else if (staleEnd == entry) {
3916            staleEnd = entry.n;
3917          }
3918
3919          link(entry.n, entry.p);
3920          link(entry, freshEnd);
3921          freshEnd = entry;
3922          freshEnd.n = null;
3923        }
3924      }
3925
3926
3927      /**
3928       * bidirectionally links two entries of the LRU linked list
3929       */
3930      function link(nextEntry, prevEntry) {
3931        if (nextEntry != prevEntry) {
3932          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
3933          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
3934        }
3935      }
3936    }
3937
3938
3939  /**
3940   * @ngdoc method
3941   * @name ng.$cacheFactory#info
3942   * @methodOf ng.$cacheFactory
3943   *
3944   * @description
3945   * Get information about all the of the caches that have been created
3946   *
3947   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
3948   */
3949    cacheFactory.info = function() {
3950      var info = {};
3951      forEach(caches, function(cache, cacheId) {
3952        info[cacheId] = cache.info();
3953      });
3954      return info;
3955    };
3956
3957
3958  /**
3959   * @ngdoc method
3960   * @name ng.$cacheFactory#get
3961   * @methodOf ng.$cacheFactory
3962   *
3963   * @description
3964   * Get access to a cache object by the `cacheId` used when it was created.
3965   *
3966   * @param {string} cacheId Name or id of a cache to access.
3967   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
3968   */
3969    cacheFactory.get = function(cacheId) {
3970      return caches[cacheId];
3971    };
3972
3973
3974    return cacheFactory;
3975  };
3976}
3977
3978/**
3979 * @ngdoc object
3980 * @name ng.$templateCache
3981 *
3982 * @description
3983 * The first time a template is used, it is loaded in the template cache for quick retrieval. You can
3984 * load templates directly into the cache in a `script` tag, or by consuming the `$templateCache`
3985 * service directly.
3986 * 
3987 * Adding via the `script` tag:
3988 * <pre>
3989 * <html ng-app>
3990 * <head>
3991 * <script type="text/ng-template" id="templateId.html">
3992 *   This is the content of the template
3993 * </script>
3994 * </head>
3995 *   ...
3996 * </html>
3997 * </pre>
3998 * 
3999 * **Note:** the `script` tag containing the template does not need to be included in the `head` of the document, but 
4000 * it must be below the `ng-app` definition.
4001 * 
4002 * Adding via the $templateCache service:
4003 * 
4004 * <pre>
4005 * var myApp = angular.module('myApp', []);
4006 * myApp.run(function($templateCache) {
4007 *   $templateCache.put('templateId.html', 'This is the content of the template');
4008 * });
4009 * </pre>
4010 * 
4011 * To retrieve the template later, simply use it in your HTML:
4012 * <pre>
4013 * <div ng-include=" 'templateId.html' "></div>
4014 * </pre>
4015 * 
4016 * or get it via Javascript:
4017 * <pre>
4018 * $templateCache.get('templateId.html')
4019 * </pre>
4020 * 
4021 * See {@link ng.$cacheFactory $cacheFactory}.
4022 *
4023 */
4024function $TemplateCacheProvider() {
4025  this.$get = ['$cacheFactory', function($cacheFactory) {
4026    return $cacheFactory('templates');
4027  }];
4028}
4029
4030/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
4031 *
4032 * DOM-related variables:
4033 *
4034 * - "node" - DOM Node
4035 * - "element" - DOM Element or Node
4036 * - "$node" or "$element" - jqLite-wrapped node or element
4037 *
4038 *
4039 * Compiler related stuff:
4040 *
4041 * - "linkFn" - linking fn of a single directive
4042 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
4043 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
4044 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
4045 */
4046
4047
4048/**
4049 * @ngdoc function
4050 * @name ng.$compile
4051 * @function
4052 *
4053 * @description
4054 * Compiles a piece of HTML string or DOM into a template and produces a template function, which
4055 * can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
4056 *
4057 * The compilation is a process of walking the DOM tree and trying to match DOM elements to
4058 * {@link ng.$compileProvider#directive directives}. For each match it
4059 * executes corresponding template function and collects the
4060 * instance functions into a single template function which is then returned.
4061 *
4062 * The template function can then be used once to produce the view or as it is the case with
4063 * {@link ng.directive:ngRepeat repeater} many-times, in which
4064 * case each call results in a view that is a DOM clone of the original template.
4065 *
4066 <doc:example module="compile">
4067   <doc:source>
4068    <script>
4069      // declare a new module, and inject the $compileProvider
4070      angular.module('compile', [], function($compileProvider) {
4071        // configure new 'compile' directive by passing a directive
4072        // factory function. The factory function injects the '$compile'
4073        $compileProvider.directive('compile', function($compile) {
4074          // directive factory creates a link function
4075          return function(scope, element, attrs) {
4076            scope.$watch(
4077              function(scope) {
4078                 // watch the 'compile' expression for changes
4079                return scope.$eval(attrs.compile);
4080              },
4081              function(value) {
4082                // when the 'compile' expression changes
4083                // assign it into the current DOM
4084                element.html(value);
4085
4086                // compile the new DOM and link it to the current
4087                // scope.
4088                // NOTE: we only compile .childNodes so that
4089                // we don't get into infinite loop compiling ourselves
4090                $compile(element.contents())(scope);
4091              }
4092            );
4093          };
4094        })
4095      });
4096
4097      function Ctrl($scope) {
4098        $scope.name = 'Angular';
4099        $scope.html = 'Hello {{name}}';
4100      }
4101    </script>
4102    <div ng-controller="Ctrl">
4103      <input ng-model="name"> <br>
4104      <textarea ng-model="html"></textarea> <br>
4105      <div compile="html"></div>
4106    </div>
4107   </doc:source>
4108   <doc:scenario>
4109     it('should auto compile', function() {
4110       expect(element('div[compile]').text()).toBe('Hello Angular');
4111       input('html').enter('{{name}}!');
4112       expect(element('div[compile]').text()).toBe('Angular!');
4113     });
4114   </doc:scenario>
4115 </doc:example>
4116
4117 *
4118 *
4119 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
4120 * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
4121 * @param {number} maxPriority only apply directives lower then given priority (Only effects the
4122 *                 root element(s), not their children)
4123 * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
4124 * (a DOM element/tree) to a scope. Where:
4125 *
4126 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
4127 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
4128 *               `template` and call the `cloneAttachFn` function allowing the caller to attach the
4129 *               cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
4130 *               called as: <br> `cloneAttachFn(clonedElement, scope)` where:
4131 *
4132 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
4133 *      * `scope` - is the current scope with which the linking function is working with.
4134 *
4135 * Calling the linking function returns the element of the template. It is either the original element
4136 * passed in, or the clone of the element if the `cloneAttachFn` is provided.
4137 *
4138 * After linking the view is not updated until after a call to $digest which typically is done by
4139 * Angular automatically.
4140 *
4141 * If you need access to the bound view, there are two ways to do it:
4142 *
4143 * - If you are not asking the linking function to clone the template, create the DOM element(s)
4144 *   before you send them to the compiler and keep this reference around.
4145 *   <pre>
4146 *     var element = $compile('<p>{{total}}</p>')(scope);
4147 *   </pre>
4148 *
4149 * - if on the other hand, you need the element to be cloned, the view reference from the original
4150 *   example would not point to the clone, but rather to the original template that was cloned. In
4151 *   this case, you can access the clone via the cloneAttachFn:
4152 *   <pre>
4153 *     var templateHTML = angular.element('<p>{{total}}</p>'),
4154 *         scope = ....;
4155 *
4156 *     var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
4157 *       //attach the clone to DOM document at the right place
4158 *     });
4159 *
4160 *     //now we have reference to the cloned DOM via `clone`
4161 *   </pre>
4162 *
4163 *
4164 * For information on how the compiler works, see the
4165 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
4166 */
4167
4168var $compileMinErr = minErr('$compile');
4169
4170/**
4171 * @ngdoc service
4172 * @name ng.$compileProvider
4173 * @function
4174 *
4175 * @description
4176 */
4177$CompileProvider.$inject = ['$provide'];
4178function $CompileProvider($provide) {
4179  var hasDirectives = {},
4180      Suffix = 'Directive',
4181      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
4182      CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
4183      aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/,
4184      imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
4185
4186  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
4187  // The assumption is that future DOM event attribute names will begin with
4188  // 'on' and be composed of only English letters.
4189  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]*|formaction)$/;
4190
4191  /**
4192   * @ngdoc function
4193   * @name ng.$compileProvider#directive
4194   * @methodOf ng.$compileProvider
4195   * @function
4196   *
4197   * @description
4198   * Register a new directive with the compiler.
4199   *
4200   * @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
4201   *                <code>ng-bind</code>).
4202   * @param {function|Array} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
4203   *                info.
4204   * @returns {ng.$compileProvider} Self for chaining.
4205   */
4206   this.directive = function registerDirective(name, directiveFactory) {
4207    if (isString(name)) {
4208      assertArg(directiveFactory, 'directiveFactory');
4209      if (!hasDirectives.hasOwnProperty(name)) {
4210        hasDirectives[name] = [];
4211        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
4212          function($injector, $exceptionHandler) {
4213            var directives = [];
4214            forEach(hasDirectives[name], function(directiveFactory) {
4215              try {
4216                var directive = $injector.invoke(directiveFactory);
4217                if (isFunction(directive)) {
4218                  directive = { compile: valueFn(directive) };
4219                } else if (!directive.compile && directive.link) {
4220                  directive.compile = valueFn(directive.link);
4221                }
4222                directive.priority = directive.priority || 0;
4223                directive.name = directive.name || name;
4224                directive.require = directive.require || (directive.controller && directive.name);
4225                directive.restrict = directive.restrict || 'A';
4226                directives.push(directive);
4227              } catch (e) {
4228                $exceptionHandler(e);
4229              }
4230            });
4231            return directives;
4232          }]);
4233      }
4234      hasDirectives[name].push(directiveFactory);
4235    } else {
4236      forEach(name, reverseParams(registerDirective));
4237    }
4238    return this;
4239  };
4240
4241
4242  /**
4243   * @ngdoc function
4244   * @name ng.$compileProvider#aHrefSanitizationWhitelist
4245   * @methodOf ng.$compileProvider
4246   * @function
4247   *
4248   * @description
4249   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
4250   * urls during a[href] sanitization.
4251   *
4252   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
4253   *
4254   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
4255   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
4256   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
4257   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
4258   *
4259   * @param {RegExp=} regexp New regexp to whitelist urls with.
4260   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
4261   *    chaining otherwise.
4262   */
4263  this.aHrefSanitizationWhitelist = function(regexp) {
4264    if (isDefined(regexp)) {
4265      aHrefSanitizationWhitelist = regexp;
4266      return this;
4267    }
4268    return aHrefSanitizationWhitelist;
4269  };
4270
4271
4272  /**
4273   * @ngdoc function
4274   * @name ng.$compileProvider#imgSrcSanitizationWhitelist
4275   * @methodOf ng.$compileProvider
4276   * @function
4277   *
4278   * @description
4279   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
4280   * urls during img[src] sanitization.
4281   *
4282   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
4283   *
4284   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into an
4285   * absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` regular
4286   * expression. If a match is found, the original url is written into the dom. Otherwise, the
4287   * absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
4288   *
4289   * @param {RegExp=} regexp New regexp to whitelist urls with.
4290   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
4291   *    chaining otherwise.
4292   */
4293  this.imgSrcSanitizationWhitelist = function(regexp) {
4294    if (isDefined(regexp)) {
4295      imgSrcSanitizationWhitelist = regexp;
4296      return this;
4297    }
4298    return imgSrcSanitizationWhitelist;
4299  };
4300
4301
4302  this.$get = [
4303            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
4304            '$controller', '$rootScope', '$document', '$sce', '$$urlUtils', '$animate',
4305    function($injector,   $interpolate,   $exceptionHandler,   $http,   $templateCache,   $parse,
4306             $controller,   $rootScope,   $document,   $sce,   $$urlUtils, $animate) {
4307
4308    var Attributes = function(element, attr) {
4309      this.$$element = element;
4310      this.$attr = attr || {};
4311    };
4312
4313    Attributes.prototype = {
4314      $normalize: directiveNormalize,
4315
4316
4317      /**
4318       * @ngdoc function
4319       * @name ng.$compile.directive.Attributes#$addClass
4320       * @methodOf ng.$compile.directive.Attributes
4321       * @function
4322       *
4323       * @description
4324       * Adds the CSS class value specified by the classVal parameter to the element. If animations
4325       * are enabled then an animation will be triggered for the class addition.
4326       *
4327       * @param {string} classVal The className value that will be added to the element
4328       */
4329      $addClass : function(classVal) {
4330        if(classVal && classVal.length > 0) {
4331          $animate.addClass(this.$$element, classVal);
4332        }
4333      },
4334
4335      /**
4336       * @ngdoc function
4337       * @name ng.$compile.directive.Attributes#$removeClass
4338       * @methodOf ng.$compile.directive.Attributes
4339       * @function
4340       *
4341       * @description
4342       * Removes the CSS class value specified by the classVal parameter from the element. If animations
4343       * are enabled then an animation will be triggered for the class removal.
4344       *
4345       * @param {string} classVal The className value that will be removed from the element
4346       */
4347      $removeClass : function(classVal) {
4348        if(classVal && classVal.length > 0) {
4349          $animate.removeClass(this.$$element, classVal);
4350        }
4351      },
4352
4353      /**
4354       * Set a normalized attribute on the element in a way such that all directives
4355       * can share the attribute. This function properly handles boolean attributes.
4356       * @param {string} key Normalized key. (ie ngAttribute)
4357       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
4358       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
4359       *     Defaults to true.
4360       * @param {string=} attrName Optional none normalized name. Defaults to key.
4361       */
4362      $set: function(key, value, writeAttr, attrName) {
4363        //special case for class attribute addition + removal
4364        //so that class changes can tap into the animation
4365        //hooks provided by the $animate service
4366        if(key == 'class') {
4367          value = value || '';
4368          var current = this.$$element.attr('class') || '';
4369          this.$removeClass(tokenDifference(current, value).join(' '));
4370          this.$addClass(tokenDifference(value, current).join(' '));
4371        } else {
4372          var booleanKey = getBooleanAttrName(this.$$element[0], key),
4373              normalizedVal,
4374              nodeName;
4375
4376          if (booleanKey) {
4377            this.$$element.prop(key, value);
4378            attrName = booleanKey;
4379          }
4380
4381          this[key] = value;
4382
4383          // translate normalized key to actual key
4384          if (attrName) {
4385            this.$attr[key] = attrName;
4386          } else {
4387            attrName = this.$attr[key];
4388            if (!attrName) {
4389              this.$attr[key] = attrName = snake_case(key, '-');
4390            }
4391          }
4392
4393          nodeName = nodeName_(this.$$element);
4394
4395          // sanitize a[href] and img[src] values
4396          if ((nodeName === 'A' && key === 'href') ||
4397              (nodeName === 'IMG' && key === 'src')) {
4398            // NOTE: $$urlUtils.resolve() doesn't support IE < 8 so we don't sanitize for that case.
4399            if (!msie || msie >= 8 ) {
4400              normalizedVal = $$urlUtils.resolve(value);
4401              if (normalizedVal !== '') {
4402                if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
4403                    (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
4404                  this[key] = value = 'unsafe:' + normalizedVal;
4405                }
4406              }
4407            }
4408          }
4409
4410          if (writeAttr !== false) {
4411            if (value === null || value === undefined) {
4412              this.$$element.removeAttr(attrName);
4413            } else {
4414              this.$$element.attr(attrName, value);
4415            }
4416          }
4417        }
4418
4419        // fire observers
4420        var $$observers = this.$$observers;
4421        $$observers && forEach($$observers[key], function(fn) {
4422          try {
4423            fn(value);
4424          } catch (e) {
4425            $exceptionHandler(e);
4426          }
4427        });
4428
4429        function tokenDifference(str1, str2) {
4430          var values = [],
4431              tokens1 = str1.split(/\s+/),
4432              tokens2 = str2.split(/\s+/);
4433
4434          outer:
4435          for(var i=0;i<tokens1.length;i++) {
4436            var token = tokens1[i];
4437            for(var j=0;j<tokens2.length;j++) {
4438              if(token == tokens2[j]) continue outer;
4439            }
4440            values.push(token);
4441          }
4442          return values;
4443        };
4444      },
4445
4446
4447      /**
4448       * Observe an interpolated attribute.
4449       * The observer will never be called, if given attribute is not interpolated.
4450       *
4451       * @param {string} key Normalized key. (ie ngAttribute) .
4452       * @param {function(*)} fn Function that will be called whenever the attribute value changes.
4453       * @returns {function(*)} the `fn` Function passed in.
4454       */
4455      $observe: function(key, fn) {
4456        var attrs = this,
4457            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
4458            listeners = ($$observers[key] || ($$observers[key] = []));
4459
4460        listeners.push(fn);
4461        $rootScope.$evalAsync(function() {
4462          if (!listeners.$$inter) {
4463            // no one registered attribute interpolation function, so lets call it manually
4464            fn(attrs[key]);
4465          }
4466        });
4467        return fn;
4468      }
4469    };
4470
4471    var urlSanitizationNode = $document[0].createElement('a'),
4472        startSymbol = $interpolate.startSymbol(),
4473        endSymbol = $interpolate.endSymbol(),
4474        denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
4475            ? identity
4476            : function denormalizeTemplate(template) {
4477              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
4478        },
4479        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
4480
4481
4482    return compile;
4483
4484    //================================
4485
4486    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective) {
4487      if (!($compileNodes instanceof jqLite)) {
4488        // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
4489        $compileNodes = jqLite($compileNodes);
4490      }
4491      // We can not compile top level text elements since text nodes can be merged and we will
4492      // not be able to attach scope data to them, so we will wrap them in <span>
4493      forEach($compileNodes, function(node, index){
4494        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
4495          $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
4496        }
4497      });
4498      var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority, ignoreDirective);
4499      return function publicLinkFn(scope, cloneConnectFn){
4500        assertArg(scope, 'scope');
4501        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
4502        // and sometimes changes the structure of the DOM.
4503        var $linkNode = cloneConnectFn
4504          ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
4505          : $compileNodes;
4506
4507        // Attach scope only to non-text nodes.
4508        for(var i = 0, ii = $linkNode.length; i<ii; i++) {
4509          var node = $linkNode[i];
4510          if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
4511            $linkNode.eq(i).data('$scope', scope);
4512          }
4513        }
4514        safeAddClass($linkNode, 'ng-scope');
4515        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
4516        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
4517        return $linkNode;
4518      };
4519    }
4520
4521    function safeAddClass($element, className) {
4522      try {
4523        $element.addClass(className);
4524      } catch(e) {
4525        // ignore, since it means that we are trying to set class on
4526        // SVG element, where class name is read-only.
4527      }
4528    }
4529
4530    /**
4531     * Compile function matches each node in nodeList against the directives. Once all directives
4532     * for a particular node are collected their compile functions are executed. The compile
4533     * functions return values - the linking functions - are combined into a composite linking
4534     * function, which is the a linking function for the node.
4535     *
4536     * @param {NodeList} nodeList an array of nodes or NodeList to compile
4537     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
4538     *        scope argument is auto-generated to the new child of the transcluded parent scope.
4539     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
4540     *        rootElement must be set the jqLite collection of the compile root. This is
4541     *        needed so that the jqLite collection items can be replaced with widgets.
4542     * @param {number=} max directive priority
4543     * @returns {?function} A composite linking function of all of the matched directives or null.
4544     */
4545    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective) {
4546      var linkFns = [],
4547          nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
4548
4549      for(var i = 0; i < nodeList.length; i++) {
4550        attrs = new Attributes();
4551
4552        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
4553        directives = collectDirectives(nodeList[i], [], attrs, i == 0 ? maxPriority : undefined, ignoreDirective);
4554
4555        nodeLinkFn = (directives.length)
4556            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement)
4557            : null;
4558
4559        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
4560            ? null
4561            : compileNodes(nodeList[i].childNodes,
4562                 nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
4563
4564        linkFns.push(nodeLinkFn);
4565        linkFns.push(childLinkFn);
4566        linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
4567      }
4568
4569      // return a linking function if we have found anything, null otherwise
4570      return linkFnFound ? compositeLinkFn : null;
4571
4572      function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
4573        var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
4574
4575        // copy nodeList so that linking doesn't break due to live list updates.
4576        var stableNodeList = [];
4577        for (i = 0, ii = nodeList.length; i < ii; i++) {
4578          stableNodeList.push(nodeList[i]);
4579        }
4580
4581        for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
4582          node = stableNodeList[n];
4583          nodeLinkFn = linkFns[i++];
4584          childLinkFn = linkFns[i++];
4585
4586          if (nodeLinkFn) {
4587            if (nodeLinkFn.scope) {
4588              childScope = scope.$new(isObject(nodeLinkFn.scope));
4589              jqLite(node).data('$scope', childScope);
4590            } else {
4591              childScope = scope;
4592            }
4593            childTranscludeFn = nodeLinkFn.transclude;
4594            if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
4595              nodeLinkFn(childLinkFn, childScope, node, $rootElement,
4596                  (function(transcludeFn) {
4597                    return function(cloneFn) {
4598                      var transcludeScope = scope.$new();
4599                      transcludeScope.$$transcluded = true;
4600
4601                      return transcludeFn(transcludeScope, cloneFn).
4602                          on('$destroy', bind(transcludeScope, transcludeScope.$destroy));
4603                    };
4604                  })(childTranscludeFn || transcludeFn)
4605              );
4606            } else {
4607              nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
4608            }
4609          } else if (childLinkFn) {
4610            childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
4611          }
4612        }
4613      }
4614    }
4615
4616
4617    /**
4618     * Looks for directives on the given node and adds them to the directive collection which is
4619     * sorted.
4620     *
4621     * @param node Node to search.
4622     * @param directives An array to which the directives are added to. This array is sorted before
4623     *        the function returns.
4624     * @param attrs The shared attrs object which is used to populate the normalized attributes.
4625     * @param {number=} maxPriority Max directive priority.
4626     */
4627    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
4628      var nodeType = node.nodeType,
4629          attrsMap = attrs.$attr,
4630          match,
4631          className;
4632
4633      switch(nodeType) {
4634        case 1: /* Element */
4635          // use the node name: <directive>
4636          addDirective(directives,
4637              directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
4638
4639          // iterate over the attributes
4640          for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
4641                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
4642            var attrStartName;
4643            var attrEndName;
4644            var index;
4645
4646            attr = nAttrs[j];
4647            if (!msie || msie >= 8 || attr.specified) {
4648              name = attr.name;
4649              // support ngAttr attribute binding
4650              ngAttrName = directiveNormalize(name);
4651              if (NG_ATTR_BINDING.test(ngAttrName)) {
4652                name = ngAttrName.substr(6).toLowerCase();
4653              }
4654              if ((index = ngAttrName.lastIndexOf('Start')) != -1 && index == ngAttrName.length - 5) {
4655                attrStartName = name;
4656                attrEndName = name.substr(0, name.length - 5) + 'end';
4657                name = name.substr(0, name.length - 6);
4658              }
4659              nName = directiveNormalize(name.toLowerCase());
4660              attrsMap[nName] = name;
4661              attrs[nName] = value = trim((msie && name == 'href')
4662                ? decodeURIComponent(node.getAttribute(name, 2))
4663                : attr.value);
4664              if (getBooleanAttrName(node, nName)) {
4665                attrs[nName] = true; // presence means true
4666              }
4667              addAttrInterpolateDirective(node, directives, value, nName);
4668              addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, attrEndName);
4669            }
4670          }
4671
4672          // use class as directive
4673          className = node.className;
4674          if (isString(className) && className !== '') {
4675            while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
4676              nName = directiveNormalize(match[2]);
4677              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
4678                attrs[nName] = trim(match[3]);
4679              }
4680              className = className.substr(match.index + match[0].length);
4681            }
4682          }
4683          break;
4684        case 3: /* Text Node */
4685          addTextInterpolateDirective(directives, node.nodeValue);
4686          break;
4687        case 8: /* Comment */
4688          try {
4689            match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
4690            if (match) {
4691              nName = directiveNormalize(match[1]);
4692              if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
4693                attrs[nName] = trim(match[2]);
4694              }
4695            }
4696          } catch (e) {
4697            // turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
4698            // Just ignore it and continue. (Can't seem to reproduce in test case.)
4699          }
4700          break;
4701      }
4702
4703      directives.sort(byPriority);
4704      return directives;
4705    }
4706
4707    /**
4708     * Given a node with an directive-start it collects all of the siblings until it find directive-end.
4709     * @param node
4710     * @param attrStart
4711     * @param attrEnd
4712     * @returns {*}
4713     */
4714    function groupScan(node, attrStart, attrEnd) {
4715      var nodes = [];
4716      var depth = 0;
4717      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
4718        var startNode = node;
4719        do {
4720          if (!node) {
4721            throw $compileMinErr('uterdir', "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd);
4722          }
4723          if (node.nodeType == 1 /** Element **/) {
4724            if (node.hasAttribute(attrStart)) depth++;
4725            if (node.hasAttribute(attrEnd)) depth--;
4726          }
4727          nodes.push(node);
4728          node = node.nextSibling;
4729        } while (depth > 0);
4730      } else {
4731        nodes.push(node);
4732      }
4733      return jqLite(nodes);
4734    }
4735
4736    /**
4737     * Wrapper for linking function which converts normal linking function into a grouped
4738     * linking function.
4739     * @param linkFn
4740     * @param attrStart
4741     * @param attrEnd
4742     * @returns {Function}
4743     */
4744    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
4745      return function(scope, element, attrs, controllers) {
4746        element = groupScan(element[0], attrStart, attrEnd);
4747        return linkFn(scope, element, attrs, controllers);
4748      }
4749    }
4750
4751    /**
4752     * Once the directives have been collected, their compile functions are executed. This method
4753     * is responsible for inlining directive templates as well as terminating the application
4754     * of the directives if the terminal directive has been reached.
4755     *
4756     * @param {Array} directives Array of collected directives to execute their compile function.
4757     *        this needs to be pre-sorted by priority order.
4758     * @param {Node} compileNode The raw DOM node to apply the compile functions to
4759     * @param {Object} templateAttrs The shared attribute function
4760     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
4761     *        scope argument is auto-generated to the new child of the transcluded parent scope.
4762     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
4763     *        argument has the root jqLite array so that we can replace nodes on it.
4764     * @returns linkFn
4765     */
4766    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection, originalReplaceDirective) {
4767      var terminalPriority = -Number.MAX_VALUE,
4768          preLinkFns = [],
4769          postLinkFns = [],
4770          newScopeDirective = null,
4771          newIsolateScopeDirective = null,
4772          templateDirective = null,
4773          $compileNode = templateAttrs.$$element = jqLite(compileNode),
4774          directive,
4775          directiveName,
4776          $template,
4777          transcludeDirective,
4778          replaceDirective = originalReplaceDirective,
4779          childTranscludeFn = transcludeFn,
4780          controllerDirectives,
4781          linkFn,
4782          directiveValue;
4783
4784      // executes all directives on the current element
4785      for(var i = 0, ii = directives.length; i < ii; i++) {
4786        directive = directives[i];
4787        var attrStart = directive.$$start;
4788        var attrEnd = directive.$$end;
4789
4790        // collect multiblock sections
4791        if (attrStart) {
4792          $compileNode = groupScan(compileNode, attrStart, attrEnd)
4793        }
4794        $template = undefined;
4795
4796        if (terminalPriority > directive.priority) {
4797          break; // prevent further processing of directives
4798        }
4799
4800        if (directiveValue = directive.scope) {
4801          assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
4802          if (isObject(directiveValue)) {
4803            safeAddClass($compileNode, 'ng-isolate-scope');
4804            newIsolateScopeDirective = directive;
4805          }
4806          safeAddClass($compileNode, 'ng-scope');
4807          newScopeDirective = newScopeDirective || directive;
4808        }
4809
4810        directiveName = directive.name;
4811
4812        if (directiveValue = directive.controller) {
4813          controllerDirectives = controllerDirectives || {};
4814          assertNoDuplicate("'" + directiveName + "' controller",
4815              controllerDirectives[directiveName], directive, $compileNode);
4816          controllerDirectives[directiveName] = directive;
4817        }
4818
4819        if (directiveValue = directive.transclude) {
4820          assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
4821          transcludeDirective = directive;
4822          terminalPriority = directive.priority;
4823          if (directiveValue == 'element') {
4824            $template = groupScan(compileNode, attrStart, attrEnd)
4825            $compileNode = templateAttrs.$$element =
4826                jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
4827            compileNode = $compileNode[0];
4828            replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
4829
4830            childTranscludeFn = compile($template, transcludeFn, terminalPriority,
4831                                        replaceDirective && replaceDirective.name);
4832          } else {
4833            $template = jqLite(JQLiteClone(compileNode)).contents();
4834            $compileNode.html(''); // clear contents
4835            childTranscludeFn = compile($template, transcludeFn);
4836          }
4837        }
4838
4839        if (directive.template) {
4840          assertNoDuplicate('template', templateDirective, directive, $compileNode);
4841          templateDirective = directive;
4842
4843          directiveValue = (isFunction(directive.template))
4844              ? directive.template($compileNode, templateAttrs)
4845              : directive.template;
4846
4847          directiveValue = denormalizeTemplate(directiveValue);
4848
4849          if (directive.replace) {
4850            replaceDirective = directive;
4851            $template = jqLite('<div>' +
4852                                 trim(directiveValue) +
4853                               '</div>').contents();
4854            compileNode = $template[0];
4855
4856            if ($template.length != 1 || compileNode.nodeType !== 1) {
4857              throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}", directiveName, '');
4858            }
4859
4860            replaceWith(jqCollection, $compileNode, compileNode);
4861
4862            var newTemplateAttrs = {$attr: {}};
4863
4864            // combine directives from the original node and from the template:
4865            // - take the array of directives for this element
4866            // - split it into two parts, those that were already applied and those that weren't
4867            // - collect directives from the template, add them to the second group and sort them
4868            // - append the second group with new directives to the first group
4869            directives = directives.concat(
4870                collectDirectives(
4871                    compileNode,
4872                    directives.splice(i + 1, directives.length - (i + 1)),
4873                    newTemplateAttrs
4874                )
4875            );
4876            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
4877
4878            ii = directives.length;
4879          } else {
4880            $compileNode.html(directiveValue);
4881          }
4882        }
4883
4884        if (directive.templateUrl) {
4885          assertNoDuplicate('template', templateDirective, directive, $compileNode);
4886          templateDirective = directive;
4887
4888          if (directive.replace) {
4889            replaceDirective = directive;
4890          }
4891          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i),
4892              nodeLinkFn, $compileNode, templateAttrs, jqCollection, childTranscludeFn);
4893          ii = directives.length;
4894        } else if (directive.compile) {
4895          try {
4896            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
4897            if (isFunction(linkFn)) {
4898              addLinkFns(null, linkFn, attrStart, attrEnd);
4899            } else if (linkFn) {
4900              addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
4901            }
4902          } catch (e) {
4903            $exceptionHandler(e, startingTag($compileNode));
4904          }
4905        }
4906
4907        if (directive.terminal) {
4908          nodeLinkFn.terminal = true;
4909          terminalPriority = Math.max(terminalPriority, directive.priority);
4910        }
4911
4912      }
4913
4914      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
4915      nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
4916
4917      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
4918      return nodeLinkFn;
4919
4920      ////////////////////
4921
4922      function addLinkFns(pre, post, attrStart, attrEnd) {
4923        if (pre) {
4924          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
4925          pre.require = directive.require;
4926          preLinkFns.push(pre);
4927        }
4928        if (post) {
4929          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
4930          post.require = directive.require;
4931          postLinkFns.push(post);
4932        }
4933      }
4934
4935
4936      function getControllers(require, $element) {
4937        var value, retrievalMethod = 'data', optional = false;
4938        if (isString(require)) {
4939          while((value = require.charAt(0)) == '^' || value == '?') {
4940            require = require.substr(1);
4941            if (value == '^') {
4942              retrievalMethod = 'inheritedData';
4943            }
4944            optional = optional || value == '?';
4945          }
4946          value = $element[retrievalMethod]('$' + require + 'Controller');
4947          if (!value && !optional) {
4948            throw $compileMinErr('ctreq', "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName);
4949          }
4950          return value;
4951        } else if (isArray(require)) {
4952          value = [];
4953          forEach(require, function(require) {
4954            value.push(getControllers(require, $element));
4955          });
4956        }
4957        return value;
4958      }
4959
4960
4961      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
4962        var attrs, $element, i, ii, linkFn, controller;
4963
4964        if (compileNode === linkNode) {
4965          attrs = templateAttrs;
4966        } else {
4967          attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
4968        }
4969        $element = attrs.$$element;
4970
4971        if (newIsolateScopeDirective) {
4972          var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
4973
4974          var parentScope = scope.$parent || scope;
4975
4976          forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
4977            var match = definition.match(LOCAL_REGEXP) || [],
4978                attrName = match[3] || scopeName,
4979                optional = (match[2] == '?'),
4980                mode = match[1], // @, =, or &
4981                lastValue,
4982                parentGet, parentSet;
4983
4984            scope.$$isolateBindings[scopeName] = mode + attrName;
4985
4986            switch (mode) {
4987
4988              case '@': {
4989                attrs.$observe(attrName, function(value) {
4990                  scope[scopeName] = value;
4991                });
4992                attrs.$$observers[attrName].$$scope = parentScope;
4993                if( attrs[attrName] ) {
4994                  // If the attribute has been provided then we trigger an interpolation to ensure the value is there for use in the link fn
4995                  scope[scopeName] = $interpolate(attrs[attrName])(parentScope);
4996                }
4997                break;
4998              }
4999
5000              case '=': {
5001                if (optional && !attrs[attrName]) {
5002                  return;
5003                }
5004                parentGet = $parse(attrs[attrName]);
5005                parentSet = parentGet.assign || function() {
5006                  // reset the change, or we will throw this exception on every $digest
5007                  lastValue = scope[scopeName] = parentGet(parentScope);
5008                  throw $compileMinErr('nonassign', "Expression '{0}' used with directive '{1}' is non-assignable!",
5009                      attrs[attrName], newIsolateScopeDirective.name);
5010                };
5011                lastValue = scope[scopeName] = parentGet(parentScope);
5012                scope.$watch(function parentValueWatch() {
5013                  var parentValue = parentGet(parentScope);
5014
5015                  if (parentValue !== scope[scopeName]) {
5016                    // we are out of sync and need to copy
5017                    if (parentValue !== lastValue) {
5018                      // parent changed and it has precedence
5019                      lastValue = scope[scopeName] = parentValue;
5020                    } else {
5021                      // if the parent can be assigned then do so
5022                      parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
5023                    }
5024                  }
5025                  return parentValue;
5026                });
5027                break;
5028              }
5029
5030              case '&': {
5031                parentGet = $parse(attrs[attrName]);
5032                scope[scopeName] = function(locals) {
5033                  return parentGet(parentScope, locals);
5034                };
5035                break;
5036              }
5037
5038              default: {
5039                throw $compileMinErr('iscp', "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}",
5040                    newIsolateScopeDirective.name, scopeName, definition);
5041              }
5042            }
5043          });
5044        }
5045
5046        if (controllerDirectives) {
5047          forEach(controllerDirectives, function(directive) {
5048            var locals = {
5049              $scope: scope,
5050              $element: $element,
5051              $attrs: attrs,
5052              $transclude: boundTranscludeFn
5053            }, controllerInstance;
5054
5055            controller = directive.controller;
5056            if (controller == '@') {
5057              controller = attrs[directive.name];
5058            }
5059
5060            controllerInstance = $controller(controller, locals);
5061            $element.data(
5062                '$' + directive.name + 'Controller',
5063                controllerInstance);
5064            if (directive.controllerAs) {
5065              locals.$scope[directive.controllerAs] = controllerInstance;
5066            }
5067          });
5068        }
5069
5070        // PRELINKING
5071        for(i = 0, ii = preLinkFns.length; i < ii; i++) {
5072          try {
5073            linkFn = preLinkFns[i];
5074            linkFn(scope, $element, attrs,
5075                linkFn.require && getControllers(linkFn.require, $element));
5076          } catch (e) {
5077            $exceptionHandler(e, startingTag($element));
5078          }
5079        }
5080
5081        // RECURSION
5082        childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
5083
5084        // POSTLINKING
5085        for(i = 0, ii = postLinkFns.length; i < ii; i++) {
5086          try {
5087            linkFn = postLinkFns[i];
5088            linkFn(scope, $element, attrs,
5089                linkFn.require && getControllers(linkFn.require, $element));
5090          } catch (e) {
5091            $exceptionHandler(e, startingTag($element));
5092          }
5093        }
5094      }
5095    }
5096
5097
5098    /**
5099     * looks up the directive and decorates it with exception handling and proper parameters. We
5100     * call this the boundDirective.
5101     *
5102     * @param {string} name name of the directive to look up.
5103     * @param {string} location The directive must be found in specific format.
5104     *   String containing any of theses characters:
5105     *
5106     *   * `E`: element name
5107     *   * `A': attribute
5108     *   * `C`: class
5109     *   * `M`: comment
5110     * @returns true if directive was added.
5111     */
5112    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName) {
5113      if (name === ignoreDirective) return null;
5114      var match = null;
5115      if (hasDirectives.hasOwnProperty(name)) {
5116        for(var directive, directives = $injector.get(name + Suffix),
5117            i = 0, ii = directives.length; i<ii; i++) {
5118          try {
5119            directive = directives[i];
5120            if ( (maxPriority === undefined || maxPriority > directive.priority) &&
5121                 directive.restrict.indexOf(location) != -1) {
5122              if (startAttrName) {
5123                directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
5124              }
5125              tDirectives.push(directive);
5126              match = directive;
5127            }
5128          } catch(e) { $exceptionHandler(e); }
5129        }
5130      }
5131      return match;
5132    }
5133
5134
5135    /**
5136     * When the element is replaced with HTML template then the new attributes
5137     * on the template need to be merged with the existing attributes in the DOM.
5138     * The desired effect is to have both of the attributes present.
5139     *
5140     * @param {object} dst destination attributes (original DOM)
5141     * @param {object} src source attributes (from the directive template)
5142     */
5143    function mergeTemplateAttributes(dst, src) {
5144      var srcAttr = src.$attr,
5145          dstAttr = dst.$attr,
5146          $element = dst.$$element;
5147
5148      // reapply the old attributes to the new element
5149      forEach(dst, function(value, key) {
5150        if (key.charAt(0) != '$') {
5151          if (src[key]) {
5152            value += (key === 'style' ? ';' : ' ') + src[key];
5153          }
5154          dst.$set(key, value, true, srcAttr[key]);
5155        }
5156      });
5157
5158      // copy the new attributes on the old attrs object
5159      forEach(src, function(value, key) {
5160        if (key == 'class') {
5161          safeAddClass($element, value);
5162          dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
5163        } else if (key == 'style') {
5164          $element.attr('style', $element.attr('style') + ';' + value);
5165        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
5166          dst[key] = value;
5167          dstAttr[key] = srcAttr[key];
5168        }
5169      });
5170    }
5171
5172
5173    function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs,
5174        $rootElement, childTranscludeFn) {
5175      var linkQueue = [],
5176          afterTemplateNodeLinkFn,
5177          afterTemplateChildLinkFn,
5178          beforeTemplateCompileNode = $compileNode[0],
5179          origAsyncDirective = directives.shift(),
5180          // The fact that we have to copy and patch the directive seems wrong!
5181          derivedSyncDirective = extend({}, origAsyncDirective, {
5182            controller: null, templateUrl: null, transclude: null, scope: null, replace: null
5183          }),
5184          templateUrl = (isFunction(origAsyncDirective.templateUrl))
5185              ? origAsyncDirective.templateUrl($compileNode, tAttrs
5185)
5186              : origAsyncDirective.templateUrl;
5187
5188      $compileNode.html('');
5189
5190      $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
5191        success(function(content) {
5192          var compileNode, tempTemplateAttrs, $template;
5193
5194          content = denormalizeTemplate(content);
5195
5196          if (origAsyncDirective.replace) {
5197            $template = jqLite('<div>' + trim(content) + '</div>').contents();
5198            compileNode = $template[0];
5199
5200            if ($template.length != 1 || compileNode.nodeType !== 1) {
5201              throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}",
5202                  origAsyncDirective.name, templateUrl);
5203            }
5204
5205            tempTemplateAttrs = {$attr: {}};
5206            replaceWith($rootElement, $compileNode, compileNode);
5207            collectDirectives(compileNode, directives, tempTemplateAttrs);
5208            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
5209          } else {
5210            compileNode = beforeTemplateCompileNode;
5211            $compileNode.html(content);
5212          }
5213
5214          directives.unshift(derivedSyncDirective);
5215
5216          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn, $compileNode, origAsyncDirective);
5217          forEach($rootElement, function(node, i) {
5218            if (node == compileNode) {
5219              $rootElement[i] = $compileNode[0];
5220            }
5221          });
5222          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
5223
5224
5225          while(linkQueue.length) {
5226            var scope = linkQueue.shift(),
5227                beforeTemplateLinkNode = linkQueue.shift(),
5228                linkRootElement = linkQueue.shift(),
5229                controller = linkQueue.shift(),
5230                linkNode = $compileNode[0];
5231
5232            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
5233              // it was cloned therefore we have to clone as well.
5234              linkNode = JQLiteClone(compileNode);
5235              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
5236            }
5237
5238            afterTemplateNodeLinkFn(
5239              beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller),
5240              scope, linkNode, $rootElement, controller
5241            );
5242          }
5243          linkQueue = null;
5244        }).
5245        error(function(response, code, headers, config) {
5246          throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
5247        });
5248
5249      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
5250        if (linkQueue) {
5251          linkQueue.push(scope);
5252          linkQueue.push(node);
5253          linkQueue.push(rootElement);
5254          linkQueue.push(controller);
5255        } else {
5256          afterTemplateNodeLinkFn(function() {
5257            beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
5258          }, scope, node, rootElement, controller);
5259        }
5260      };
5261    }
5262
5263
5264    /**
5265     * Sorting function for bound directives.
5266     */
5267    function byPriority(a, b) {
5268      return b.priority - a.priority;
5269    }
5270
5271
5272    function assertNoDuplicate(what, previousDirective, directive, element) {
5273      if (previousDirective) {
5274        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
5275            previousDirective.name, directive.name, what, startingTag(element));
5276      }
5277    }
5278
5279
5280    function addTextInterpolateDirective(directives, text) {
5281      var interpolateFn = $interpolate(text, true);
5282      if (interpolateFn) {
5283        directives.push({
5284          priority: 0,
5285          compile: valueFn(function textInterpolateLinkFn(scope, node) {
5286            var parent = node.parent(),
5287                bindings = parent.data('$binding') || [];
5288            bindings.push(interpolateFn);
5289            safeAddClass(parent.data('$binding', bindings), 'ng-binding');
5290            scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
5291              node[0].nodeValue = value;
5292            });
5293          })
5294        });
5295      }
5296    }
5297
5298
5299    function getTrustedContext(node, attrNormalizedName) {
5300      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
5301      if (attrNormalizedName == "xlinkHref" ||
5302          (nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
5303                                        attrNormalizedName == "ngSrc"))) {
5304        return $sce.RESOURCE_URL;
5305      }
5306    }
5307
5308
5309    function addAttrInterpolateDirective(node, directives, value, name) {
5310      var interpolateFn = $interpolate(value, true);
5311
5312      // no interpolation found -> ignore
5313      if (!interpolateFn) return;
5314
5315
5316      if (name === "multiple" && nodeName_(node) === "SELECT") {
5317        throw $compileMinErr("selmulti", "Binding to the 'multiple' attribute is not supported. Element: {0}",
5318            startingTag(node));
5319      }
5320
5321      directives.push({
5322        priority: 100,
5323        compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
5324          var $$observers = (attr.$$observers || (attr.$$observers = {}));
5325
5326          if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
5327            throw $compileMinErr('nodomevents',
5328                "Interpolations for HTML DOM event attributes are disallowed.  Please use the ng- " +
5329                "versions (such as ng-click instead of onclick) instead.");
5330          }
5331
5332          // we need to interpolate again, in case the attribute value has been updated
5333          // (e.g. by another directive's compile function)
5334          interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
5335
5336          // if attribute was updated so that there is no interpolation going on we don't want to
5337          // register any observers
5338          if (!interpolateFn) return;
5339
5340          attr[name] = interpolateFn(scope);
5341          ($$observers[name] || ($$observers[name] = [])).$$inter = true;
5342          (attr.$$observers && attr.$$observers[name].$$scope || scope).
5343            $watch(interpolateFn, function interpolateFnWatchAction(value) {
5344              attr.$set(name, value);
5345            });
5346        })
5347      });
5348    }
5349
5350
5351    /**
5352     * This is a special jqLite.replaceWith, which can replace items which
5353     * have no parents, provided that the containing jqLite collection is provided.
5354     *
5355     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
5356     *    in the root of the tree.
5357     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep the shell,
5358     *    but replace its DOM node reference.
5359     * @param {Node} newNode The new DOM node.
5360     */
5361    function replaceWith($rootElement, elementsToRemove, newNode) {
5362      var firstElementToRemove = elementsToRemove[0],
5363          removeCount = elementsToRemove.length,
5364          parent = firstElementToRemove.parentNode,
5365          i, ii;
5366
5367      if ($rootElement) {
5368        for(i = 0, ii = $rootElement.length; i < ii; i++) {
5369          if ($rootElement[i] == firstElementToRemove) {
5370            $rootElement[i++] = newNode;
5371            for (var j = i, j2 = j + removeCount - 1,
5372                     jj = $rootElement.length;
5373                 j < jj; j++, j2++) {
5374              if (j2 < jj) {
5375                $rootElement[j] = $rootElement[j2];
5376              } else {
5377                delete $rootElement[j];
5378              }
5379            }
5380            $rootElement.length -= removeCount - 1;
5381            break;
5382          }
5383        }
5384      }
5385
5386      if (parent) {
5387        parent.replaceChild(newNode, firstElementToRemove);
5388      }
5389      var fragment = document.createDocumentFragment();
5390      fragment.appendChild(firstElementToRemove);
5391      newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
5392      for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
5393        var element = elementsToRemove[k];
5394        jqLite(element).remove(); // must do this way to clean up expando
5395        fragment.appendChild(element);
5396        delete elementsToRemove[k];
5397      }
5398
5399      elementsToRemove[0] = newNode;
5400      elementsToRemove.length = 1
5401    }
5402  }];
5403}
5404
5405var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
5406/**
5407 * Converts all accepted directives format into proper directive name.
5408 * All of these will become 'myDirective':
5409 *   my:Directive
5410 *   my-directive
5411 *   x-my-directive
5412 *   data-my:directive
5413 *
5414 * Also there is special case for Moz prefix starting with upper case letter.
5415 * @param name Name to normalize
5416 */
5417function directiveNormalize(name) {
5418  return camelCase(name.replace(PREFIX_REGEXP, ''));
5419}
5420
5421/**
5422 * @ngdoc object
5423 * @name ng.$compile.directive.Attributes
5424 * @description
5425 *
5426 * A shared object between directive compile / linking functions which contains 
5426normalized DOM element
5427 * attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
5428 * since all of these are treated as equivalent in Angular:
5429 *
5430 *          <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
5431 */
5432
5433/**
5434 * @ngdoc property
5435 * @name ng.$compile.directive.Attributes#$attr
5436 * @propertyOf ng.$compile.directive.Attributes
5437 * @returns {object} A map of DOM element attribute names to the normalized name. This is
5438 *          needed to do reverse lookup from normalized name back to actual name.
5439 */
5440
5441
5442/**
5443 * @ngdoc function
5444 * @name ng.$compile.directive.Attributes#$set
5445 * @methodOf ng.$compile.directive.Attributes
5446 * @function
5447 *
5448 * @description
5449 * Set DOM element attribute value.
5450 *
5451 *
5452 * @param {string} name Normalized element attribute name of the property to modify. The name is
5453 *          revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
5454 *          property to the original name.
5455 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
5456 */
5457
5458
5459
5460/**
5461 * Closure compiler type information
5462 */
5463
5464function nodesetLinkingFn(
5465  /* angular.Scope */ scope,
5466  /* NodeList */ nodeList,
5467  /* Element */ rootElement,
5468  /* function(Function) */ boundTranscludeFn
5469){}
5470
5471function directiveLinkingFn(
5472  /* nodesetLinkingFn */ nodesetLinkingFn,
5473  /* angular.Scope */ scope,
5474  /* Node */ node,
5475  /* Element */ rootElement,
5476  /* function(Function) */ boundTranscludeFn
5477){}
5478
5479/**
5480 * @ngdoc object
5481 * @name ng.$controllerProvider
5482 * @description
5483 * The {@link ng.$controller $controller service} is used by Angular to create new
5484 * controllers.
5485 *
5486 * This provider allows controller registration via the
5487 * {@link ng.$controllerProvider#register register} method.
5488 */
5489function $ControllerProvider() {
5490  var controllers = {},
5491      CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
5492
5493
5494  /**
5495   * @ngdoc function
5496   * @name ng.$controllerProvider#register
5497   * @methodOf ng.$controllerProvider
5498   * @param {string} name Controller name
5499   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
5500   *    annotations in the array notation).
5501   */
5502  this.register = function(name, constructor) {
5503    if (isObject(name)) {
5504      extend(controllers, name)
5505    } else {
5506      controllers[name] = constructor;
5507    }
5508  };
5509
5510
5511  this.$get = ['$injector', '$window', function($injector, $window) {
5512
5513    /**
5514     * @ngdoc function
5515     * @name ng.$controller
5516     * @requires $injector
5517     *
5518     * @param {Function|string} constructor If called with a function then it's considered to be the
5519     *    controller constructor function. Otherwise it's considered to be a string which is used
5520     *    to retrieve the controller constructor using the following steps:
5521     *
5522     *    * check if a controller with given name is registered via `$controllerProvider`
5523     *    * check if evaluating the string on the current scope returns a constructor
5524     *    * check `window[constructor]` on the global `window` object
5525     *
5526     * @param {Object} locals Injection locals for Controller.
5527     * @return {Object} Instance of given controller.
5528     *
5529     * @description
5530     * `$controller` service is responsible for instantiating controllers.
5531     *
5532     * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
5533     * a service, so that one can override this service with {@link https://gist.github.com/1649788
5534     * BC version}.
5535     */
5536    return function(expression, locals) {
5537      var instance, match, constructor, identifier;
5538
5539      if(isString(expression)) {
5540        match = expression.match(CNTRL_REG),
5541        constructor = match[1],
5542        identifier = match[3];
5543        expression = controllers.hasOwnProperty(constructor)
5544            ? controllers[constructor]
5545            : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
5546
5547        assertArgFn(expression, constructor, true);
5548      }
5549
5550      instance = $injector.instantiate(expression, locals);
5551
5552      if (identifier) {
5553        if (!(locals && typeof locals.$scope == 'object')) {
5554          throw minErr('$controller')('noscp', "Cannot export controller '{0}' as '{1}
5554'! No $scope object provided via `locals`.", constructor || expression.name, identifier);
5555        }
5556
5557        locals.$scope[identifier] = instance;
5558      }
5559
5560      return instance;
5561    };
5562  }];
5563}
5564
5565/**
5566 * @ngdoc object
5567 * @name ng.$document
5568 * @requires $window
5569 *
5570 * @description
5571 * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
5572 * element.
5573 */
5574function $DocumentProvider(){
5575  this.$get = ['$window', function(window){
5576    return jqLite(window.document);
5577  }];
5578}
5579
5580/**
5581 * @ngdoc function
5582 * @name ng.$exceptionHandler
5583 * @requires $log
5584 *
5585 * @description
5586 * Any uncaught exception in angular expressions is delegated to this service.
5587 * The default implementation simply delegates to `$log.error` which logs it into
5588 * the browser console.
5589 *
5590 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
5591 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
5592 *
5593 * @param {Error} exception Exception associated with the error.
5594 * @param {string=} cause optional information about the context in which
5595 *       the error was thrown.
5596 *
5597 */
5598function $ExceptionHandlerProvider() {
5599  this.$get = ['$log', function($log) {
5600    return function(exception, cause) {
5601      $log.error.apply($log, arguments);
5602    };
5603  }];
5604}
5605
5606/**
5607 * Parse headers into key value object
5608 *
5609 * @param {string} headers Raw headers as a string
5610 * @returns {Object} Parsed headers as key value object
5611 */
5612function parseHeaders(headers) {
5613  var parsed = {}, key, val, i;
5614
5615  if (!headers) return parsed;
5616
5617  forEach(headers.split('\n'), function(line) {
5618    i = line.indexOf(':');
5619    key = lowercase(trim(line.substr(0, i)));
5620    val = trim(line.substr(i + 1));
5621
5622    if (key) {
5623      if (parsed[key]) {
5624        parsed[key] += ', ' + val;
5625      } else {
5626        parsed[key] = val;
5627      }
5628    }
5629  });
5630
5631  return parsed;
5632}
5633
5634
5635/**
5636 * Returns a function that provides access to parsed headers.
5637 *
5638 * Headers are lazy parsed when first requested.
5639 * @see parseHeaders
5640 *
5641 * @param {(string|Object)} headers Headers to provide access to.
5642 * @returns {function(string=)} Returns a getter function which if called with:
5643 *
5644 *   - if called with single an argument returns a single header value or null
5645 *   - if called with no arguments returns an object containing all headers.
5646 */
5647function headersGetter(headers) {
5648  var headersObj = isObject(headers) ? headers : undefined;
5649
5650  return function(name) {
5651    if (!headersObj) headersObj =  parseHeaders(headers);
5652
5653    if (name) {
5654      return headersObj[lowercase(name)] || null;
5655    }
5656
5657    return headersObj;
5658  };
5659}
5660
5661
5662/**
5663 * Chain all given functions
5664 *
5665 * This function is used for both request and response transforming
5666 *
5667 * @param {*} data Data to transform.
5668 * @param {function(string=)} headers Http headers getter fn.
5669 * @param {(function|Array.<function>)} fns Function or an array of functions.
5670 * @returns {*} Transformed data.
5671 */
5672function transformData(data, headers, fns) {
5673  if (isFunction(fns))
5674    return fns(data, headers);
5675
5676  forEach(fns, function(fn) {
5677    data = fn(data, headers);
5678  });
5679
5680  return data;
5681}
5682
5683
5684function isSuccess(status) {
5685  return 200 <= status && status < 300;
5686}
5687
5688
5689function $HttpProvider() {
5690  var JSON_START = /^\s*(\[|\{[^\{])/,
5691      JSON_END = /[\}\]]\s*$/,
5692      PROTECTION_PREFIX = /^\)\]\}',?\n/,
5693      CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
5694
5695  var defaults = this.defaults = {
5696    // transform incoming response data
5697    transformResponse: [function(data) {
5698      if (isString(data)) {
5699        // strip json vulnerability protection prefix
5700        data = data.replace(PROTECTION_PREFIX, '');
5701        if (JSON_START.test(data) && JSON_END.test(data))
5702          data = fromJson(data, true);
5703      }
5704      return data;
5705    }],
5706
5707    // transform outgoing request data
5708    transformRequest: [function(d) {
5709      return isObject(d) && !isFile(d) ? toJson(d) : d;
5710    }],
5711
5712    // default headers
5713    headers: {
5714      common: {
5715        'Accept': 'application/json, text/plain, */*'
5716      },
5717      post:   CONTENT_TYPE_APPLICATION_JSON,
5718      put:    CONTENT_TYPE_APPLICATION_JSON,
5719      patch:  CONTENT_TYPE_APPLICATION_JSON
5720    },
5721
5722    xsrfCookieName: 'XSRF-TOKEN',
5723    xsrfHeaderName: 'X-XSRF-TOKEN'
5724  };
5725
5726  /**
5727   * Are order by request. I.E. they are applied in the same order as
5728   * array on request, but revers order on response.
5729   */
5730  var interceptorFactories = this.interceptors = [];
5731  /**
5732   * For historical reasons, response interceptors ordered by the order in which
5733   * they are applied to response. (This is in revers to interceptorFactories)
5734   */
5735  var responseInterceptorFactories = this.responseInterceptors = [];
5736
5737  this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', '$$urlUtils',
5738      function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector, $$urlUtils) {
5739
5740    var defaultCache = $cacheFactory('$http');
5741
5742    /**
5743     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
5744     * The reversal is needed so that we can build up the interception chain around the
5745     * server request.
5746     */
5747    var reversedInterceptors = [];
5748
5749    forEach(interceptorFactories, function(interceptorFactory) {
5750      reversedInterceptors.unshift(isString(interceptorFactory)
5751          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
5752    });
5753
5754    forEach(responseInterceptorFactories, function(interceptorFactory, index) {
5755      var responseFn = isString(interceptorFactory)
5756          ? $injector.get(interceptorFactory)
5757          : $injector.invoke(interceptorFactory);
5758
5759      /**
5760       * Response interceptors go before "around" interceptors (no real reason, just
5761       * had to pick one.) But they are already reversed, so we can't use unshift, hence
5762       * the splice.
5763       */
5764      reversedInterceptors.splice(index, 0, {
5765        response: function(response) {
5766          return responseFn($q.when(response));
5767        },
5768        responseError: function(response) {
5769          return responseFn($q.reject(response));
5770        }
5771      });
5772    });
5773
5774
5775    /**
5776     * @ngdoc function
5777     * @name ng.$http
5778     * @requires $httpBackend
5779     * @requires $browser
5780     * @requires $cacheFactory
5781     * @requires $rootScope
5782     * @requires $q
5783     * @requires $injector
5784     *
5785     * @description
5786     * The `$http` service is a core Angular service that facilitates communication with the remote
5787     * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
5788     * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
5789     *
5790     * For unit testing applications that use `$http` service, see
5791     * {@link ngMock.$httpBackend $httpBackend mock}.
5792     *
5793     * For a higher level of abstraction, please check out the {@link ngResource.$resource
5794     * $resource} service.
5795     *
5796     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
5797     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
5798     * it is important to familiarize yourself with these APIs and the guarantees they provide.
5799     *
5800     *
5801     * # General usage
5802     * The `$http` service is a function which takes a single argument — a configuration object —
5803     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
5804     * with two $http specific methods: `success` and `error`.
5805     *
5806     * <pre>
5807     *   $http({method: 'GET', url: '/someUrl'}).
5808     *     success(function(data, status, headers, config) {
5809     *       // this callback will be called asynchronously
5810     *       // when the response is available
5811     *     }).
5812     *     error(function(data, status, headers, config) {
5813     *       // called asynchronously if an error occurs
5814     *       // or server returns response with an error status.
5815     *     });
5816     * </pre>
5817     *
5818     * Since the returned value of calling the $http function is a `promise`, you can also use
5819     * the `then` method to register callbacks, and these callbacks will receive a single argument –
5820     * an object representing the response. See the API signature and type info below for more
5821     * details.
5822     *
5823     * A response status code between 200 and 299 is considered a success status and
5824     * will result in the success callback being called. Note that if the response is a redirect,
5825     * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
5826     * called for such responses.
5827     *
5828     * # Shortcut methods
5829     *
5830     * Since all invocations of the $http service require passing in an HTTP method and URL, and
5831     * POST/PUT requests require request data to be provided as well, shortcut methods
5832     * were created:
5833     *
5834     * <pre>
5835     *   $http.get('/someUrl').success(successCallback);
5836     *   $http.post('/someUrl', data).success(successCallback);
5837     * </pre>
5838     *
5839     * Complete list of shortcut methods:
5840     *
5841     * - {@link ng.$http#get $http.get}
5842     * - {@link ng.$http#head $http.head}
5843     * - {@link ng.$http#post $http.post}
5844     * - {@link ng.$http#put $http.put}
5845     * - {@link ng.$http#delete $http.delete}
5846     * - {@link ng.$http#jsonp $http.jsonp}
5847     *
5848     *
5849     * # Setting HTTP Headers
5850     *
5851     * The $http service will automatically add certain HTTP headers to all requests. These defaults
5852     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
5853     * object, which currently contains this default configuration:
5854     *
5855     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
5856     *   - `Accept: application/json, text/plain, * / *`
5857     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
5858     *   - `Content-Type: application/json`
5859     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
5860     *   - `Content-Type: application/json`
5861     *
5862     * To add or overwrite these defaults, simply add or remove a property from these configuration
5863     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
5864     * with the lowercased HTTP method name as the key, e.g.
5865     * `$httpProvider.defaults.headers.get['My-Header']='value'`.
5866     *
5867     * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
5868     * fashion.
5869     *
5870     *
5871     * # Transforming Requests and Responses
5872     *
5873     * Both requests and responses can be transformed using transform functions. By default, Angular
5874     * applies these transformations:
5875     *
5876     * Request transformations:
5877     *
5878     * - If the `data` property of the request configuration object c
5878ontains an object, serialize it into
5879     *   JSON format.
5880     *
5881     * Response transformations:
5882     *
5883     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
5884     *  - If JSON response is detected, deserialize it using a JSON parser.
5885     *
5886     * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
5887     * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
5888     * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
5889     * transformation chain. You can also decide to completely override any default transformations by assigning your
5890     * transformation functions to these properties directly without the array wrapper.
5891     *
5892     * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
5893     * `transformResponse` properties of the configuration object passed into `$http`.
5894     *
5895     *
5896     * # Caching
5897     *
5898     * To enable caching, set the configuration property `cache` to `true`. When the cache is
5899     * enabled, `$http` stores the response from the server in local cache. Next time the
5900     * response is served from the cache without sending a request to the server.
5901     *
5902     * Note that even if the response is served from cache, delivery of the data is asynchronous in
5903     * the same way that real requests are.
5904     *
5905     * If there are multiple GET requests for the same URL that should be cached using the same
5906     * cache, but the cache is not populated yet, only one request to the server will be made and
5907     * the remaining requests will be fulfilled using the response from the first request.
5908     *
5909     * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
5910     * To skip it, set configuration property `cache` to `false`.
5911     *
5912     *
5913     * # Interceptors
5914     *
5915     * Before you start creating interceptors, be sure to understand the
5916     * {@link ng.$q $q and deferred/promise APIs}.
5917     *
5918     * For purposes of global error handling, authentication, or any kind of synchronous or
5919     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
5920     * able to intercept requests before they are handed to the server and
5921     * responses before they are handed over to the application code that
5922     * initiated these requests. The interceptors leverage the {@link ng.$q
5923     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
5924     *
5925     * The interceptors are service factories that are registered with the `$httpProvider` by
5926     * adding them to the `$httpProvider.interceptors` array. The factory is called and
5927     * injected with dependencies (if specified) and returns the interceptor.
5928     *
5929     * There are two kinds of interceptors (and two kinds of rejection interceptors):
5930     *
5931     *   * `request`: interceptors get called with http `config` object. The function is free to modify
5932     *     the `config` or create a new one. The function needs to return the `config` directly or as a
5933     *     promise.
5934     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or resolved
5935     *      with a rejection.
5936     *   * `response`: interceptors get called with http `response` object. The function is free to modify
5937     *     the `response` or create a new one. The function needs to return the `response` directly or as a
5938     *     promise.
5939     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or resolved
5940     *      with a rejection.
5941     *
5942     *
5943     * <pre>
5944     *   // register the interceptor as a service
5945     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
5946     *     return {
5947     *       // optional method
5948     *       'request': function(config) {
5949     *         // do something on success
5950     *         return config || $q.when(config);
5951     *       },
5952     *
5953     *       // optional method
5954     *      'requestError': function(rejection) {
5955     *         // do something on error
5956     *         if (canRecover(rejection)) {
5957     *           return responseOrNewPromise
5958     *         }
5959     *         return $q.reject(rejection);
5960     *       },
5961     *
5962     *
5963     *
5964     *       // optional method
5965     *       'response': function(response) {
5966     *         // do something on success
5967     *         return response || $q.when(response);
5968     *       },
5969     *
5970     *       // optional method
5971     *      'responseError': function(rejection) {
5972     *         // do something on error
5973     *         if (canRecover(rejection)) {
5974     *           return responseOrNewPromise
5975     *         }
5976     *         return $q.reject(rejection);
5977     *       };
5978     *     }
5979     *   });
5980     *
5981     *   $httpProvider.interceptors.push('myHttpInterceptor');
5982     *
5983     *
5984     *   // register the interceptor via an anonymous factory
5985     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
5986     *     return {
5987     *      'request': function(config) {
5988     *          // same as above
5989     *       },
5990     *       'response': function(response) {
5991     *          // same as above
5992     *       }
5993     *   });
5994     * </pre>
5995     *
5996     * # Response interceptors (DEPRECATED)
5997     *
5998     * Before you start creating interceptors, be sure to understand the
5999     * {@link ng.$q $q and deferred/promise APIs}.
6000     *
6001     * For purposes of global error handling, authentication or any kind of synchronous or
6002     * asynchronous preprocessing of received responses, it is desirable to be able to intercept
6003     * responses for http requests before they are handed over to the application code that
6004     * initiated these requests. The response interceptors leverage the {@link ng.$q
6005     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
6006     *
6007     * The interceptors are service factories that are registered with the $httpProvider by
6008     * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
6009     * injected with dependencies (if specified) and returns the interceptor  — a function that
6010     * takes a {@link ng.$q promise} and returns the original or a new promise.
6011     *
6012     * <pre>
6013     *   // register the interceptor as a service
6014     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
6015     *     return function(promise) {
6016     *       return promise.then(function(response) {
6017     *         // do something on success
6018     *       }, function(response) {
6019     *         // do something on error
6020     *         if (canRecover(response)) {
6021     *           return responseOrNewPromise
6022     *         }
6023     *         return $q.reject(response);
6024     *       });
6025     *     }
6026     *   });
6027     *
6028     *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
6029     *
6030     *
6031     *   // register the interceptor via an anonymous factory
6032     *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
6033     *     return function(promise) {
6034     *       // same as above
6035     *     }
6036     *   });
6037     * </pre>
6038     *
6039     *
6040     * # Security Considerations
6041     *
6042     * When designing web applications, consider security threats from:
6043     *
6044     * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
6045     *   JSON vulnerability}
6046     * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
6047     *
6048     * Both server and the client must cooperate in order to eliminate these threats. Angular comes
6049     * pre-configured with strategies that address these issues, but for this to work backend server
6050     * cooperation is required.
6051     *
6052     * ## JSON Vulnerability Protection
6053     *
6054     * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
6055     * JSON vulnerability} allows third party website to turn your JSON resource URL into
6056     * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
6057     * counter this your server can prefix all JSON requests with following str
6057ing `")]}',\n"`.
6058     * Angular will automatically strip the prefix before processing it as JSON.
6059     *
6060     * For example if your server needs to return:
6061     * <pre>
6062     * ['one','two']
6063     * </pre>
6064     *
6065     * which is vulnerable to attack, your server can return:
6066     * <pre>
6067     * )]}',
6068     * ['one','two']
6069     * </pre>
6070     *
6071     * Angular will strip the prefix, before processing the JSON.
6072     *
6073     *
6074     * ## Cross Site Request Forgery (XSRF) Protection
6075     *
6076     * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
6077     * an unauthorized site can gain your user's private data. Angular provides a mechanism
6078     * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
6079     * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
6080     * JavaScript that runs on your domain could read the cookie, your server can be assured that
6081     * the XHR came from JavaScript running on your domain. The header will not be set for
6082     * cross-domain requests.
6083     *
6084     * To take advantage of this, your server needs to set a token in a JavaScript readable session
6085     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
6086     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
6087     * that only JavaScript running on your domain could have sent the request. The token must be
6088     * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
6089     * up its own tokens). We recommend that the token is a digest of your site's authentication
6090     * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
6091     *
6092     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
6093     * properties of either $httpProvider.defaults, or the per-request config object.
6094     *
6095     *
6096     * @param {object} config Object describing the request to be made and how it should be
6097     *    processed. The object has following properties:
6098     *
6099     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
6100     *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
6101     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to
6102     *      `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
6103     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
6104     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
6105     *      HTTP headers to send to the server. If the return value of a function is null, the header will
6106     *      not be sent.
6107     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
6108     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
6109     *    - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
6110     *      transform function or an array of such functions. The transform function takes the http
6111     *      request body and headers and returns its transformed (typically serialized) version.
6112     *    - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
6113     *      transform function or an array of such functions. The transform function takes the http
6114     *      response body and headers and returns its transformed (typically deserialized) version.
6115     *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
6116     *      GET request, otherwise if a cache instance built with
6117     *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
6118     *      caching.
6119     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
6120     *      that should abort the request when resolved.
6121     *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
6122     *      XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
6123     *      requests with credentials} for more information.
6124     *    - **responseType** - `{string}` - see {@link
6125     *      https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
6126     *
6127     * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
6128     *   standard `then` method and two http specific methods: `success` and `error`. The `then`
6129     *   method takes two arguments a success and an error callback which will be called with a
6130     *   response object. The `success` and `error` methods take a single argument - a function that
6131     *   will be called when the request succeeds or fails respectively. The arguments passed into
6132     *   these functions are destructured representation of the response object passed into the
6133     *   `then` method. The response object has these properties:
6134     *
6135     *   - **data** – `{string|Object}` – The response body transformed with the transform functions.
6136     *   - **status** – `{number}` – HTTP status code of the response.
6137     *   - **headers** – `{function([headerName])}` – Header getter function.
6138     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
6139     *
6140     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
6141     *   requests. This is primarily meant to be used for debugging purposes.
6142     *
6143     *
6144     * @example
6145      <example>
6146        <file name="index.html">
6147          <div ng-controller="FetchCtrl">
6148            <select ng-model="method">
6149              <option>GET</option>
6150              <option>JSONP</option>
6151            </select>
6152            <input type="text" ng-model="url" size="80"/>
6153            <button ng-click="fetch()">fetch</button><br>
6154            <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
6155            <button ng-click="updateModel('JSONP', 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
6156            <button ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
6157            <pre>http status code: {{status}}</pre>
6158            <pre>http response data: {{data}}</pre>
6159          </div>
6160        </file>
6161        <file name="script.js">
6162          function FetchCtrl($scope, $http, $templateCache) {
6163            $scope.method = 'GET';
6164            $scope.url = 'http-hello.html';
6165
6166            $scope.fetch = function() {
6167              $scope.code = null;
6168              $scope.response = null;
6169
6170              $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
6171                success(function(data, status) {
6172                  $scope.status = status;
6173                  $scope.data = data;
6174                }).
6175                error(function(data, status) {
6176                  $scope.data = data || "Request failed";
6177                  $scope.status = status;
6178              });
6179            };
6180
6181            $scope.updateModel = function(method, url) {
6182              $scope.method = method;
6183              $scope.url = url;
6184            };
6185          }
6186        </file>
6187        <file name="http-hello.html">
6188          Hello, $http!
6189        </file>
6190        <file name="scenario.js">
6191          it('should make an xhr GET request', function() {
6192            element(':button:contains("Sample GET")').click();
6193            element(':button:contains("fetch")').click();
6194            expect(binding('status')).toBe('200');
6195            expect(binding('data')).toMatch(/Hello, \$http!/);
6196          });
6197
6198          it('should make a JSONP request to angularjs.org', function() {
6199            element(':button:contains("Sample JSONP")').click();
6200            element(':button:contains("fetch")').click();
6201            expect(binding('status')).toBe('200');
6202            expect(binding('data')).toMatch(/Super Hero!/);
6203          });
6204
6205          it('should make JSONP request to invalid URL and invoke the error handler',
6206              function() {
6207            element(':button:contains("Invalid JSONP")').click();
6208            element(':button:contains("fetch")').click();
6209            expect(binding('status')).toBe('0');
6210            expect(binding('data')).toBe('Request failed');
6211          });
6212        </file>
6213      </example>
6214     */
6215    function $http(requestConfig) {
6216      var config = {
6217        transformRequest: defaults.transformRequest,
6218        transformResponse: defaults.transformResponse
6219      };
6220      var headers = mergeHeaders(requestConfig);
6221
6222      extend(config, requestConfig);
6223      config.headers = headers;
6224      config.method = uppercase(config.method);
6225
6226      var xsrfValue = $$urlUtils.isSameOrigin(config.url)
6227          ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
6228          : undefined;
6229      if (xsrfValue) {
6230        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
6231      }
6232
6233
6234      var serverRequest = function(config) {
6235        headers = config.headers;
6236        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
6237
6238        // strip content-type if data is undefined
6239        if (isUndefined(config.data)) {
6240          forEach(headers, function(value, header) {
6241            if (lowercase(header) === 'content-type') {
6242                delete headers[header];
6243            }
6244          });
6245        }
6246
6247        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
6248          config.withCredentials = defaults.withCredentials;
6249        }
6250
6251        // send request
6252        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
6253      };
6254
6255      var chain = [serverRequest, undefined];
6256      var promise = $q.when(config);
6257
6258      // apply interceptors
6259      forEach(reversedInterceptors, function(interceptor) {
6260        if (interceptor.request || interceptor.requestError) {
6261          chain.unshift(interceptor.request, interceptor.requestError);
6262        }
6263        if (interceptor.response || interceptor.responseError) {
6264          chain.push(interceptor.response, interceptor.responseError);
6265        }
6266      });
6267
6268      while(chain.length) {
6269        var thenFn = chain.shift();
6270        var rejectFn = chain.shift();
6271
6272        promise = promise.then(thenFn, rejectFn);
6273      }
6274
6275      promise.success = function(fn) {
6276        promise.then(function(response) {
6277          fn(response.data, response.status, response.headers, config);
6278        });
6279        return promise;
6280      };
6281
6282      promise.error = function(fn) {
6283        promise.then(null, function(response) {
6284          fn(response.data, response.status, response.headers, config);
6285        });
6286        return promise;
6287      };
6288
6289      return promise;
6290
6291      function transformResponse(response) {
6292        // make a copy since the response must be cacheable
6293        var resp = extend({}, response, {
6294          data: transformData(response.data, response.headers, config.transformResponse)
6295        });
6296        return (isSuccess(response.status))
6297          ? resp
6298          : $q.reject(resp);
6299      }
6300
6301      function mergeHeaders(config) {
6302        var defHeaders = defaults.headers,
6303            reqHeaders = extend({}, config.headers),
6304            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
6305
6306        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
6307
6308        // execute if header value is function
6309        execHeaders(defHeaders);
6310        execHeaders(reqHeaders);
6311
6312        // using for-in instead of forEach to avoid unecessary iteration after header has been found
6313        defaultHeadersIteration:
6314        for (defHeaderName in defHeaders) {
6315          lowercaseDefHeaderName = lowercase(defHeaderName);
6316
6317          for (reqHeaderName in reqHeaders) {
6318            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
6319              continue defaultHeadersIteration;
6320            }
6321          }
6322
6323          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
6324        }
6325
6326        return reqHeaders;
6327
6328        function execHeaders(headers) {
6329          var headerContent;
6330
6331          forEach(headers, function(headerFn, header) {
6332            if (isFunction(headerFn)) {
6333              headerContent = headerFn();
6334              if (headerContent != null) {
6335                headers[header] = headerContent;
6336              } else {
6337                delete headers[header];
6338              }
6339            }
6340          });
6341        }
6342      }
6343    }
6344
6345    $http.pendingRequests = [];
6346
6347    /**
6348     * @ngdoc method
6349     * @name ng.$http#get
6350     * @methodOf ng.$http
6351     *
6352     * @description
6353     * Shortcut method to perform `GET` request.
6354     *
6355     * @param {string} url Relative or absolute URL specifying the destination of the request
6356     * @param {Object=} config Optional configuration object
6357     * @returns {HttpPromise} Future object
6358     */
6359
6360    /**
6361     * @ngdoc method
6362     * @name ng.$http#delete
6363     * @methodOf ng.$http
6364     *
6365     * @description
6366     * Shortcut method to perform `DELETE` request.
6367     *
6368     * @param {string} url Relative or absolute URL specifying the destination of the request
6369     * @param {Object=} config Optional configuration object
6370     * @returns {HttpPromise} Future object
6371     */
6372
6373    /**
6374     * @ngdoc method
6375     * @name ng.$http#head
6376     * @methodOf ng.$http
6377     *
6378     * @description
6379     * Shortcut method to perform `HEAD` request.
6380     *
6381     * @param {string} url Relative or absolute URL specifying the destination of the request
6382     * @param {Object=} config Optional configuration object
6383     * @returns {HttpPromise} Future object
6384     */
6385
6386    /**
6387     * @ngdoc method
6388     * @name ng.$http#jsonp
6389     * @methodOf ng.$http
6390     *
6391     * @description
6392     * Shortcut method to perform `JSONP` request.
6393     *
6394     * @param {string} url Relative or absolute URL specifying the destination of the request.
6395     *                     Should contain `JSON_CALLBACK` string.
6396     * @param {Object=} config Optional configuration object
6397     * @returns {HttpPromise} Future object
6398     */
6399    createShortMethods('get', 'delete', 'head', 'jsonp');
6400
6401    /**
6402     * @ngdoc method
6403     * @name ng.$http#post
6404     * @methodOf ng.$http
6405     *
6406     * @description
6407     * Shortcut method to perform `POST` request.
6408     *
6409     * @param {string} url Relative or absolute URL specifying the destination of the request
6410     * @param {*} data Request content
6411     * @param {Object=} config Optional configuration object
6412     * @returns {HttpPromise} Future object
6413     */
6414
6415    /**
6416     * @ngdoc method
6417     * @name ng.$http#put
6418     * @methodOf ng.$http
6419     *
6420     * @description
6421     * Shortcut method to perform `PUT` request.
6422     *
6423     * @param {string} url Relative or absolute URL specifying the destination of the request
6424     * @param {*} data Request content
6425     * @param {Object=} config Optional configuration object
6426     * @returns {HttpPromise} Future object
6427     */
6428    createShortMethodsWithData('post', 'put');
6429
6430        /**
6431         * @ngdoc property
6432         * @name ng.$http#defaults
6433         * @propertyOf ng.$http
6434         *
6435         * @description
6436         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
6437         * default headers, withCredentials as well as request and response transformations.
6438         *
6439         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
6440         */
6441    $http.defaults = defaults;
6442
6443
6444    return $http;
6445
6446
6447    function createShortMethods(names) {
6448      forEach(arguments, function(name) {
6449        $http[name] = function(url, config) {
6450          return $http(extend(config || {}, {
6451            method: name,
6452            url: url
6453          }));
6454        };
6455      });
6456    }
6457
6458
6459    function createShortMethodsWithData(name) {
6460      forEach(arguments, function(name) {
6461        $http[name] = function(url, data, config) {
6462          return $http(extend(config || {}, {
6463            method: name,
6464            url: url,
6465            data: data
6466          }));
6467        };
6468      });
6469    }
6470
6471
6472    /**
6473     * Makes the request.
6474     *
6475     * !!! ACCESSES CLOSURE VARS:
6476     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
6477     */
6478    function sendReq(config, reqData, reqHeaders) {
6479      var deferred = $q.defer(),
6480          promise = deferred.promise,
6481          cache,
6482          cachedResp,
6483          url = buildUrl(config.url, config.params);
6484
6485      $http.pendingRequests.push(config);
6486      promise.then(removePendingReq, removePendingReq);
6487
6488
6489      if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
6490        cache = isObject(config.cache) ? config.cache
6491              : isObject(defaults.cache) ? defaults.cache
6492              : defaultCache;
6493      }
6494
6495      if (cache) {
6496        cachedResp = cache.get(url);
6497        if (cachedResp) {
6498          if (cachedResp.then) {
6499            // cached request has already been sent, but there is no response yet
6500            cachedResp.then(removePendingReq, removePendingReq);
6501            return cachedResp;
6502          } else {
6503            // serving from cache
6504            if (isArray(cachedResp)) {
6505              resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
6506            } else {
6507              resolvePromise(cachedResp, 200, {});
6508            }
6509          }
6510        } else {
6511          // put the promise for the non-transformed response into cache as a placeholder
6512          cache.put(url, promise);
6513        }
6514      }
6515
6516      // if we won't have the response in cache, send the request to the backend
6517      if (!cachedResp) {
6518        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
6519            config.withCredentials, config.responseType);
6520      }
6521
6522      return promise;
6523
6524
6525      /**
6526       * Callback registered to $httpBackend():
6527       *  - caches the response if desired
6528       *  - resolves the raw $http promise
6529       *  - calls $apply
6530       */
6531      function done(status, response, headersString) {
6532        if (cache) {
6533          if (isSuccess(status)) {
6534            cache.put(url, [status, response, parseHeaders(headersString)]);
6535          } else {
6536            // remove promise from the cache
6537            cache.remove(url);
6538          }
6539        }
6540
6541        resolvePromise(response, status, headersString);
6542        if (!$rootScope.$$phase) $rootScope.$apply();
6543      }
6544
6545
6546      /**
6547       * Resolves the raw $http promise.
6548       */
6549      function resolvePromise(response, status, headers) {
6550        // normalize internal statuses to 0
6551        status = Math.max(status, 0);
6552
6553        (isSuccess(status) ? deferred.resolve : deferred.reject)({
6554          data: response,
6555          status: status,
6556          headers: headersGetter(headers),
6557          config: config
6558        });
6559      }
6560
6561
6562      function removePendingReq() {
6563        var idx = indexOf($http.pendingRequests, config);
6564        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
6565      }
6566    }
6567
6568
6569    function buildUrl(url, params) {
6570          if (!params) return url;
6571          var parts = [];
6572          forEachSorted(params, function(value, key) {
6573            if (value == null || value == undefined) return;
6574            if (!isArray(value)) value = [value];
6575
6576            forEach(value, function(v) {
6577              if (isObject(v)) {
6578                v = toJson(v);
6579              }
6580              parts.push(encodeUriQuery(key) + '=' +
6581                         encodeUriQuery(v));
6582            });
6583          });
6584          return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
6585        }
6586
6587
6588  }];
6589}
6590
6591var XHR = window.XMLHttpRequest || function() {
6592  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
6593  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
6594  try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
6595  throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
6596};
6597
6598
6599/**
6600 * @ngdoc object
6601 * @name ng.$httpBackend
6602 * @requires $browser
6603 * @requires $window
6604 * @requires $document
6605 *
6606 * @description
6607 * HTTP backend used by the {@link ng.$http service} that delegates to
6608 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
6609 *
6610 * You should never need to use this service directly, instead use the higher-level abstractions:
6611 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
6612 *
6613 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
6614 * $httpBackend} which can be trained with responses.
6615 */
6616function $HttpBackendProvider() {
6617  this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
6618    return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks,
6619        $document[0], $window.location.protocol.replace(':', ''));
6620  }];
6621}
6622
6623function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) {
6624  // TODO(vojta): fix the signature
6625  return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
6626    var status;
6627    $browser.$$incOutstandingRequestCount();
6628    url = url || $browser.url();
6629
6630    if (lowercase(method) == 'jsonp') {
6631      var callbackId = '_' + (callbacks.counter++).toString(36);
6632      callbacks[callbackId] = function(data) {
6633        callbacks[callbackId].data = data;
6634      };
6635
6636      var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
6637          function() {
6638        if (callbacks[callbackId].data) {
6639          completeRequest(callback, 200, callbacks[callbackId].data);
6640        } else {
6641          completeRequest(callback, status || -2);
6642        }
6643        delete callbacks[callbackId];
6644      });
6645    } else {
6646      var xhr = new XHR();
6647      xhr.open(method, url, true);
6648      forEach(headers, function(value, key) {
6649        if (value) xhr.setRequestHeader(key, value);
6650      });
6651
6652      // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
6653      // response is in the cache. the promise api will ensure that to the app code the api is
6654      // always async
6655      xhr.onreadystatechange = function() {
6656        if (xhr.readyState == 4) {
6657          var responseHeaders = xhr.getAllResponseHeaders();
6658
6659          // TODO(vojta): remove once Firefox 21 gets released.
6660          // begin: workaround to overcome Firefox CORS http response headers bug
6661          // https://bugzilla.mozilla.org/show_bug.cgi?id=608735
6662          // Firefox already patched in nightly. Should land in Firefox 21.
6663
6664          // CORS "simple response headers" http://www.w3.org/TR/cors/
6665          var value,
6666              simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type",
6667                                  "Expires", "Last-Modified", "Pragma"];
6668          if (!responseHeaders) {
6669            responseHeaders = "";
6670            forEach(simpleHeaders, function (header) {
6671              var value = xhr.getResponseHeader(header);
6672              if (value) {
6673                  responseHeaders += header + ": " + value + "\n";
6674              }
6675            });
6676          }
6677          // end of the workaround.
6678
6679          // responseText is the old-school way of retrieving response (supported by IE8 & 9)
6680          // response and responseType properties were introduced in XHR Level2 spec (supported by IE10)
6681          completeRequest(callback,
6682              status || xhr.status,
6683              (xhr.responseType ? xhr.response : xhr.responseText),
6684              responseHeaders);
6685        }
6686      };
6687
6688      if (withCredentials) {
6689        xhr.withCredentials = true;
6690      }
6691
6692      if (responseType) {
6693        xhr.responseType = responseType;
6694      }
6695
6696      xhr.send(post || '');
6697    }
6698
6699    if (timeout > 0) {
6700      var timeoutId = $browserDefer(timeoutRequest, timeout);
6701    } else if (timeout && timeout.then) {
6702      timeout.then(timeoutRequest);
6703    }
6704
6705
6706    function timeoutRequest() {
6707      status = -1;
6708      jsonpDone && jsonpDone();
6709      xhr && xhr.abort();
6710    }
6711
6712    function completeRequest(callback, status, response, headersString) {
6713      // URL_MATCH is defined in src/service/location.js
6714      var protocol = (url.match(SERVER_MATCH) || ['', locationProtocol])[1];
6715
6716      // cancel timeout and subsequent timeout promise resolution
6717      timeoutId && $browserDefer.cancel(timeoutId);
6718      jsonpDone = xhr = null;
6719
6720      // fix status code for file protocol (it's always 0)
6721      status = (protocol == 'file') ? (response ? 200 : 404) : status;
6722
6723      // normalize IE bug (http://bugs.jquery.com/ticket/1450)
6724      status = status == 1223 ? 204 : status;
6725
6726      callback(status, response, headersString);
6727      $browser.$$completeOutstandingRequest(noop);
6728    }
6729  };
6730
6731  function jsonpReq(url, done) {
6732    // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
6733    // - fetches local scripts via XHR and evals them
6734    // - adds and immediately removes script elements from the document
6735    var script = rawDocument.createElement('script'),
6736        doneWrapper = function() {
6737          rawDocument.body.removeChild(script);
6738          if (done) done();
6739        };
6740
6741    script.type = 'text/javascript';
6742    script.src = url;
6743
6744    if (msie) {
6745      script.onreadystatechange = function() {
6746        if (/loaded|complete/.test(script.readyState)) doneWrapper();
6747      };
6748    } else {
6749      script.onload = script.onerror = doneWrapper;
6750    }
6751
6752    rawDocument.body.appendChild(script);
6753    return doneWrapper;
6754  }
6755}
6756
6757var $interpolateMinErr = minErr('$interpolate');
6758
6759/**
6760 * @ngdoc object
6761 * @name ng.$interpolateProvider
6762 * @function
6763 *
6764 * @description
6765 *
6766 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
6767 * 
6768 * @example
6769   <doc:example>
6770     <doc:source>
6771      <script>
6772        var myApp = angular.module('App', [], function($interpolateProvider) {
6773          $interpolateProvider.startSymbol('//');
6774          $interpolateProvider.endSymbol('//');
6775        });
6776        function Controller($scope) {   
6777            $scope.label = "Interpolation Provider Sample";
6778        }
6779      </script>
6780      <div ng-app="App" ng-controller="Controller">
6781          //label//
6782      </div>
6783     </doc:source>
6784   </doc:example>
6785 */
6786function $InterpolateProvider() {
6787  var startSymbol = '{{';
6788  var endSymbol = '}}';
6789
6790  /**
6791   * @ngdoc method
6792   * @name ng.$interpolateProvider#startSymbol
6793   * @methodOf ng.$interpolateProvider
6794   * @description
6795   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
6796   *
6797   * @param {string=} value new value to set the starting symbol to.
6798   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
6799   */
6800  this.startSymbol = function(value){
6801    if (value) {
6802      startSymbol = value;
6803      return this;
6804    } else {
6805      return startSymbol;
6806    }
6807  };
6808
6809  /**
6810   * @ngdoc method
6811   * @name ng.$interpolateProvider#endSymbol
6812   * @methodOf ng.$interpolateProvider
6813   * @description
6814   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
6815   *
6816   * @param {string=} value new value to set the ending symbol to.
6817   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
6818   */
6819  this.endSymbol = function(value){
6820    if (value) {
6821      endSymbol = value;
6822      return this;
6823    } else {
6824      return endSymbol;
6825    }
6826  };
6827
6828
6829  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
6830    var startSymbolLength = startSymbol.length,
6831        endSymbolLength = endSymbol.length;
6832
6833    /**
6834     * @ngdoc function
6835     * @name ng.$interpolate
6836     * @function
6837     *
6838     * @requires $parse
6839     * @requires $sce
6840     *
6841     * @description
6842     *
6843     * Compiles a string with markup into an interpolation function. This service is used by the
6844     * HTML {@link ng.$compile $compile} service for data binding. See
6845     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
6846     * interpolation markup.
6847     *
6848     *
6849       <pre>
6850         var $interpolate = ...; // injected
6851         var exp = $interpolate('Hello {{name}}!');
6852         expect(exp({name:'Angular'}).toEqual('Hello Angular!');
6853       </pre>
6854     *
6855     *
6856     * @param {string} text The text with markup to interpolate.
6857     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
6858     *    embedded expression in order to return an interpolation function. Strings with no
6859     *    embedded expression will return null for the interpolation function.
6860     * @param {string=} trustedContext when provided, the returned function passes the interpolated
6861     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
6862     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
6863     *    provides Strict Contextual Escaping for details.
6864     * @returns {function(context)} an interpolation function which is used to compute the interpolated
6865     *    string. The function has these parameters:
6866     *
6867     *    * `context`: an object against which any expressions embedded in the strings are evaluated
6868     *      against.
6869     *
6870     */
6871    function $interpolate(text, mustHaveExpression, trustedContext) {
6872      var startIndex,
6873          endIndex,
6874          index = 0,
6875          parts = [],
6876          length = text.length,
6877          hasInterpolation = false,
6878          fn,
6879          exp,
6880          concat = [];
6881
6882      while(index < length) {
6883        if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
6884             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
6885          (index != startIndex) && parts.push(text.substring(index, startIndex));
6886          parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
6887          fn.exp = exp;
6888          index = endIndex + endSymbolLength;
6889          hasInterpolation = true;
6890        } else {
6891          // we did not find anything, so we have to add the remainder to the parts array
6892          (index != length) && parts.push(text.substring(index));
6893          index = length;
6894        }
6895      }
6896
6897      if (!(length = parts.length)) {
6898        // we added, nothing, must have been an empty string.
6899        parts.push('');
6900        length = 1;
6901      }
6902
6903      // Concatenating expressions makes it hard to reason about whether some combination of concatenated
6904      // values are unsafe to use and could easily lead to XSS.  By requiring that a single
6905      // expression be used for iframe[src], object[src], etc., we ensure that the value that's used
6906      // is assigned or constructed by some JS code somewhere that is more testable or make it
6907      // obvious that you bound the value to some user controlled value.  This helps reduce the load
6908      // when auditing for XSS issues.
6909      if (trustedContext && parts.length > 1) {
6910          throw $interpolateMinErr('noconcat',
6911              "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
6912              "interpolations that concatenate multiple expressions when a trusted value is " +
6913              "required.  See http://docs.angularjs.org/api/ng.$sce", text);
6914      }
6915
6916      if (!mustHaveExpression  || hasInterpolation) {
6917        concat.length = length;
6918        fn = function(context) {
6919          try {
6920            for(var i = 0, ii = length, part; i<ii; i++) {
6921              if (typeof (part = parts[i]) == 'function') {
6922                part = part(context);
6923                if (trustedContext) {
6924                  part = $sce.getTrusted(trustedContext, part);
6925                } else {
6926                  part = $sce.valueOf(part);
6927                }
6928                if (part == null || part == undefined) {
6929                  part = '';
6930                } else if (typeof part != 'string') {
6931                  part = toJson(part);
6932                }
6933              }
6934              concat[i] = part;
6935            }
6936            return concat.join('');
6937          }
6938          catch(err) {
6939            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
6940            $exceptionHandler(newErr);
6941          }
6942        };
6943        fn.exp = text;
6944        fn.parts = parts;
6945        return fn;
6946      }
6947    }
6948
6949
6950    /**
6951     * @ngdoc method
6952     * @name ng.$interpolate#startSymbol
6953     * @methodOf ng.$interpolate
6954     * @description
6955     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
6956     *
6957     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
6958     * the symbol.
6959     *
6960     * @returns {string} start symbol.
6961     */
6962    $interpolate.startSymbol = function() {
6963      return startSymbol;
6964    }
6965
6966
6967    /**
6968     * @ngdoc method
6969     * @name ng.$interpolate#endSymbol
6970     * @methodOf ng.$interpolate
6971     * @description
6972     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
6973     *
6974     * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
6975     * the symbol.
6976     *
6977     * @returns {string} start symbol.
6978     */
6979    $interpolate.endSymbol = function() {
6980      return endSymbol;
6981    }
6982
6983    return $interpolate;
6984  }];
6985}
6986
6987/**
6988 * @ngdoc object
6989 * @name ng.$locale
6990 *
6991 * @description
6992 * $locale service provides localization rules for various Angular components. As of right now the
6993 * only public api is:
6994 *
6995 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
6996 */
6997function $LocaleProvider(){
6998  this.$get = function() {
6999    return {
7000      id: 'en-us',
7001
7002      NUMBER_FORMATS: {
7003        DECIMAL_SEP: '.',
7004        GROUP_SEP: ',',
7005        PATTERNS: [
7006          { // Decimal Pattern
7007            minInt: 1,
7008            minFrac: 0,
7009            maxFrac: 3,
7010            posPre: '',
7011            posSuf: '',
7012            negPre: '-',
7013            negSuf: '',
7014            gSize: 3,
7015            lgSize: 3
7016          },{ //Currency Pattern
7017            minInt: 1,
7018            minFrac: 2,
7019            maxFrac: 2,
7020            posPre: '\u00A4',
7021            posSuf: '',
7022            negPre: '(\u00A4',
7023            negSuf: ')',
7024            gSize: 3,
7025            lgSize: 3
7026          }
7027        ],
7028        CURRENCY_SYM: '$'
7029      },
7030
7031      DATETIME_FORMATS: {
7032        MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
7033                .split(','),
7034        SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
7035        DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
7036        SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
7037        AMPMS: ['AM','PM'],
7038        medium: 'MMM d, y h:mm:ss a',
7039        short: 'M/d/yy h:mm a',
7040        fullDate: 'EEEE, MMMM d, y',
7041        longDate: 'MMMM d, y',
7042        mediumDate: 'MMM d, y',
7043        shortDate: 'M/d/yy',
7044        mediumTime: 'h:mm:ss a',
7045        shortTime: 'h:mm a'
7046      },
7047
7048      pluralCat: function(num) {
7049        if (num === 1) {
7050          return 'one';
7051        }
7052        return 'other';
7053      }
7054    };
7055  };
7056}
7057
7058var SERVER_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,
7059    PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
7060    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
7061var $locationMinErr = minErr('$location');
7062
7063
7064/**
7065 * Encode path using encodeUriSegment, ignoring forward slashes
7066 *
7067 * @param {string} path Path to encode
7068 * @returns {string}
7069 */
7070function encodePath(path) {
7071  var segments = path.split('/'),
7072      i = segments.length;
7073
7074  while (i--) {
7075    segments[i] = encodeUriSegment(segments[i]);
7076  }
7077
7078  return segments.join('/');
7079}
7080
7081function matchUrl(url, obj) {
7082  var match = SERVER_MATCH.exec(url);
7083
7084  obj.$$protocol = match[1];
7085  obj.$$host = match[3];
7086  obj.$$port = int(match[5]) || DEFAULT_PORTS[match[1]] || null;
7087}
7088
7089function matchAppUrl(url, obj) {
7090  var match = PATH_MATCH.exec(url);
7091
7092  obj.$$path = decodeURIComponent(match[1]);
7093  obj.$$search = parseKeyValue(match[3]);
7094  obj.$$hash = decodeURIComponent(match[5] || '');
7095
7096  // make sure path starts with '/';
7097  if (obj.$$path && obj.$$path.charAt(0) != '/') obj.$$path = '/' + obj.$$path;
7098}
7099
7100
7101function composeProtocolHostPort(protocol, host, port) {
7102  return protocol + '://' + host + (port == DEFAULT_PORTS[protocol] ? '' : ':' + port);
7103}
7104
7105/**
7106 *
7107 * @param {string} begin
7108 * @param {string} whole
7109 * @param {string} otherwise
7110 * @returns {string} returns text from whole after begin or otherwise if it does not begin with expected string.
7111 */
7112function beginsWith(begin, whole, otherwise) {
7113  return whole.indexOf(begin) == 0 ? whole.substr(begin.length) : otherwise;
7114}
7115
7116
7117function stripHash(url) {
7118  var index = url.indexOf('#');
7119  return index == -1 ? url : url.substr(0, index);
7120}
7121
7122
7123function stripFile(url) {
7124  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
7125}
7126
7127/* return the server only (scheme://host:port) */
7128function serverBase(url) {
7129  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
7130}
7131
7132
7133/**
7134 * LocationHtml5Url represents an url
7135 * This object is exposed as $location service when HTML5 mode is enabled and supported
7136 *
7137 * @constructor
7138 * @param {string} appBase application base URL
7139 * @param {string} basePrefix url path prefix
7140 */
7141function LocationHtml5Url(appBase, basePrefix) {
7142  this.$$html5 = true;
7143  basePrefix = basePrefix || '';
7144  var appBaseNoFile = stripFile(appBase);
7145  /**
7146   * Parse given html5 (regular) url string into properties
7147   * @param {string} newAbsoluteUrl HTML5 url
7148   * @private
7149   */
7150  this.$$parse = function(url) {
7151    var parsed = {}
7152    matchUrl(url, parsed);
7153    var pathUrl = beginsWith(appBaseNoFile, url);
7154    if (!isString(pathUrl)) {
7155      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile);
7156    }
7157    matchAppUrl(pathUrl, parsed);
7158    extend(this, parsed);
7159    if (!this.$$path) {
7160      this.$$path = '/';
7161    }
7162
7163    this.$$compose();
7164  };
7165
7166  /**
7167   * Compose url and update `absUrl` property
7168   * @private
7169   */
7170  this.$$compose = function() {
7171    var search = toKeyValue(this.$$search),
7172        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
7173
7174    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
7175    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
7176  };
7177
7178  this.$$rewrite = function(url) {
7179    var appUrl, prevAppUrl;
7180
7181    if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
7182      prevAppUrl = appUrl;
7183      if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
7184        return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
7185      } else {
7186        return appBase + prevAppUrl;
7187      }
7188    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
7189      return appBaseNoFile + appUrl;
7190    } else if (appBaseNoFile == url + '/') {
7191      return appBaseNoFile;
7192    }
7193  }
7194}
7195
7196
7197/**
7198 * LocationHashbangUrl represents url
7199 * This object is exposed as $location service when developer doesn't opt into html5 mode.
7200 * It also serves as the base class for html5 mode fallback on legacy browsers.
7201 *
7202 * @constructor
7203 * @param {string} appBase application base URL
7204 * @param {string} hashPrefix hashbang prefix
7205 */
7206function LocationHashbangUrl(appBase, hashPrefix) {
7207  var appBaseNoFile = stripFile(appBase);
7208
7209  matchUrl(appBase, this);
7210
7211
7212  /**
7213   * Parse given hashbang url into properties
7214   * @param {string} url Hashbang url
7215   * @private
7216   */
7217  this.$$parse = function(url) {
7218    var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
7219    var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
7220        ? beginsWith(hashPrefix, withoutBaseUrl)
7221        : (this.$$html5)
7222          ? withoutBaseUrl
7223          : '';
7224
7225    if (!isString(withoutHashUrl)) {
7226      throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix);
7227    }
7228    matchAppUrl(withoutHashUrl, this);
7229    this.$$compose();
7230  };
7231
7232  /**
7233   * Compose hashbang url and update `absUrl` property
7234   * @private
7235   */
7236  this.$$compose = function() {
7237    var search = toKeyValue(this.$$search),
7238        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
7239
7240    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
7241    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
7242  };
7243
7244  this.$$rewrite = function(url) {
7245    if(stripHash(appBase) == stripHash(url)) {
7246      return url;
7247    }
7248  }
7249}
7250
7251
7252/**
7253 * LocationHashbangUrl represents url
7254 * This object is exposed as $location service when html5 history api is enabled but the browser
7255 * does not support it.
7256 *
7257 * @constructor
7258 * @param {string} appBase application base URL
7259 * @param {string} hashPrefix hashbang prefix
7260 */
7261function LocationHashbangInHtml5Url(appBase, hashPrefix) {
7262  this.$$html5 = true;
7263  LocationHashbangUrl.apply(this, arguments);
7264
7265  var appBaseNoFile = stripFile(appBase);
7266
7267  this.$$rewrite = function(url) {
7268    var appUrl;
7269
7270    if ( appBase == stripHash(url) ) {
7271      return url;
7272    } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
7273      return appBase + hashPrefix + appUrl;
7274    } else if ( appBaseNoFile === url + '/') {
7275      return appBaseNoFile;
7276    }
7277  }
7278}
7279
7280
7281LocationHashbangInHtml5Url.prototype =
7282  LocationHashbangUrl.prototype =
7283  LocationHtml5Url.prototype = {
7284
7285  /**
7286   * Are we in html5 mode?
7287   * @private
7288   */
7289  $$html5: false,
7290
7291  /**
7292   * Has any change been replacing ?
7293   * @private
7294   */
7295  $$replace: false,
7296
7297  /**
7298   * @ngdoc method
7299   * @name ng.$location#absUrl
7300   * @methodOf ng.$location
7301   *
7302   * @description
7303   * This method is getter only.
7304   *
7305   * Return full url representation with all segments encoded according to rules specified in
7306   * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
7307   *
7308   * @return {string} full url
7309   */
7310  absUrl: locationGetter('$$absUrl'),
7311
7312  /**
7313   * @ngdoc method
7314   * @name ng.$location#url
7315   * @methodOf ng.$location
7316   *
7317   * @description
7318   * This method is getter / setter.
7319   *
7320   * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
7321   *
7322   * Change path, search and hash, when called with parameter and return `$location`.
7323   *
7324   * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
7325   * @param {string=} replace The path that will be changed
7326   * @return {string} url
7327   */
7328  url: function(url, replace) {
7329    if (isUndefined(url))
7330      return this.$$url;
7331
7332    var match = PATH_MATCH.exec(url);
7333    if (match[1]) this.path(decodeURIComponent(match[1]));
7334    if (match[2] || match[1]) this.search(match[3] || '');
7335    this.hash(match[5] || '', replace);
7336
7337    return this;
7338  },
7339
7340  /**
7341   * @ngdoc method
7342   * @name ng.$location#protocol
7343   * @methodOf ng.$location
7344   *
7345   * @description
7346   * This method is getter only.
7347   *
7348   * Return protocol of current url.
7349   *
7350   * @return {string} protocol of current url
7351   */
7352  protocol: locationGetter('$$protocol'),
7353
7354  /**
7355   * @ngdoc method
7356   * @name ng.$location#host
7357   * @methodOf ng.$location
7358   *
7359   * @description
7360   * This method is getter only.
7361   *
7362   * Return host of current url.
7363   *
7364   * @return {string} host of current url.
7365   */
7366  host: locationGetter('$$host'),
7367
7368  /**
7369   * @ngdoc method
7370   * @name ng.$location#port
7371   * @methodOf ng.$location
7372   *
7373   * @description
7374   * This method is getter only.
7375   *
7376   * Return port of current url.
7377   *
7378   * @return {Number} port
7379   */
7380  port: locationGetter('$$port'),
7381
7382  /**
7383   * @ngdoc method
7384   * @name ng.$location#path
7385   * @methodOf ng.$location
7386   *
7387   * @description
7388   * This method is getter / setter.
7389   *
7390   * Return path of current url when called without any parameter.
7391   *
7392   * Change path when called with parameter and return `$location`.
7393   *
7394   * Note: Path should always begin with forward slash (/), this method will add the forward slash
7395   * if it is missing.
7396   *
7397   * @param {string=} path New path
7398   * @return {string} path
7399   */
7400  path: locationGetterSetter('$$path', function(path) {
7401    return path.charAt(0) == '/' ? path : '/' + path;
7402  }),
7403
7404  /**
7405   * @ngdoc method
7406   * @name ng.$location#search
7407   * @methodOf ng.$location
7408   *
7409   * @description
7410   * This method is getter / setter.
7411   *
7412   * Return search part (as object) of current url when called without any parameter.
7413   *
7414   * Change search part when called with parameter and return `$location`.
7415   *
7416   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or hash object. Hash object
7417   *    may contain an array of values, which will be decoded as duplicates in the url.
7418   * @param {string=} paramValue If `search` is a string, then `paramValue` will override only a
7419   *    single search parameter. If the value is `null`, the parameter will be deleted.
7420   *
7421   * @return {string} search
7422   */
7423  search: function(search, paramValue) {
7424    switch (arguments.length) {
7425      case 0:
7426        return this.$$search;
7427      case 1:
7428        if (isString(search)) {
7429          this.$$search = parseKeyValue(search);
7430        } else if (isObject(search)) {
7431          this.$$search = search;
7432        } else {
7433          throw $locationMinErr('isrcharg', 'The first argument of the `$location#search()` call must be a string or an object.');
7434        }
7435        break;
7436      default:
7437        if (paramValue == undefined || paramValue == null) {
7438          delete this.$$search[search];
7439        } else {
7440          this.$$search[search] = paramValue;
7441        }
7442    }
7443
7444    this.$$compose();
7445    return this;
7446  },
7447
7448  /**
7449   * @ngdoc method
7450   * @name ng.$location#hash
7451   * @methodOf ng.$location
7452   *
7453   * @description
7454   * This method is getter / setter.
7455   *
7456   * Return hash fragment when called without any parameter.
7457   *
7458   * Change hash fragment when called with parameter and return `$location`.
7459   *
7460   * @param {string=} hash New hash fragment
7461   * @return {string} hash
7462   */
7463  hash: locationGetterSetter('$$hash', identity),
7464
7465  /**
7466   * @ngdoc method
7467   * @name ng.$location#replace
7468   * @methodOf ng.$location
7469   *
7470   * @description
7471   * If called, all changes to $location during current `$digest` will be replacing current history
7472   * record, instead of adding new one.
7473   */
7474  replace: function() {
7475    this.$$replace = true;
7476    return this;
7477  }
7478};
7479
7480function locationGetter(property) {
7481  return function() {
7482    return this[property];
7483  };
7484}
7485
7486
7487function locationGetterSetter(property, preprocess) {
7488  return function(value) {
7489    if (isUndefined(value))
7490      return this[property];
7491
7492    this[property] = preprocess(value);
7493    this.$$compose();
7494
7495    return this;
7496  };
7497}
7498
7499
7500/**
7501 * @ngdoc object
7502 * @name ng.$location
7503 *
7504 * @requires $browser
7505 * @requires $sniffer
7506 * @requires $rootElement
7507 *
7508 * @description
7509 * The $location service parses the URL in the browser address bar (based on the
7510 * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
7511 * available to your application. Changes to the URL in the address bar are reflected into
7512 * $location service and changes to $location are reflected into the browser address bar.
7513 *
7514 * **The $location service:**
7515 *
7516 * - Exposes the current URL in the browser address bar, so you can
7517 *   - Watch and observe the URL.
7518 *   - Change the URL.
7519 * - Synchronizes the URL with the browser when the user
7520 *   - Changes the address bar.
7521 *   - Clicks the back or forward button (or clicks a History link).
7522 *   - Clicks on a link.
7523 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
7524 *
7525 * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
7526 * Services: Using $location}
7527 */
7528
7529/**
7530 * @ngdoc object
7531 * @name ng.$locationProvider
7532 * @description
7533 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
7534 */
7535function $LocationProvider(){
7536  var hashPrefix = '',
7537      html5Mode = false;
7538
7539  /**
7540   * @ngdoc property
7541   * @name ng.$locationProvider#hashPrefix
7542   * @methodOf ng.$locationProvider
7543   * @description
7544   * @param {string=} prefix Prefix for hash part (containing path and search)
7545   * @returns {*} current value if used as getter or itself (chaining) if used as setter
7546   */
7547  this.hashPrefix = function(prefix) {
7548    if (isDefined(prefix)) {
7549      hashPrefix = prefix;
7550      return this;
7551    } else {
7552      return hashPrefix;
7553    }
7554  };
7555
7556  /**
7557   * @ngdoc property
7558   * @name ng.$locationProvider#html5Mode
7559   * @methodOf ng.$locationProvider
7560   * @description
7561   * @param {string=} mode Use HTML5 strategy if available.
7562   * @returns {*} current value if used as getter or itself (chaining) if used as setter
7563   */
7564  this.html5Mode = function(mode) {
7565    if (isDefined(mode)) {
7566      html5Mode = mode;
7567      return this;
7568    } else {
7569      return html5Mode;
7570    }
7571  };
7572
7573  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
7574      function( $rootScope,   $browser,   $sniffer,   $rootElement) {
7575    var $location,
7576        LocationMode,
7577        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
7578        initialUrl = $browser.url(),
7579        appBase;
7580
7581    if (html5Mode) {
7582      appBase = serverBase(initialUrl) + (baseHref || '/');
7583      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
7584    } else {
7585      appBase = stripHash(initialUrl);
7586      LocationMode = LocationHashbangUrl;
7587    }
7588    $location = new LocationMode(appBase, '#' + hashPrefix);
7589    $location.$$parse($location.$$rewrite(initialUrl));
7590
7591    $rootElement.on('click', function(event) {
7592      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
7593      // currently we open nice url link and redirect then
7594
7595      if (event.ctrlKey || event.metaKey || event.which == 2) return;
7596
7597      var elm = jqLite(event.target);
7598
7599      // traverse the DOM up to find first A tag
7600      while (lowercase(elm[0].nodeName) !== 'a') {
7601        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
7602        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
7603      }
7604
7605      var absHref = elm.prop('href');
7606      var rewrittenUrl = $location.$$rewrite(absHref);
7607
7608      if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
7609        event.preventDefault();
7610        if (rewrittenUrl != $browser.url()) {
7611          // update location manually
7612          $location.$$parse(rewrittenUrl);
7613          $rootScope.$apply();
7614          // hack to work around FF6 bug 684208 when scenario runner clicks on links
7615          window.angular['ff-684208-preventDefault'] = true;
7616        }
7617      }
7618    });
7619
7620
7621    // rewrite hashbang url <> html5 url
7622    if ($location.absUrl() != initialUrl) {
7623      $browser.url($location.absUrl(), true);
7624    }
7625
7626    // update $location when $browser url changes
7627    $browser.onUrlChange(function(newUrl) {
7628      if ($location.absUrl() != newUrl) {
7629        if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
7630          $browser.url($location.absUrl());
7631          return;
7632        }
7633        $rootScope.$evalAsync(function() {
7634          var oldUrl = $location.absUrl();
7635
7636          $location.$$parse(newUrl);
7637          afterLocationChange(oldUrl);
7638        });
7639        if (!$rootScope.$$phase) $rootScope.$digest();
7640      }
7641    });
7642
7643    // update browser
7644    var changeCounter = 0;
7645    $rootScope.$watch(function $locationWatch() {
7646      var oldUrl = $browser.url();
7647      var currentReplace = $location.$$replace;
7648
7649      if (!changeCounter || oldUrl != $location.absUrl()) {
7650        changeCounter++;
7651        $rootScope.$evalAsync(function() {
7652          if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
7653              defaultPrevented) {
7654            $location.$$parse(oldUrl);
7655          } else {
7656            $browser.url($location.absUrl(), currentReplace);
7657            afterLocationChange(oldUrl);
7658          }
7659        });
7660      }
7661      $location.$$replace = false;
7662
7663      return changeCounter;
7664    });
7665
7666    return $location;
7667
7668    function afterLocationChange(oldUrl) {
7669      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
7670    }
7671}];
7672}
7673
7674/**
7675 * @ngdoc object
7676 * @name ng.$log
7677 * @requires $window
7678 *
7679 * @description
7680 * Simple service for logging. Default implementation writes the message
7681 * into the browser's console (if present).
7682 *
7683 * The main purpose of this service is to simplify debugging and troubleshooting.
7684 *
7685 * @example
7686   <example>
7687     <file name="script.js">
7688       function LogCtrl($scope, $log) {
7689         $scope.$log = $log;
7690         $scope.message = 'Hello World!';
7691       }
7692     </file>
7693     <file name="index.html">
7694       <div ng-controller="LogCtrl">
7695         <p>Reload this page with open console, enter text and hit the log button...</p>
7696         Message:
7697         <input type="text" ng-model="message"/>
7698         <button ng-click="$log.log(message)">log</button>
7699         <button ng-click="$log.warn(message)">warn</button>
7700         <button ng-click="$log.info(message)">info</button>
7701         <button ng-click="$log.error(message)">error</button>
7702       </div>
7703     </file>
7704   </example>
7705 */
7706
7707/**
7708 * @ngdoc object
7709 * @name ng.$logProvider
7710 * @description
7711 * Use the `$logProvider` to configure how the application logs messages
7712 */
7713function $LogProvider(){
7714  var debug = true,
7715      self = this;
7716  
7717  /**
7718   * @ngdoc property
7719   * @name ng.$logProvider#debugEnabled
7720   * @methodOf ng.$logProvider
7721   * @description
7722   * @param {string=} flag enable or disable debug level messages
7723   * @returns {*} current value if used as getter or itself (chaining) if used as setter
7724   */
7725  this.debugEnabled = function(flag) {
7726	  if (isDefined(flag)) {
7727		  debug = flag;
7728		  return this;
7729	  } else {
7730		  return debug;
7731	  }
7732  };
7733  
7734  this.$get = ['$window', function($window){
7735    return {
7736      /**
7737       * @ngdoc method
7738       * @name ng.$log#log
7739       * @methodOf ng.$log
7740       *
7741       * @description
7742       * Write a log message
7743       */
7744      log: consoleLog('log'),
7745
7746      /**
7747       * @ngdoc method
7748       * @name ng.$log#info
7749       * @methodOf ng.$log
7750       *
7751       * @description
7752       * Write an information message
7753       */
7754      info: consoleLog('info'),
7755
7756      /**
7757       * @ngdoc method
7758       * @name ng.$log#warn
7759       * @methodOf ng.$log
7760       *
7761       * @description
7762       * Write a warning message
7763       */
7764      warn: consoleLog('warn'),
7765
7766      /**
7767       * @ngdoc method
7768       * @name ng.$log#error
7769       * @methodOf ng.$log
7770       *
7771       * @description
7772       * Write an error message
7773       */
7774      error: consoleLog('error'),
7775      
7776      /**
7777       * @ngdoc method
7778       * @name ng.$log#debug
7779       * @methodOf ng.$log
7780       * 
7781       * @description
7782       * Write a debug message
7783       */
7784      debug: (function () {
7785    	var fn = consoleLog('debug');
7786    	
7787    	return function() {
7788    		if (debug) {
7789    			fn.apply(self, arguments);
7790    		}
7791    	}
7792      }())
7793    };
7794
7795    function formatError(arg) {
7796      if (arg instanceof Error) {
7797        if (arg.stack) {
7798          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
7799              ? 'Error: ' + arg.message + '\n' + arg.stack
7800              : arg.stack;
7801        } else if (arg.sourceURL) {
7802          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
7803        }
7804      }
7805      return arg;
7806    }
7807
7808    function consoleLog(type) {
7809      var console = $window.console || {},
7810          logFn = console[type] || console.log || noop;
7811
7812      if (logFn.apply) {
7813        return function() {
7814          var args = [];
7815          forEach(arguments, function(arg) {
7816            args.push(formatError(arg));
7817          });
7818          return logFn.apply(console, args);
7819        };
7820      }
7821
7822      // we are IE which either doesn't have window.console => this is noop and we do nothing,
7823      // or we are IE where console.log doesn't have apply so we log at least first 2 args
7824      return function(arg1, arg2) {
7825        logFn(arg1, arg2);
7826      }
7827    }
7828  }];
7829}
7830
7831var $parseMinErr = minErr('$parse');
7832
7833// Sandboxing Angular Expressions
7834// ------------------------------
7835// Angular expressions are generally considered safe because these expressions only have direct access to $scope and
7836// locals. However, one can obtain the ability to execute arbitrary JS code by obtaining a reference to native JS
7837// functions such as the Function constructor.
7838//
7839// As an example, consider the following Angular expression:
7840//
7841//   {}.toString.constructor(alert("evil JS code"))
7842//
7843// We want to prevent this type of access. For the sake of performance, during the lexing phase we disallow any "dotted"
7844// access to any member named "constructor".
7845//
7846// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor while evaluating
7847// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor while evaluating
7848// the expression, which is a stronger but more expensive test. Since reflective calls are expensive anyway, this is not
7849// such a big deal compared to static dereferencing.
7850//
7851// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits against the
7852// expression language, but not to prevent exploits that were enabled by exposing sensitive JavaScript or browser apis
7853// on Scope. Exposing such objects on a Scope is never a good practice and therefore we are not even trying to protect
7854// against interaction with an object explicitly exposed in this way.
7855//
7856// A developer could foil the name check by aliasing the Function constructor under a different name on the scope.
7857//
7858// In general, it is not possible to access a Window object from an angular expression unless a window or some DOM
7859// object that has a reference to window is published onto a Scope.
7860
7861function ensureSafeMemberName(name, fullExpression) {
7862  if (name === "constructor") {
7863    throw $parseMinErr('isecfld',
7864        'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}', fullExpression);
7865  }
7866  return name;
7867};
7868
7869function ensureSafeObject(obj, fullExpression) {
7870  // nifty check if obj is Function that is fast and works across iframes and other contexts
7871  if (obj && obj.constructor === obj) {
7872    throw $parseMinErr('isecfn',
7873        'Referencing Function in Angular expressions is disallowed! Expression: {0}', fullExpression);
7874  } else {
7875    return obj;
7876  }
7877}
7878
7879
7880var OPERATORS = {
7881    'null':function(){return null;},
7882    'true':function(){return true;},
7883    'false':function(){return false;},
7884    undefined:noop,
7885    '+':function(self, locals, a,b){
7886      a=a(self, locals); b=b(self, locals);
7887      if (isDefined(a)) {
7888        if (isDefined(b)) {
7889          return a + b;
7890        }
7891        return a;
7892      }
7893      return isDefined(b)?b:undefined;},
7894    '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
7895    '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
7896    '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
7897    '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
7898    '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
7899    '=':noop,
7900    '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
7901    '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
7902    '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
7903    '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
7904    '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
7905    '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
7906    '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
7907    '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
7908    '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
7909    '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
7910    '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
7911//    '|':function(self, locals, a,b){return a|b;},
7912    '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
7913    '!':function(self, locals, a){return !a(self, locals);}
7914};
7915var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
7916
7917function lex(text, csp){
7918  var tokens = [],
7919      token,
7920      index = 0,
7921      json = [],
7922      ch,
7923      lastCh = ':'; // can start regexp
7924
7925  while (index < text.length) {
7926    ch = text.charAt(index);
7927    if (is('"\'')) {
7928      readString(ch);
7929    } else if (isNumber(ch) || is('.') && isNumber(peek())) {
7930      readNumber();
7931    } else if (isIdent(ch)) {
7932      readIdent();
7933      // identifiers can only be if the preceding char was a { or ,
7934      if (was('{,') && json[0]=='{' &&
7935         (token=tokens[tokens.length-1])) {
7936        token.json = token.text.indexOf('.') == -1;
7937      }
7938    } else if (is('(){}[].,;:?')) {
7939      tokens.push({
7940        index:index,
7941        text:ch,
7942        json:(was(':[,') && is('{[')) || is('}]:,')
7943      });
7944      if (is('{[')) json.unshift(ch);
7945      if (is('}]')) json.shift();
7946      index++;
7947    } else if (isWhitespace(ch)) {
7948      index++;
7949      continue;
7950    } else {
7951      var ch2 = ch + peek(),
7952          ch3 = ch2 + peek(2),
7953          fn = OPERATORS[ch],
7954          fn2 = OPERATORS[ch2],
7955          fn3 = OPERATORS[ch3];
7956      if (fn3) {
7957        tokens.push({index:index, text:ch3, fn:fn3});
7958        index += 3;
7959      } else if (fn2) {
7960        tokens.push({index:index, text:ch2, fn:fn2});
7961        index += 2;
7962      } else if (fn) {
7963        tokens.push({index:index, text:ch, fn:fn, json: was('[,:') && is('+-')});
7964        index += 1;
7965      } else {
7966        throwError("Unexpected next character ", index, index+1);
7967      }
7968    }
7969    lastCh = ch;
7970  }
7971  return tokens;
7972
7973  function is(chars) {
7974    return chars.indexOf(ch) != -1;
7975  }
7976
7977  function was(chars) {
7978    return chars.indexOf(lastCh) != -1;
7979  }
7980
7981  function peek(i) {
7982    var num = i || 1;
7983    return index + num < text.length ? text.charAt(index + num) : false;
7984  }
7985  function isNumber(ch) {
7986    return '0' <= ch && ch <= '9';
7987  }
7988  function isWhitespace(ch) {
7989    return ch == ' ' || ch == '\r' || ch == '\t' ||
7990           ch == '\n' || ch == '\v' || ch == '\u00A0'; // IE treats non-breaking space as \u00A0
7991  }
7992  function isIdent(ch) {
7993    return 'a' <= ch && ch <= 'z' ||
7994           'A' <= ch && ch <= 'Z' ||
7995           '_' == ch || ch == '$';
7996  }
7997  function isExpOperator(ch) {
7998    return ch == '-' || ch == '+' || isNumber(ch);
7999  }
8000
8001  function throwError(error, start, end) {
8002    end = end || index;
8003    var colStr = (isDefined(start) ?
8004        "s " + start +  "-" + index + " [" + text.substring(start, end) + "]"
8005        : " " + end);
8006    throw $parseMinErr('lexerr', "Lexer Error: {0} at column{1} in expression [{2}].",
8007        error, colStr, text);
8008  }
8009
8010  function readNumber() {
8011    var number = "";
8012    var start = index;
8013    while (index < text.length) {
8014      var ch = lowercase(text.charAt(index));
8015      if (ch == '.' || isNumber(ch)) {
8016        number += ch;
8017      } else {
8018        var peekCh = peek();
8019        if (ch == 'e' && isExpOperator(peekCh)) {
8020          number += ch;
8021        } else if (isExpOperator(ch) &&
8022            peekCh && isNumber(peekCh) &&
8023            number.charAt(number.length - 1) == 'e') {
8024          number += ch;
8025        } else if (isExpOperator(ch) &&
8026            (!peekCh || !isNumber(peekCh)) &&
8027            number.charAt(number.length - 1) == 'e') {
8028          throwError('Invalid exponent');
8029        } else {
8030          break;
8031        }
8032      }
8033      index++;
8034    }
8035    number = 1 * number;
8036    tokens.push({index:start, text:number, json:true,
8037      fn:function() {return number;}});
8038  }
8039  function readIdent() {
8040    var ident = "",
8041        start = index,
8042        lastDot, peekIndex, methodName, ch;
8043
8044    while (index < text.length) {
8045      ch = text.charAt(index);
8046      if (ch == '.' || isIdent(ch) || isNumber(ch)) {
8047        if (ch == '.') lastDot = index;
8048        ident += ch;
8049      } else {
8050        break;
8051      }
8052      index++;
8053    }
8054
8055    //check if this is not a method invocation and if it is back out to last dot
8056    if (lastDot) {
8057      peekIndex = index;
8058      while(peekIndex < text.length) {
8059        ch = text.charAt(peekIndex);
8060        if (ch == '(') {
8061          methodName = ident.substr(lastDot - start + 1);
8062          ident = ident.substr(0, lastDot - start);
8063          index = peekIndex;
8064          break;
8065        }
8066        if(isWhitespace(ch)) {
8067          peekIndex++;
8068        } else {
8069          break;
8070        }
8071      }
8072    }
8073
8074
8075    var token = {
8076      index:start,
8077      text:ident
8078    };
8079
8080    if (OPERATORS.hasOwnProperty(ident)) {
8081      token.fn = token.json = OPERATORS[ident];
8082    } else {
8083      var getter = getterFn(ident, csp, text);
8084      token.fn = extend(function(self, locals) {
8085        return (getter(self, locals));
8086      }, {
8087        assign: function(self, value) {
8088          return setter(self, ident, value, text);
8089        }
8090      });
8091    }
8092
8093    tokens.push(token);
8094
8095    if (methodName) {
8096      tokens.push({
8097        index:lastDot,
8098        text: '.',
8099        json: false
8100      });
8101      tokens.push({
8102        index: lastDot + 1,
8103        text: methodName,
8104        json: false
8105      });
8106    }
8107  }
8108
8109  function readString(quote) {
8110    var start = index;
8111    index++;
8112    var string = "";
8113    var rawString = quote;
8114    var escape = false;
8115    while (index < text.length) {
8116      var ch = text.charAt(index);
8117      rawString += ch;
8118      if (escape) {
8119        if (ch == 'u') {
8120          var hex = text.substring(index + 1, index + 5);
8121          if (!hex.match(/[\da-f]{4}/i))
8122            throwError( "Invalid unicode escape [\\u" + hex + "]");
8123          index += 4;
8124          string += String.fromCharCode(parseInt(hex, 16));
8125        } else {
8126          var rep = ESCAPE[ch];
8127          if (rep) {
8128            string += rep;
8129          } else {
8130            string += ch;
8131          }
8132        }
8133        escape = false;
8134      } else if (ch == '\\') {
8135        escape = true;
8136      } else if (ch == quote) {
8137        index++;
8138        tokens.push({
8139          index:start,
8140          text:rawString,
8141          string:string,
8142          json:true,
8143          fn:function() { return string; }
8144        });
8145        return;
8146      } else {
8147        string += ch;
8148      }
8149      index++;
8150    }
8151    throwError("Unterminated quote", start);
8152  }
8153}
8154
8155/////////////////////////////////////////
8156
8157function parser(text, json, $filter, csp){
8158  var ZERO = valueFn(0),
8159      value,
8160      tokens = lex(text, csp),
8161      assignment = _assignment,
8162      functionCall = _functionCall,
8163      fieldAccess = _fieldAccess,
8164      objectIndex = _objectIndex,
8165      filterChain = _filterChain;
8166
8167  if(json){
8168    // The extra level of aliasing is here, just in case the lexer misses something, so that
8169    // we prevent any accidental execution in JSON.
8170    assignment = logicalOR;
8171    functionCall =
8172      fieldAccess =
8173      objectIndex =
8174      filterChain =
8175        function() { throwError("is not valid json", {text:text, index:0}); };
8176    value = primary();
8177  } else {
8178    value = statements();
8179  }
8180  if (tokens.length !== 0) {
8181    throwError("is an unexpected token", tokens[0]);
8182  }
8183  value.literal = !!value.literal;
8184  value.constant = !!value.constant;
8185  return value;
8186
8187  ///////////////////////////////////
8188  function throwError(msg, token) {
8189    throw $parseMinErr('syntax',
8190        "Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].",
8191        token.text, msg, (token.index + 1), text, text.substring(token.index));
8192  }
8193
8194  function peekToken() {
8195    if (tokens.length === 0)
8196      throw $parseMinErr('ueoe', "Unexpected end of expression: {0}", text);
8197    return tokens[0];
8198  }
8199
8200  function peek(e1, e2, e3, e4) {
8201    if (tokens.length > 0) {
8202      var token = tokens[0];
8203      var t = token.text;
8204      if (t==e1 || t==e2 || t==e3 || t==e4 ||
8205          (!e1 && !e2 && !e3 && !e4)) {
8206        return token;
8207      }
8208    }
8209    return false;
8210  }
8211
8212  function expect(e1, e2, e3, e4){
8213    var token = peek(e1, e2, e3, e4);
8214    if (token) {
8215      if (json && !token.json) {
8216        throwError("is not valid json", token);
8217      }
8218      tokens.shift();
8219      return token;
8220    }
8221    return false;
8222  }
8223
8224  function consume(e1){
8225    if (!expect(e1)) {
8226      throwError("is unexpected, expecting [" + e1 + "]", peek());
8227    }
8228  }
8229
8230  function unaryFn(fn, right) {
8231    return extend(function(self, locals) {
8232      return fn(self, locals, right);
8233    }, {
8234      constant:right.constant
8235    });
8236  }
8237
8238  function ternaryFn(left, middle, right){
8239    return extend(function(self, locals){
8240      return left(self, locals) ? middle(self, locals) : right(self, locals);
8241    }, {
8242      constant: left.constant && middle.constant && right.constant
8243    });
8244  }
8245
8246  function binaryFn(left, fn, right) {
8247    return extend(function(self, locals) {
8248      return fn(self, locals, left, right);
8249    }, {
8250      constant:left.constant && right.constant
8251    });
8252  }
8253
8254  function statements() {
8255    var statements = [];
8256    while(true) {
8257      if (tokens.length > 0 && !peek('}', ')', ';', ']'))
8258        statements.push(filterChain());
8259      if (!expect(';')) {
8260        // optimize for the common case where there is only one statement.
8261        // TODO(size): maybe we should not support multiple statements?
8262        return statements.length == 1
8263          ? statements[0]
8264          : function(self, locals){
8265            var value;
8266            for ( var i = 0; i < statements.length; i++) {
8267              var statement = statements[i];
8268              if (statement)
8269                value = statement(self, locals);
8270            }
8271            return value;
8272          };
8273      }
8274    }
8275  }
8276
8277  function _filterChain() {
8278    var left = expression();
8279    var token;
8280    while(true) {
8281      if ((token = expect('|'))) {
8282        left = binaryFn(left, token.fn, filter());
8283      } else {
8284        return left;
8285      }
8286    }
8287  }
8288
8289  function filter() {
8290    var token = expect();
8291    var fn = $filter(token.text);
8292    var argsFn = [];
8293    while(true) {
8294      if ((token = expect(':'))) {
8295        argsFn.push(expression());
8296      } else {
8297        var fnInvoke = function(self, locals, input){
8298          var args = [input];
8299          for ( var i = 0; i < argsFn.length; i++) {
8300            args.push(argsFn[i](self, locals));
8301          }
8302          return fn.apply(self, args);
8303        };
8304        return function() {
8305          return fnInvoke;
8306        };
8307      }
8308    }
8309  }
8310
8311  function expression() {
8312    return assignment();
8313  }
8314
8315  function _assignment() {
8316    var left = ternary();
8317    var right;
8318    var token;
8319    if ((token = expect('='))) {
8320      if (!left.assign) {
8321        throwError("implies assignment but [" +
8322          text.substring(0, token.index) + "] can not be assigned to", token);
8323      }
8324      right = ternary();
8325      return function(scope, locals){
8326        return left.assign(scope, right(scope, locals), locals);
8327      };
8328    } else {
8329      return left;
8330    }
8331  }
8332
8333  function ternary() {
8334    var left = logicalOR();
8335    var middle;
8336    var token;
8337    if((token = expect('?'))){
8338      middle = ternary();
8339      if((token = expect(':'))){
8340        return ternaryFn(left, middle, ternary());
8341      }
8342      else {
8343        throwError('expected :', token);
8344      }
8345    }
8346    else {
8347      return left;
8348    }
8349  }
8350
8351  function logicalOR() {
8352    var left = logicalAND();
8353    var token;
8354    while(true) {
8355      if ((token = expect('||'))) {
8356        left = binaryFn(left, token.fn, logicalAND());
8357      } else {
8358        return left;
8359      }
8360    }
8361  }
8362
8363  function logicalAND() {
8364    var left = equality();
8365    var token;
8366    if ((token = expect('&&'))) {
8367      left = binaryFn(left, token.fn, logicalAND());
8368    }
8369    return left;
8370  }
8371
8372  function equality() {
8373    var left = relational();
8374    var token;
8375    if ((token = expect('==','!=','===','!=='))) {
8376      left = binaryFn(left, token.fn, equality());
8377    }
8378    return left;
8379  }
8380
8381  function relational() {
8382    var left = additive();
8383    var token;
8384    if ((token = expect('<', '>', '<=', '>='))) {
8385      left = binaryFn(left, token.fn, relational());
8386    }
8387    return left;
8388  }
8389
8390  function additive() {
8391    var left = multiplicative();
8392    var token;
8393    while ((token = expect('+','-'))) {
8394      left = binaryFn(left, token.fn, multiplicative());
8395    }
8396    return left;
8397  }
8398
8399  function multiplicative() {
8400    var left = unary();
8401    var token;
8402    while ((token = expect('*','/','%'))) {
8403      left = binaryFn(left, token.fn, unary());
8404    }
8405    return left;
8406  }
8407
8408  function unary() {
8409    var token;
8410    if (expect('+')) {
8411      return primary();
8412    } else if ((token = expect('-'))) {
8413      return binaryFn(ZERO, token.fn, unary());
8414    } else if ((token = expect('!'))) {
8415      return unaryFn(token.fn, unary());
8416    } else {
8417      return primary();
8418    }
8419  }
8420
8421
8422  function primary() {
8423    var primary;
8424    if (expect('(')) {
8425      primary = filterChain();
8426      consume(')');
8427    } else if (expect('[')) {
8428      primary = arrayDeclaration();
8429    } else if (expect('{')) {
8430      primary = object();
8431    } else {
8432      var token = expect();
8433      primary = token.fn;
8434      if (!primary) {
8435        throwError("not a primary expression", token);
8436      }
8437      if (token.json) {
8438        primary.constant = primary.literal = true;
8439      }
8440    }
8441
8442    var next, context;
8443    while ((next = expect('(', '[', '.'))) {
8444      if (next.text === '(') {
8445        primary = functionCall(primary, context);
8446        context = null;
8447      } else if (next.text === '[') {
8448        context = primary;
8449        primary = objectIndex(primary);
8450      } else if (next.text === '.') {
8451        context = primary;
8452        primary = fieldAccess(primary);
8453      } else {
8454        throwError("IMPOSSIBLE");
8455      }
8456    }
8457    return primary;
8458  }
8459
8460  function _fieldAccess(object) {
8461    var field = expect().text;
8462    var getter = getterFn(field, csp, text);
8463    return extend(
8464        function(scope, locals, self) {
8465          return getter(self || object(scope, locals), locals);
8466        },
8467        {
8468          assign:function(scope, value, locals) {
8469            return setter(object(scope, locals), field, value, text);
8470          }
8471        }
8472    );
8473  }
8474
8475  function _objectIndex(obj) {
8476    var indexFn = expression();
8477    consume(']');
8478    return extend(
8479      function(self, locals){
8480        var o = obj(self, locals),
8481            i = indexFn(self, locals),
8482            v, p;
8483
8484        if (!o) return undefined;
8485        v = ensureSafeObject(o[i], text);
8486        if (v && v.then) {
8487          p = v;
8488          if (!('$$v' in v)) {
8489            p.$$v = undefined;
8490            p.then(function(val) { p.$$v = val; });
8491          }
8492          v = v.$$v;
8493        }
8494        return v;
8495      }, {
8496        assign:function(self, value, locals){
8497          var key = indexFn(self, locals);
8498          // prevent overwriting of Function.constructor which would break ensureSafeObject check
8499          return ensureSafeObject(obj(self, locals), text)[key] = value;
8500        }
8501      });
8502  }
8503
8504  function _functionCall(fn, contextGetter) {
8505    var argsFn = [];
8506    if (peekToken().text != ')') {
8507      do {
8508        argsFn.push(expression());
8509      } while (expect(','));
8510    }
8511    consume(')');
8512    return function(scope, locals){
8513      var args = [],
8514          context = contextGetter ? contextGetter(scope, locals) : scope;
8515
8516      for ( var i = 0; i < argsFn.length; i++) {
8517        args.push(argsFn[i](scope, locals));
8518      }
8519      var fnPtr = fn(scope, locals, context) || noop;
8520      // IE stupidity!
8521      return fnPtr.apply
8522          ? fnPtr.apply(context, args)
8523          : fnPtr(args[0], args[1], args[2], args[3], args[4]);
8524    };
8525  }
8526
8527  // This is used with json array declaration
8528  function arrayDeclaration () {
8529    var elementFns = [];
8530    var allConstant = true;
8531    if (peekToken().text != ']') {
8532      do {
8533        var elementFn = expression();
8534        elementFns.push(elementFn);
8535        if (!elementFn.constant) {
8536          allConstant = false;
8537        }
8538      } while (expect(','));
8539    }
8540    consume(']');
8541    return extend(function(self, locals){
8542      var array = [];
8543      for ( var i = 0; i < elementFns.length; i++) {
8544        array.push(elementFns[i](self, locals));
8545      }
8546      return array;
8547    }, {
8548      literal:true,
8549      constant:allConstant
8550    });
8551  }
8552
8553  function object () {
8554    var keyValues = [];
8555    var allConstant = true;
8556    if (peekToken().text != '}') {
8557      do {
8558        var token = expect(),
8559        key = token.string || token.text;
8560        consume(":");
8561        var value = expression();
8562        keyValues.push({key:key, value:value});
8563        if (!value.constant) {
8564          allConstant = false;
8565        }
8566      } while (expect(','));
8567    }
8568    consume('}');
8569    return extend(function(self, locals){
8570      var object = {};
8571      for ( var i = 0; i < keyValues.length; i++) {
8572        var keyValue = keyValues[i];
8573        object[keyValue.key] = keyValue.value(self, locals);
8574      }
8575      return object;
8576    }, {
8577      literal:true,
8578      constant:allConstant
8579    });
8580  }
8581}
8582
8583//////////////////////////////////////////////////
8584// Parser helper functions
8585//////////////////////////////////////////////////
8586
8587function setter(obj, path, setValue, fullExp) {
8588  var element = path.split('.'), key;
8589  for (var i = 0; element.length > 1; i++) {
8590    key = ensureSafeMemberName(element.shift(), fullExp);
8591    var propertyObj = obj[key];
8592    if (!propertyObj) {
8593      propertyObj = {};
8594      obj[key] = propertyObj;
8595    }
8596    obj = propertyObj;
8597    if (obj.then) {
8598      if (!("$$v" in obj)) {
8599        (function(promise) {
8600          promise.then(function(val) { promise.$$v = val; }); }
8601        )(obj);
8602      }
8603      if (obj.$$v === undefined) {
8604        obj.$$v = {};
8605      }
8606      obj = obj.$$v;
8607    }
8608  }
8609  key = ensureSafeMemberName(element.shift(), fullExp);
8610  obj[key] = setValue;
8611  return setValue;
8612}
8613
8614var getterFnCache = {};
8615
8616/**
8617 * Implementation of the "Black Hole" variant from:
8618 * - http://jsperf.com/angularjs-parse-getter/4
8619 * - http://jsperf.com/path-evaluation-simplified/7
8620 */
8621function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp) {
8622  ensureSafeMemberName(key0, fullExp);
8623  ensureSafeMemberName(key1, fullExp);
8624  ensureSafeMemberName(key2, fullExp);
8625  ensureSafeMemberName(key3, fullExp);
8626  ensureSafeMemberName(key4, fullExp);
8627  return function(scope, locals) {
8628    var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
8629        promise;
8630
8631    if (pathVal === null || pathVal === undefined) return pathVal;
8632
8633    pathVal = pathVal[key0];
8634    if (pathVal && pathVal.then) {
8635      if (!("$$v" in pathVal)) {
8636        promise = pathVal;
8637        promise.$$v = undefined;
8638        promise.then(function(val) { promise.$$v = val; });
8639      }
8640      pathVal = pathVal.$$v;
8641    }
8642    if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
8643
8644    pathVal = pathVal[key1];
8645    if (pathVal && pathVal.then) {
8646      if (!("$$v" in pathVal)) {
8647        promise = pathVal;
8648        promise.$$v = undefined;
8649        promise.then(function(val) { promise.$$v = val; });
8650      }
8651      pathVal = pathVal.$$v;
8652    }
8653    if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
8654
8655    pathVal = pathVal[key2];
8656    if (pathVal && pathVal.then) {
8657      if (!("$$v" in pathVal)) {
8658        promise = pathVal;
8659        promise.$$v = undefined;
8660        promise.then(function(val) { promise.$$v = val; });
8661      }
8662      pathVal = pathVal.$$v;
8663    }
8664    if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
8665
8666    pathVal = pathVal[key3];
8667    if (pathVal && pathVal.then) {
8668      if (!("$$v" in pathVal)) {
8669        promise = pathVal;
8670        promise.$$v = undefined;
8671        promise.then(function(val) { promise.$$v = val; });
8672      }
8673      pathVal = pathVal.$$v;
8674    }
8675    if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
8676
8677    pathVal = pathVal[key4];
8678    if (pathVal && pathVal.then) {
8679      if (!("$$v" in pathVal)) {
8680        promise = pathVal;
8681        promise.$$v = undefined;
8682        promise.then(function(val) { promise.$$v = val; });
8683      }
8684      pathVal = pathVal.$$v;
8685    }
8686    return pathVal;
8687  };
8688}
8689
8690function getterFn(path, csp, fullExp) {
8691  if (getterFnCache.hasOwnProperty(path)) {
8692    return getterFnCache[path];
8693  }
8694
8695  var pathKeys = path.split('.'),
8696      pathKeysLength = pathKeys.length,
8697      fn;
8698
8699  if (csp) {
8700    fn = (pathKeysLength < 6)
8701        ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp)
8702        : function(scope, locals) {
8703          var i = 0, val;
8704          do {
8705            val = cspSafeGetterFn(
8706                    pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], fullExp
8707                  )(scope, locals);
8708
8709            locals = undefined; // clear after first iteration
8710            scope = val;
8711          } while (i < pathKeysLength);
8712          return val;
8713        }
8714  } else {
8715    var code = 'var l, fn, p;\n';
8716    forEach(pathKeys, function(key, index) {
8717      ensureSafeMemberName(key, fullExp);
8718      code += 'if(s === null || s === undefined) return s;\n' +
8719              'l=s;\n' +
8720              's='+ (index
8721                      // we simply dereference 's' on any .dot notation
8722                      ? 's'
8723                      // but if we are first then we check locals first, and if so read it first
8724                      : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
8725              'if (s && s.then) {\n' +
8726                ' if (!("$$v" in s)) {\n' +
8727                  ' p=s;\n' +
8728                  ' p.$$v = undefined;\n' +
8729                  ' p.then(function(v) {p.$$v=v;});\n' +
8730                  '}\n' +
8731                ' s=s.$$v\n' +
8732              '}\n';
8733    });
8734    code += 'return s;';
8735    fn = Function('s', 'k', code); // s=scope, k=locals
8736    fn.toString = function() { return code; };
8737  }
8738
8739  return getterFnCache[path] = fn;
8740}
8741
8742///////////////////////////////////
8743
8744/**
8745 * @ngdoc function
8746 * @name ng.$parse
8747 * @function
8748 *
8749 * @description
8750 *
8751 * Converts Angular {@link guide/expression expression} into a function.
8752 *
8753 * <pre>
8754 *   var getter = $parse('user.name');
8755 *   var setter = getter.assign;
8756 *   var context = {user:{name:'angular'}};
8757 *   var locals = {user:{name:'local'}};
8758 *
8759 *   expect(getter(context)).toEqual('angular');
8760 *   setter(context, 'newValue');
8761 *   expect(context.user.name).toEqual('newValue');
8762 *   expect(getter(context, locals)).toEqual('local');
8763 * </pre>
8764 *
8765 *
8766 * @param {string} expression String expression to compile.
8767 * @returns {function(context, locals)} a function which represents the compiled expression:
8768 *
8769 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
8770 *      are evaluated against (typically a scope object).
8771 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
8772 *      `context`.
8773 *
8774 *    The returned function also has the following properties:
8775 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
8776 *        literal.
8777 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
8778 *        constant literals.
8779 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
8780 *        set to a function to change its value on the given context.
8781 *
8782 */
8783function $ParseProvider() {
8784  var cache = {};
8785  this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
8786    return function(exp) {
8787      switch(typeof exp) {
8788        case 'string':
8789          return cache.hasOwnProperty(exp)
8790            ? cache[exp]
8791            : cache[exp] =  parser(exp, false, $filter, $sniffer.csp);
8792        case 'function':
8793          return exp;
8794        default:
8795          return noop;
8796      }
8797    };
8798  }];
8799}
8800
8801/**
8802 * @ngdoc service
8803 * @name ng.$q
8804 * @requires $rootScope
8805 *
8806 * @description
8807 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
8808 *
8809 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
8810 * interface for interacting with an object that represents the result of an action that is
8811 * performed asynchronously, and may or may not be finished at any given point in time.
8812 *
8813 * From the perspective of dealing with error handling, deferred and promise APIs are to
8814 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
8815 *
8816 * <pre>
8817 *   // for the purpose of this example let's assume that variables `$q` and `scope` are
8818 *   // available in the current lexical scope (they could have been injected or passed in).
8819 *
8820 *   function asyncGreet(name) {
8821 *     var deferred = $q.defer();
8822 *
8823 *     setTimeout(function() {
8824 *       // since this fn executes async in a future turn of the event loop, we need to wrap
8825 *       // our code into an $apply call so that the model changes are properly observed.
8826 *       scope.$apply(function() {
8827 *         if (okToGreet(name)) {
8828 *           deferred.resolve('Hello, ' + name + '!');
8829 *         } else {
8830 *           deferred.reject('Greeting ' + name + ' is not allowed.');
8831 *         }
8832 *       });
8833 *     }, 1000);
8834 *
8835 *     return deferred.promise;
8836 *   }
8837 *
8838 *   var promise = asyncGreet('Robin Hood');
8839 *   promise.then(function(greeting) {
8840 *     alert('Success: ' + greeting);
8841 *   }, function(reason) {
8842 *     alert('Failed: ' + reason);
8843 *   });
8844 * </pre>
8845 *
8846 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
8847 * comes in the way of
8848 * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
8849 *
8850 * Additionally the promise api allows for composition that is very hard to do with the
8851 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
8852 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
8853 * section on serial or parallel joining of promises.
8854 *
8855 *
8856 * # The Deferred API
8857 *
8858 * A new instance of deferred is constructed by calling `$q.defer()`.
8859 *
8860 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
8861 * that can be used for signaling the successful or unsuccessful completion of the task.
8862 *
8863 * **Methods**
8864 *
8865 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
8866 *   constructed via `$q.reject`, the promise will be rejected instead.
8867 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
8868 *   resolving it with a rejection constructed via `$q.reject`.
8869 *
8870 * **Properties**
8871 *
8872 * - promise – `{Promise}` – promise object associated with this deferred.
8873 *
8874 *
8875 * # The Promise API
8876 *
8877 * A new promise instance is created when a deferred instance is created and can be retrieved by
8878 * calling `deferred.promise`.
8879 *
8880 * The purpose of the promise object is to allow for interested parties to get access to the result
8881 * of the deferred task when it completes.
8882 *
8883 * **Methods**
8884 *
8885 * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved
8886 *   or rejected, `then` calls one of the success or error callbacks asynchronously as soon as the result
8887 *   is available. The callbacks are called with a single argument: the result or rejection reason.
8888 *
8889 *   This method *returns a new promise* which is resolved or rejected via the return value of the
8890 *   `successCallback` or `errorCallback`.
8891 *
8892 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
8893 *
8894 * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
8895 *   but to do so without modifying the final value. This is useful to release resources or do some
8896 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
8897 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
8898 *   more information.
8899 *
8900 *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
8901 *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
8902 *   make your code IE8 compatible.
8903 *
8904 * # Chaining promises
8905 *
8906 * Because calling the `then` method of a promise returns a new derived promise, it is easily possible
8907 * to create a chain of promises:
8908 *
8909 * <pre>
8910 *   promiseB = promiseA.then(function(result) {
8911 *     return result + 1;
8912 *   });
8913 *
8914 *   // promiseB will be resolved immediately after promiseA is resolved and its value
8915 *   // will be the result of promiseA incremented by 1
8916 * </pre>
8917 *
8918 * It is possible to create chains of any length and since a promise can be resolved with another
8919 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
8920 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
8921 * $http's response interceptors.
8922 *
8923 *
8924 * # Differences between Kris Kowal's Q and $q
8925 *
8926 *  There are three main differences:
8927 *
8928 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
8929 *   mechanism in angular, which means faster propagation of resolution or rejection into your
8930 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
8931 * - $q promises are recognized by the templating engine in angular, which means that in templates
8932 *   you can treat promises attached to a scope as if they were the resulting values.
8933 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
8934 *   all the important functionality needed for common async tasks.
8935 *
8936 *  # Testing
8937 *
8938 *  <pre>
8939 *    it('should simulate promise', inject(function($q, $rootScope) {
8940 *      var deferred = $q.defer();
8941 *      var promise = deferred.promise;
8942 *      var resolvedValue;
8943 *
8944 *      promise.then(function(value) { resolvedValue = value; });
8945 *      expect(resolvedValue).toBeUndefined();
8946 *
8947 *      // Simulate resolving of promise
8948 *      deferred.resolve(123);
8949 *      // Note that the 'then' function does not get called synchronously.
8950 *      // This is because we want the promise API to always be async, whether or not
8951 *      // it got called synchronously or asynchronously.
8952 *      expect(resolvedValue).toBeUndefined();
8953 *
8954 *      // Propagate promise resolution to 'then' functions using $apply().
8955 *      $rootScope.$apply();
8956 *      expect(resolvedValue).toEqual(123);
8957 *    });
8958 *  </pre>
8959 */
8960function $QProvider() {
8961
8962  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
8963    return qFactory(function(callback) {
8964      $rootScope.$evalAsync(callback);
8965    }, $exceptionHandler);
8966  }];
8967}
8968
8969
8970/**
8971 * Constructs a promise manager.
8972 *
8973 * @param {function(function)} nextTick Function for executing functions in the next turn.
8974 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
8975 *     debugging purposes.
8976 * @returns {object} Promise manager.
8977 */
8978function qFactory(nextTick, exceptionHandler) {
8979
8980  /**
8981   * @ngdoc
8982   * @name ng.$q#defer
8983   * @methodOf ng.$q
8984   * @description
8985   * Creates a `Deferred` object which represents a task which will finish in the future.
8986   *
8987   * @returns {Deferred} Returns a new instance of deferred.
8988   */
8989  var defer = function() {
8990    var pending = [],
8991        value, deferred;
8992
8993    deferred = {
8994
8995      resolve: function(val) {
8996        if (pending) {
8997          var callbacks = pending;
8998          pending = undefined;
8999          value = ref(val);
9000
9001          if (callbacks.length) {
9002            nextTick(function() {
9003              var callback;
9004              for (var i = 0, ii = callbacks.length; i < ii; i++) {
9005                callback = callbacks[i];
9006                value.then(callback[0], callback[1], callback[2]);
9007              }
9008            });
9009          }
9010        }
9011      },
9012
9013
9014      reject: function(reason) {
9015        deferred.resolve(reject(reason));
9016      },
9017
9018
9019      notify: function(progress) {
9020        if (pending) {
9021          var callbacks = pending;
9022
9023          if (pending.length) {
9024            nextTick(function() {
9025              var callback;
9026              for (var i = 0, ii = callbacks.length; i < ii; i++) {
9027                callback = callbacks[i];
9028                callback[2](progress);
9029              }
9030            });
9031          }
9032        }
9033      },
9034
9035
9036      promise: {
9037        then: function(callback, errback, progressback) {
9038          var result = defer();
9039
9040          var wrappedCallback = function(value) {
9041            try {
9042              result.resolve((callback || defaultCallback)(value));
9043            } catch(e) {
9044              result.reject(e);
9045              exceptionHandler(e);
9046            }
9047          };
9048
9049          var wrappedErrback = function(reason) {
9050            try {
9051              result.resolve((errback || defaultErrback)(reason));
9052            } catch(e) {
9053              result.reject(e);
9054              exceptionHandler(e);
9055            }
9056          };
9057
9058          var wrappedProgressback = function(progress) {
9059            try {
9060              result.notify((progressback || defaultCallback)(progress));
9061            } catch(e) {
9062              exceptionHandler(e);
9063            }
9064          };
9065
9066          if (pending) {
9067            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
9068          } else {
9069            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
9070          }
9071
9072          return result.promise;
9073        },
9074
9075        "catch": function(callback) {
9076          return this.then(null, callback);
9077        },
9078
9079        "finally": function(callback) {
9080
9081          function makePromise(value, resolved) {
9082            var result = defer();
9083            if (resolved) {
9084              result.resolve(value);
9085            } else {
9086              result.reject(value);
9087            }
9088            return result.promise;
9089          }
9090
9091          function handleCallback(value, isResolved) {
9092            var callbackOutput = null;
9093            try {
9094              callbackOutput = (callback ||defaultCallback)();
9095            } catch(e) {
9096              return makePromise(e, false);
9097            }
9098            if (callbackOutput && callbackOutput.then) {
9099              return callbackOutput.then(function() {
9100                return makePromise(value, isResolved);
9101              }, function(error) {
9102                return makePromise(error, false);
9103              });
9104            } else {
9105              return makePromise(value, isResolved);
9106            }
9107          }
9108
9109          return this.then(function(value) {
9110            return handleCallback(value, true);
9111          }, function(error) {
9112            return handleCallback(error, false);
9113          });
9114        }
9115      }
9116    };
9117
9118    return deferred;
9119  };
9120
9121
9122  var ref = function(value) {
9123    if (value && value.then) return value;
9124    return {
9125      then: function(callback) {
9126        var result = defer();
9127        nextTick(function() {
9128          result.resolve(callback(value));
9129        });
9130        return result.promise;
9131      }
9132    };
9133  };
9134
9135
9136  /**
9137   * @ngdoc
9138   * @name ng.$q#reject
9139   * @methodOf ng.$q
9140   * @description
9141   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
9142   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
9143   * a promise chain, you don't need to worry about it.
9144   *
9145   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
9146   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
9147   * a promise error callback and you want to forward the error to the promise derived from the
9148   * current promise, you have to "rethrow" the error by returning a rejection constructed via
9149   * `reject`.
9150   *
9151   * <pre>
9152   *   promiseB = promiseA.then(function(result) {
9153   *     // success: do something and resolve promiseB
9154   *     //          with the old or a new result
9155   *     return result;
9156   *   }, function(reason) {
9157   *     // error: handle the error if possible and
9158   *     //        resolve promiseB with newPromiseOrValue,
9159   *     //        otherwise forward the rejection to promiseB
9160   *     if (canHandle(reason)) {
9161   *      // handle the error and recover
9162   *      return newPromiseOrValue;
9163   *     }
9164   *     return $q.reject(reason);
9165   *   });
9166   * </pre>
9167   *
9168   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
9169   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
9170   */
9171  var reject = function(reason) {
9172    return {
9173      then: function(callback, errback) {
9174        var result = defer();
9175        nextTick(function() {
9176          result.resolve((errback || defaultErrback)(reason));
9177        });
9178        return result.promise;
9179      }
9180    };
9181  };
9182
9183
9184  /**
9185   * @ngdoc
9186   * @name ng.$q#when
9187   * @methodOf ng.$q
9188   * @description
9189   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
9190   * This is useful when you are dealing with an object that might or might not be a promise, or if
9191   * the promise comes from a source that can't be trusted.
9192   *
9193   * @param {*} value Value or a promise
9194   * @returns {Promise} Returns a promise of the passed value or promise
9195   */
9196  var when = function(value, callback, errback, progressback) {
9197    var result = defer(),
9198        done;
9199
9200    var wrappedCallback = function(value) {
9201      try {
9202        return (callback || defaultCallback)(value);
9203      } catch (e) {
9204        exceptionHandler(e);
9205        return reject(e);
9206      }
9207    };
9208
9209    var wrappedErrback = function(reason) {
9210      try {
9211        return (errback || defaultErrback)(reason);
9212      } catch (e) {
9213        exceptionHandler(e);
9214        return reject(e);
9215      }
9216    };
9217
9218    var wrappedProgressback = function(progress) {
9219      try {
9220        return (progressback || defaultCallback)(progress);
9221      } catch (e) {
9222        exceptionHandler(e);
9223      }
9224    };
9225
9226    nextTick(function() {
9227      ref(value).then(function(value) {
9228        if (done) return;
9229        done = true;
9230        result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
9231      }, function(reason) {
9232        if (done) return;
9233        done = true;
9234        result.resolve(wrappedErrback(reason));
9235      }, function(progress) {
9236        if (done) return;
9237        result.notify(wrappedProgressback(progress));
9238      });
9239    });
9240
9241    return result.promise;
9242  };
9243
9244
9245  function defaultCallback(value) {
9246    return value;
9247  }
9248
9249
9250  function defaultErrback(reason) {
9251    return reject(reason);
9252  }
9253
9254
9255  /**
9256   * @ngdoc
9257   * @name ng.$q#all
9258   * @methodOf ng.$q
9259   * @description
9260   * Combines multiple promises into a single promise that is resolved when all of the input
9261   * promises are resolved.
9262   *
9263   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
9264   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
9265   *   each value corresponding to the promise at the same index/key in the `promises` array/hash. If any of
9266   *   the promises is resolved with a rejection, this resulting promise will be resolved with the
9267   *   same rejection.
9268   */
9269  function all(promises) {
9270    var deferred = defer(),
9271        counter = 0,
9272        results = isArray(promises) ? [] : {};
9273
9274    forEach(promises, function(promise, key) {
9275      counter++;
9276      ref(promise).then(function(value) {
9277        if (results.hasOwnProperty(key)) return;
9278        results[key] = value;
9279        if (!(--counter)) deferred.resolve(results);
9280      }, function(reason) {
9281        if (results.hasOwnProperty(key)) return;
9282        deferred.reject(reason);
9283      });
9284    });
9285
9286    if (counter === 0) {
9287      deferred.resolve(results);
9288    }
9289
9290    return deferred.promise;
9291  }
9292
9293  return {
9294    defer: defer,
9295    reject: reject,
9296    when: when,
9297    all: all
9298  };
9299}
9300
9301/**
9302 * DESIGN NOTES
9303 *
9304 * The design decisions behind the scope are heavily favored for speed and memory consumption.
9305 *
9306 * The typical use of scope is to watch the expressions, which most of the time return the same
9307 * value as last time so we optimize the operation.
9308 *
9309 * Closures construction is expensive in terms of speed as well as memory:
9310 *   - No closures, instead use prototypical inheritance for API
9311 *   - Internal state needs to be stored on scope directly, which means that private state is
9312 *     exposed as $$____ properties
9313 *
9314 * Loop operations are optimized by using while(count--) { ... }
9315 *   - this means that in order to keep the same order of execution as addition we have to add
9316 *     items to the array at the beginning (shift) instead of at the end (push)
9317 *
9318 * Child scopes are created and removed often
9319 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
9320 *
9321 * There are few watches then a lot of observers. This is why you don't want the observer to be
9322 * implemented in the same way as watch. Watch requires return of initialization function which
9323 * are expensive to construct.
9324 */
9325
9326
9327/**
9328 * @ngdoc object
9329 * @name ng.$rootScopeProvider
9330 * @description
9331 *
9332 * Provider for the $rootScope service.
9333 */
9334
9335/**
9336 * @ngdoc function
9337 * @name ng.$rootScopeProvider#digestTtl
9338 * @methodOf ng.$rootScopeProvider
9339 * @description
9340 *
9341 * Sets the number of digest iterations the scope should attempt to execute before giving up and
9342 * assuming that the model is unstable.
9343 *
9344 * The current default is 10 iterations.
9345 *
9346 * @param {number} limit The number of digest iterations.
9347 */
9348
9349
9350/**
9351 * @ngdoc object
9352 * @name ng.$rootScope
9353 * @description
9354 *
9355 * Every application has a single root {@link ng.$rootScope.Scope scope}.
9356 * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
9357 * event processing life-cycle. See {@link guide/scope developer guide on scopes}.
9358 */
9359function $RootScopeProvider(){
9360  var TTL = 10;
9361  var $rootScopeMinErr = minErr('$rootScope');
9362
9363  this.digestTtl = function(value) {
9364    if (arguments.length) {
9365      TTL = value;
9366    }
9367    return TTL;
9368  };
9369
9370  this.$get = ['$injector', '$exceptionHandler', '$parse',
9371      function( $injector,   $exceptionHandler,   $parse) {
9372
9373    /**
9374     * @ngdoc function
9375     * @name ng.$rootScope.Scope
9376     *
9377     * @description
9378     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
9379     * {@link AUTO.$injector $injector}. Child scopes are created using the
9380     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
9381     * compiled HTML template is executed.)
9382     *
9383     * Here is a simple scope snippet to show how you can interact with the scope.
9384     * <pre>
9385     * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
9386     * </pre>
9387     *
9388     * # Inheritance
9389     * A scope can inherit from a parent scope, as in this example:
9390     * <pre>
9391         var parent = $rootScope;
9392         var child = parent.$new();
9393
9394         parent.salutation = "Hello";
9395         child.name = "World";
9396         expect(child.salutation).toEqual('Hello');
9397
9398         child.salutation = "Welcome";
9399         expect(child.salutation).toEqual('Welcome');
9400         expect(parent.salutation).toEqual('Hello');
9401     * </pre>
9402     *
9403     *
9404     * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
9405     *     for the current scope. Defaults to {@link ng}.
9406     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
9407     *     append/override services provided by `providers`. This is handy when unit-testing and having
9408     *     the need to override a default service.
9409     * @returns {Object} Newly created scope.
9410     *
9411     */
9412    function Scope() {
9413      this.$id = nextUid();
9414      this.$$phase = this.$parent = this.$$watchers =
9415                     this.$$nextSibling = this.$$prevSibling =
9416                     this.$$childHead = this.$$childTail = null;
9417      this['this'] = this.$root =  this;
9418      this.$$destroyed = false;
9419      this.$$asyncQueue = [];
9420      this.$$listeners = {};
9421      this.$$isolateBindings = {};
9422    }
9423
9424    /**
9425     * @ngdoc property
9426     * @name ng.$rootScope.Scope#$id
9427     * @propertyOf ng.$rootScope.Scope
9428     * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
9429     *   debugging.
9430     */
9431
9432
9433    Scope.prototype = {
9434      /**
9435       * @ngdoc function
9436       * @name ng.$rootScope.Scope#$new
9437       * @methodOf ng.$rootScope.Scope
9438       * @function
9439       *
9440       * @description
9441       * Creates a new child {@link ng.$rootScope.Scope scope}.
9442       *
9443       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
9444       * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
9445       * hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
9446       *
9447       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
9448       * the scope and its child scopes to be permanently detached from the parent and thus stop
9449       * participating in model change detection and listener notification by invoking.
9450       *
9451       * @param {boolean} isolate if true then the scope does not prototypically inherit from the
9452       *         parent scope. The scope is isolated, as it can not see parent scope properties.
9453       *         When creating widgets it is useful for the widget to not accidentally read parent
9454       *         state.
9455       *
9456       * @returns {Object} The newly created child scope.
9457       *
9458       */
9459      $new: function(isolate) {
9460        var Child,
9461            child;
9462
9463        if (isolate) {
9464          child = new Scope();
9465          child.$root = this.$root;
9466          // ensure that there is just one async queue per $rootScope and it's children
9467          child.$$asyncQueue = this.$$asyncQueue;
9468        } else {
9469          Child = function() {}; // should be anonymous; This is so that when the minifier munges
9470            // the name it does not become random set of chars. These will then show up as class
9471            // name in the debugger.
9472          Child.prototype = this;
9473          child = new Child();
9474          child.$id = nextUid();
9475        }
9476        child['this'] = child;
9477        child.$$listeners = {};
9478        child.$parent = this;
9479        child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
9480        child.$$prevSibling = this.$$childTail;
9481        if (this.$$childHead) {
9482          this.$$childTail.$$nextSibling = child;
9483          this.$$childTail = child;
9484        } else {
9485          this.$$childHead = this.$$childTail = child;
9486        }
9487        return child;
9488      },
9489
9490      /**
9491       * @ngdoc function
9492       * @name ng.$rootScope.Scope#$watch
9493       * @methodOf ng.$rootScope.Scope
9494       * @function
9495       *
9496       * @description
9497       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
9498       *
9499       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest $digest()} and
9500       *   should return the value which will be watched. (Since {@link ng.$rootScope.Scope#$digest $digest()}
9501       *   reruns when it detects changes the `watchExpression` can execute multiple times per
9502       *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
9503       * - The `listener` is called only when the value from the current `watchExpression` and the
9504       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
9505       *   see below). The inequality is determined according to
9506       *   {@link angular.equals} function. To save the value of the object for later comparison, the
9507       *   {@link angular.copy} function is used. It also means that watching complex options will
9508       *   have adverse memory and performance implications.
9509       * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
9510       *   is achieved by rerunning the watchers until no changes are detected. The rerun iteration
9511       *   limit is 10 to prevent an infinite loop deadlock.
9512       *
9513       *
9514       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
9515       * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
9516       * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
9517       * detected, be prepared for multiple calls to your listener.)
9518       *
9519       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
9520       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
9521       * watcher. In rare cases, this is undesirable because the listener is called when the result
9522       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
9523       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
9524       * listener was called due to initialization.
9525       *
9526       *
9527       * # Example
9528       * <pre>
9529           // let's assume that scope was dependency injected as the $rootScope
9530           var scope = $rootScope;
9531           scope.name = 'misko';
9532           scope.counter = 0;
9533
9534           expect(scope.counter).toEqual(0);
9535           scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
9536           expect(scope.counter).toEqual(0);
9537
9538           scope.$digest();
9539           // no variable change
9540           expect(scope.counter).toEqual(0);
9541
9542           scope.name = 'adam';
9543           scope.$digest();
9544           expect(scope.counter).toEqual(1);
9545       * </pre>
9546       *
9547       *
9548       *
9549       * @param {(function()|string)} watchExpression Expression that is evaluated on each
9550       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
9551       *    call to the `listener`.
9552       *
9553       *    - `string`: Evaluated as {@link guide/expression expression}
9554       *    - `function(scope)`: called with current `scope` as a parameter.
9555       * @param {(function()|string)=} listener Callback called whenever the return value of
9556       *   the `watchExpression` changes.
9557       *
9558       *    - `string`: Evaluated as {@link guide/expression expression}
9559       *    - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
9560       *
9561       * @param {boolean=} objectEquality Compare object for equality rather than for reference.
9562       * @returns {function()} Returns a deregistration function for this listener.
9563       */
9564      $watch: function(watchExp, listener, objectEquality) {
9565        var scope = this,
9566            get = compileToFn(watchExp, 'watch'),
9567            array = scope.$$watchers,
9568            watcher = {
9569              fn: listener,
9570              last: initWatchVal,
9571              get: get,
9572              exp: watchExp,
9573              eq: !!objectEquality
9574            };
9575
9576        // in the case user pass string, we need to compile it, do we really need this ?
9577        if (!isFunction(listener)) {
9578          var listenFn = compileToFn(listener || noop, 'listener');
9579          watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
9580        }
9581
9582        if (typeof watchExp == 'string' && get.constant) {
9583          var originalFn = watcher.fn;
9584          watcher.fn = function(newVal, oldVal, scope) {
9585            originalFn.call(this, newVal, oldVal, scope);
9586            arrayRemove(array, watcher);
9587          };
9588        }
9589
9590        if (!array) {
9591          array = scope.$$watchers = [];
9592        }
9593        // we use unshift since we use a while loop in $digest for speed.
9594        // the while loop reads in reverse order.
9595        array.unshift(watcher);
9596
9597        return function() {
9598          arrayRemove(array, watcher);
9599        };
9600      },
9601
9602
9603      /**
9604       * @ngdoc function
9605       * @name ng.$rootScope.Scope#$watchCollection
9606       * @methodOf ng.$rootScope.Scope
9607       * @function
9608       *
9609       * @description
9610       * Shallow watches the properties of an object and fires whenever any of the properties change
9611       * (for arrays this implies watching the array items, for object maps this implies watching the properties).
9612       * If a change is detected the `listener` callback is fired.
9613       *
9614       * - The `obj` collection is observed via standard $watch operation and is examined on every call to $digest() to
9615       *   see if any items have been added, removed, or moved.
9616       * - The `listener` is called whenever anything within the `obj` has changed. Examples include adding new items
9617       *   into the object or array, removing and moving items around.
9618       *
9619       *
9620       * # Example
9621       * <pre>
9622          $scope.names = ['igor', 'matias', 'misko', 'james'];
9623          $scope.dataCount = 4;
9624
9625          $scope.$watchCollection('names', function(newNames, oldNames) {
9626            $scope.dataCount = newNames.length;
9627          });
9628
9629          expect($scope.dataCount).toEqual(4);
9630          $scope.$digest();
9631
9632          //still at 4 ... no changes
9633          expect($scope.dataCount).toEqual(4);
9634
9635          $scope.names.pop();
9636          $scope.$digest();
9637
9638          //now there's been a change
9639          expect($scope.dataCount).toEqual(3);
9640       * </pre>
9641       *
9642       *
9643       * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The expression value
9644       *    should evaluate to an object or an array which is observed on each
9645       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the collection will trigger
9646       *    a call to the `listener`.
9647       *
9648       * @param {function(newCollection, oldCollection, scope)} listener a callback function that is fired with both
9649       *    the `newCollection` and `oldCollection` as parameters.
9650       *    The `newCollection` object is the newly modified data obtained from the `obj` expression and the
9651       *    `oldCollection` object is a copy of the former collection data.
9652       *    The `scope` refers to the current scope.
9653       *
9654       * @returns {function()} Returns a de-registration function for this listener. When the de-registration function is executed
9655       * then the internal watch operation is terminated.
9656       */
9657      $watchCollection: function(obj, listener) {
9658        var self = this;
9659        var oldValue;
9660        var newValue;
9661        var changeDetected = 0;
9662        var objGetter = $parse(obj);
9663        var internalArray = [];
9664        var internalObject = {};
9665        var oldLength = 0;
9666
9667        function $watchCollectionWatch() {
9668          newValue = objGetter(self);
9669          var newLength, key;
9670
9671          if (!isObject(newValue)) {
9672            if (oldValue !== newValue) {
9673              oldValue = newValue;
9674              changeDetected++;
9675            }
9676          } else if (isArrayLike(newValue)) {
9677            if (oldValue !== internalArray) {
9678              // we are transitioning from something which was not an array into array.
9679              oldValue = internalArray;
9680              oldLength = oldValue.length = 0;
9681              changeDetected++;
9682            }
9683
9684            newLength = newValue.length;
9685
9686            if (oldLength !== newLength) {
9687              // if lengths do not match we need to trigger change notification
9688              changeDetected++;
9689              oldValue.length = oldLength = newLength;
9690            }
9691            // copy the items to oldValue and look for changes.
9692            for (var i = 0; i < newLength; i++) {
9693              if (oldValue[i] !== newValue[i]) {
9694                changeDetected++;
9695                oldValue[i] = newValue[i];
9696              }
9697            }
9698          } else {
9699            if (oldValue !== internalObject) {
9700              // we are transitioning from something which was not an object into object.
9701              oldValue = internalObject = {};
9702              oldLength = 0;
9703              changeDetected++;
9704            }
9705            // copy the items to oldValue and look for changes.
9706            newLength = 0;
9707            for (key in newValue) {
9708              if (newValue.hasOwnProperty(key)) {
9709                newLength++;
9710                if (oldValue.hasOwnProperty(key)) {
9711                  if (oldValue[key] !== newValue[key]) {
9712                    changeDetected++;
9713                    oldValue[key] = newValue[key];
9714                  }
9715                } else {
9716                  oldLength++;
9717                  oldValue[key] = newValue[key];
9718                  changeDetected++;
9719                }
9720              }
9721            }
9722            if (oldLength > newLength) {
9723              // we used to have more keys, need to find them and destroy them.
9724              changeDetected++;
9725              for(key in oldValue) {
9726                if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
9727                  oldLength--;
9728                  delete oldValue[key];
9729                }
9730              }
9731            }
9732          }
9733          return changeDetected;
9734        }
9735
9736        function $watchCollectionAction() {
9737          listener(newValue, oldValue, self);
9738        }
9739
9740        return this.$watch($watchCollectionWatch, $watchCollectionAction);
9741      },
9742
9743      /**
9744       * @ngdoc function
9745       * @name ng.$rootScope.Scope#$digest
9746       * @methodOf ng.$rootScope.Scope
9747       * @function
9748       *
9749       * @description
9750       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
9751       * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
9752       * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
9753       * firing. This means that it is possible to get into an infinite loop. This function will throw
9754       * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
9755       *
9756       * Usually you don't call `$digest()` directly in
9757       * {@link ng.directive:ngController controllers} or in
9758       * {@link ng.$compileProvider#directive directives}.
9759       * Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
9760       * {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
9761       *
9762       * If you want to be notified whenever `$digest()` is called,
9763       * you can register a `watchExpression` function  with {@link ng.$rootScope.Scope#$watch $watch()}
9764       * with no `listener`.
9765       *
9766       * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
9767       * life-cycle.
9768       *
9769       * # Example
9770       * <pre>
9771           var scope = ...;
9772           scope.name = 'misko';
9773           scope.counter = 0;
9774
9775           expect(scope.counter).toEqual(0);
9776           scope.$watch('name', function(newValue, oldValue) {
9777             scope.counter = scope.counter + 1;
9778           });
9779           expect(scope.counter).toEqual(0);
9780
9781           scope.$digest();
9782           // no variable change
9783           expect(scope.counter).toEqual(0);
9784
9785           scope.name = 'adam';
9786           scope.$digest();
9787           expect(scope.counter).toEqual(1);
9788       * </pre>
9789       *
9790       */
9791      $digest: function() {
9792        var watch, value, last,
9793            watchers,
9794            asyncQueue = this.$$asyncQueue,
9795            length,
9796            dirty, ttl = TTL,
9797            next, current, target = this,
9798            watchLog = [],
9799            logIdx, logMsg;
9800
9801        beginPhase('$digest');
9802
9803        do { // "while dirty" loop
9804          dirty = false;
9805          current = target;
9806
9807          while(asyncQueue.length) {
9808            try {
9809              current.$eval(asyncQueue.shift());
9810            } catch (e) {
9811              $exceptionHandler(e);
9812            }
9813          }
9814
9815          do { // "traverse the scopes" loop
9816            if ((watchers = current.$$watchers)) {
9817              // process our watches
9818              length = watchers.length;
9819              while (length--) {
9820                try {
9821                  watch = watchers[length];
9822                  // Most common watches are on primitives, in which case we can short
9823                  // circuit it with === operator, only when === fails do we use .equals
9824                  if (watch && (value = watch.get(current)) !== (last = watch.last) &&
9825                      !(watch.eq
9826                          ? equals(value, last)
9827                          : (typeof value == 'number' && typeof last == 'number'
9828                             && isNaN(value) && isNaN(last)))) {
9829                    dirty = true;
9830                    watch.last = watch.eq ? copy(value) : value;
9831                    watch.fn(value, ((last === initWatchVal) ? value : last), current);
9832                    if (ttl < 5) {
9833                      logIdx = 4 - ttl;
9834                      if (!watchLog[logIdx]) watchLog[logIdx] = [];
9835                      logMsg = (isFunction(watch.exp))
9836                          ? 'fn: ' + (watch.exp.name || watch.exp.toString())
9837                          : watch.exp;
9838                      logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
9839                      watchLog[logIdx].push(logMsg);
9840                    }
9841                  }
9842                } catch (e) {
9843                  $exceptionHandler(e);
9844                }
9845              }
9846            }
9847
9848            // Insanity Warning: scope depth-first traversal
9849            // yes, this code is a bit crazy, but it works and we have tests to prove it!
9850            // this piece should be kept in sync with the traversal in $broadcast
9851            if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
9852              while(current !== target && !(next = current.$$nextSibling)) {
9853                current = current.$parent;
9854              }
9855            }
9856          } while ((current = next));
9857
9858          if(dirty && !(ttl--)) {
9859            clearPhase();
9860            throw $rootScopeMinErr('infdig',
9861                '{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}',
9862                TTL, toJson(watchLog));
9863          }
9864        }
9864 while (dirty || asyncQueue.length);
9865
9866        clearPhase();
9867      },
9868
9869
9870      /**
9871       * @ngdoc event
9872       * @name ng.$rootScope.Scope#$destroy
9873       * @eventOf ng.$rootScope.Scope
9874       * @eventType broadcast on scope being destroyed
9875       *
9876       * @description
9877       * Broadcasted when a scope and its children are being destroyed.
9878       *
9879       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
9880       * clean up DOM bindings before an element is removed from the DOM.
9881       */
9882
9883      /**
9884       * @ngdoc function
9885       * @name ng.$rootScope.Scope#$destroy
9886       * @methodOf ng.$rootScope.Scope
9887       * @function
9888       *
9889       * @description
9890       * Removes the current scope (and all of its children) from the parent scope. Removal implies
9891       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
9892       * propagate to the current scope and its children. Removal also implies that the current
9893       * scope is eligible for garbage collection.
9894       *
9895       * The `$destroy()` is usually used by directives such as
9896       * {@link ng.directive:ngRepeat ngRepeat} for managing the
9897       * unrolling of the loop.
9898       *
9899       * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
9900       * Application code can register a `$destroy` event handler that will give it chance to
9901       * perform any necessary cleanup.
9902       *
9903       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
9904       * clean up DOM bindings before an element is removed from the DOM.
9905       */
9906      $destroy: function() {
9907        // we can't destroy the root scope or a scope that has been already destroyed
9908        if ($rootScope == this || this.$$destroyed) return;
9909        var parent = this.$parent;
9910
9911        this.$broadcast('$destroy');
9912        this.$$destroyed = true;
9913
9914        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
9915        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
9916        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
9917        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
9918
9919        // This is bogus code that works around Chrome's GC leak
9920        // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
9921        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
9922            this.$$childTail = null;
9923      },
9924
9925      /**
9926       * @ngdoc function
9927       * @name ng.$rootScope.Scope#$eval
9928       * @methodOf ng.$rootScope.Scope
9929       * @function
9930       *
9931       * @description
9932       * Executes the `expression` on the current scope returning the result. Any exceptions in the
9933       * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
9934       *
9935       * # Example
9936       * <pre>
9937           var scope = ng.$rootScope.Scope();
9938           scope.a = 1;
9939           scope.b = 2;
9940
9941           expect(scope.$eval('a+b')).toEqual(3);
9942           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
9943       * </pre>
9944       *
9945       * @param {(string|function())=} expression An angular expression to be executed.
9946       *
9947       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
9948       *    - `function(scope)`: execute the function with the current `scope` parameter.
9949       *
9950       * @returns {*} The result of evaluating the expression.
9951       */
9952      $eval: function(expr, locals) {
9953        return $parse(expr)(this, locals);
9954      },
9955
9956      /**
9957       * @ngdoc function
9958       * @name ng.$rootScope.Scope#$evalAsync
9959       * @methodOf ng.$rootScope.Scope
9960       * @function
9961       *
9962       * @description
9963       * Executes the expression on the current scope at a later point in time.
9964       *
9965       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
9966       *
9967       *   - it will execute in the current script execution context (before any DOM rendering).
9968       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
9969       *     `expression` execution.
9970       *
9971       * Any exceptions from the execution of the expression are forwarded to the
9972       * {@link ng.$exceptionHandler $exceptionHandler} service.
9973       *
9974       * @param {(string|function())=} expression An angular expression to be executed.
9975       *
9976       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
9977       *    - `function(scope)`: execute the function with the current `scope` parameter.
9978       *
9979       */
9980      $evalAsync: function(expr) {
9981        this.$$asyncQueue.push(expr);
9982      },
9983
9984      /**
9985       * @ngdoc function
9986       * @name ng.$rootScope.Scope#$apply
9987       * @methodOf ng.$rootScope.Scope
9988       * @function
9989       *
9990       * @description
9991       * `$apply()` is used to execute an expression in angular from outside of the angular framework.
9992       * (For example from browser DOM events, setTimeout, XHR or third party libraries).
9993       * Because we are calling into the angular framework we need to perform proper scope life-cycle
9994       * of {@link ng.$exceptionHandler exception handling},
9995       * {@link ng.$rootScope.Scope#$digest executing watches}.
9996       *
9997       * ## Life cycle
9998       *
9999       * # Pseudo-Code of `$apply()`
10000       * <pre>
10001           function $apply(expr) {
10002             try {
10003               return $eval(expr);
10004             } catch (e) {
10005               $exceptionHandler(e);
10006             } finally {
10007               $root.$digest();
10008             }
10009           }
10010       * </pre>
10011       *
10012       *
10013       * Scope's `$apply()` method transitions through the following stages:
10014       *
10015       * 1. The {@link guide/expression expression} is executed using the
10016       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
10017       * 2. Any exceptions from the execution of the expression are forwarded to the
10018       *    {@link ng.$exceptionHandler $exceptionHandler} service.
10019       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
10020       *    was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
10021       *
10022       *
10023       * @param {(string|function())=} exp An angular expression to be executed.
10024       *
10025       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
10026       *    - `function(scope)`: execute the function with current `scope` parameter.
10027       *
10028       * @returns {*} The result of evaluating the expression.
10029       */
10030      $apply: function(expr) {
10031        try {
10032          beginPhase('$apply');
10033          return this.$eval(expr);
10034        } catch (e) {
10035          $exceptionHandler(e);
10036        } finally {
10037          clearPhase();
10038          try {
10039            $rootScope.$digest();
10040          } catch (e) {
10041            $exceptionHandler(e);
10042            throw e;
10043          }
10044        }
10045      },
10046
10047      /**
10048       * @ngdoc function
10049       * @name ng.$rootScope.Scope#$on
10050       * @methodOf ng.$rootScope.Scope
10051       * @function
10052       *
10053       * @description
10054       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
10055       * event life cycle.
10056       *
10057       * The event listener function format is: `function(event, args...)`. The `event` object
10058       * passed into the listener has the following attributes:
10059       *
10060       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
10061       *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
10062       *   - `name` - `{string}`: Name of the event.
10063       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
10064       *     propagation (available only for events that were `$emit`-ed).
10065       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
10066       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
10067       *
10068       * @param {string} name Event name to listen on.
10069       * @param {function(event, args...)} listener Function to call when the event is emitted.
10070       * @returns {function()} Returns a deregistration function for this listener.
10071       */
10072      $on: function(name, listener) {
10073        var namedListeners = this.$$listeners[name];
10074        if (!namedListeners) {
10075          this.$$listeners[name] = namedListeners = [];
10076        }
10077        namedListeners.push(listener);
10078
10079        return function() {
10080          namedListeners[indexOf(namedListeners, listener)] = null;
10081        };
10082      },
10083
10084
10085      /**
10086       * @ngdoc function
10087       * @name ng.$rootScope.Scope#$emit
10088       * @methodOf ng.$rootScope.Scope
10089       * @function
10090       *
10091       * @description
10092       * Dispatches an event `name` upwards through the scope hierarchy notifying the
10093       * registered {@link ng.$rootScope.Scope#$on} listeners.
10094       *
10095       * The event life cycle starts at the scope on which `$emit` was called. All
10096       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
10097       * Afterwards, the event traverses upwards toward the root scope and calls all registered
10098       * listeners along the way. The event will stop propagating if one of the listeners cancels it.
10099       *
10100       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
10101       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
10102       *
10103       * @param {string} name Event name to emit.
10104       * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
10105       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
10106       */
10107      $emit: function(name, args) {
10108        var empty = [],
10109            namedListeners,
10110            scope = this,
10111            stopPropagation = false,
10112            event = {
10113              name: name,
10114              targetScope: scope,
10115              stopPropagation: function() {stopPropagation = true;},
10116              preventDefault: function() {
10117                event.defaultPrevented = true;
10118              },
10119              defaultPrevented: false
10120            },
10121            listenerArgs = concat([event], arguments, 1),
10122            i, length;
10123
10124        do {
10125          namedListeners = scope.$$listeners[name] || empty;
10126          event.currentScope = scope;
10127          for (i=0, length=namedListeners.length; i<length; i++) {
10128
10129            // if listeners were deregistered, defragment the array
10130            if (!namedListeners[i]) {
10131              namedListeners.splice(i, 1);
10132              i--;
10133              length--;
10134              continue;
10135            }
10136            try {
10137              namedListeners[i].apply(null, listenerArgs);
10138              if (stopPropagation) return event;
10139            } catch (e) {
10140              $exceptionHandler(e);
10141            }
10142          }
10143          //traverse upwards
10144          scope = scope.$parent;
10145        } while (scope);
10146
10147        return event;
10148      },
10149
10150
10151      /**
10152       * @ngdoc function
10153       * @name ng.$rootScope.Scope#$broadcast
10154       * @methodOf ng.$rootScope.Scope
10155       * @function
10156       *
10157       * @description
10158       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
10159       * registered {@link ng.$rootScope.Scope#$on} listeners.
10160       *
10161       * The event life cycle starts at the scope on which `$broadcast` was called. All
10162       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
10163       * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
10164       * calls all registered listeners along the way. The event cannot be canceled.
10165       *
10166       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
10167       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
10168       *
10169       * @param {string} name Event name to broadcast.
10170       * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
10171       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
10172       */
10173      $broadcast: function(name, args) {
10174        var target = this,
10175            current = target,
10176            next = target,
10177            event = {
10178              name: name,
10179              targetScope: target,
10180              preventDefault: function() {
10181                event.defaultPrevented = true;
10182              },
10183              defaultPrevented: false
10184            },
10185            listenerArgs = concat([event], arguments, 1),
10186            listeners, i, length;
10187
10188        //down while you can, then up and next sibling or up and next sibling until back at root
10189        do {
10190          current = next;
10191          event.currentScope = current;
10192          listeners = current.$$listeners[name] || [];
10193          for (i=0, length = listeners.length; i<length; i++) {
10194            // if listeners were deregistered, defragment the array
10195            if (!listeners[i]) {
10196              listeners.splice(i, 1);
10197              i--;
10198              length--;
10199              continue;
10200            }
10201
10202            try {
10203              listeners[i].apply(null, listenerArgs);
10204            } catch(e) {
10205              $exceptionHandler(e);
10206            }
10207          }
10208
10209          // Insanity Warning: scope depth-first traversal
10210          // yes, this code is a bit crazy, but it works and we have tests to prove it!
10211          // this piece should be kept in sync with the traversal in $digest
10212          if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
10213            while(current !== target && !(next = current.$$nextSibling)) {
10214              current = current.$parent;
10215            }
10216          }
10217        } while ((current = next));
10218
10219        return event;
10220      }
10221    };
10222
10223    var $rootScope = new Scope();
10224
10225    return $rootScope;
10226
10227
10228    function beginPhase(phase) {
10229      if ($rootScope.$$phase) {
10230        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
10231      }
10232
10233      $rootScope.$$phase = phase;
10234    }
10235
10236    function clearPhase() {
10237      $rootScope.$$phase = null;
10238    }
10239
10240    function compileToFn(exp, name) {
10241      var fn = $parse(exp);
10242      assertArgFn(fn, name);
10243      return fn;
10244    }
10245
10246    /**
10247     * function used as an initial value for watchers.
10248     * because it's unique we can easily tell it apart from other values
10249     */
10250    function initWatchVal() {}
10251  }];
10252}
10253
10254var $sceMinErr = minErr('$sce');
10255
10256var SCE_CONTEXTS = {
10257  HTML: 'html',
10258  CSS: 'css',
10259  URL: 'url',
10260  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
10261  // url.  (e.g. ng-include, script src, templateUrl)
10262  RESOURCE_URL: 'resourceUrl',
10263  JS: 'js'
10264};
10265
10266
10267/**
10268 * @ngdoc service
10269 * @name ng.$sceDelegate
10270 * @function
10271 *
10272 * @description
10273 *
10274 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
10275 * Contextual Escaping (SCE)} services to AngularJS.
10276 *
10277 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
10278 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
10279 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
10280 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
10281 * work because `$sce` delegates to `$sceDelegate` for these operations.
10282 *
10283 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
10284 *
10285 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
10286 * can override it completely to change the behavior of `$sce`, the common case would
10287 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
10288 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
10289 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
10290 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
10291 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
10292 */
10293
10294/**
10295 * @ngdoc object
10296 * @name ng.$sceDelegateProvider
10297 * @description
10298 *
10299 * The $sceDelegateProvider provider allows developers to configure the {@link ng.$sceDelegate
10300 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
10301 * that URLs used for sourcing Angular templates are safe.  Refer {@link
10302 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
10303 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
10304 *
10305 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
10306 */
10307
10308function $SceDelegateProvider() {
10309  this.SCE_CONTEXTS = SCE_CONTEXTS;
10310
10311  // Resource URLs can also be trusted by policy.
10312  var resourceUrlWhitelist = ['self'],
10313      resourceUrlBlacklist = [];
10314
10315  /**
10316   * @ngdoc function
10317   * @name ng.sceDelegateProvider#resourceUrlWhitelist
10318   * @methodOf ng.$sceDelegateProvider
10319   * @function
10320   *
10321   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
10322   *     provided.  This must be an array.
10323   *
10324   *     Each element of this array must either be a regex or the special string `'self'`.
10325   *
10326   *     When a regex is used, it is matched against the normalized / absolute URL of the resource
10327   *     being tested.
10328   *
10329   *     The **special string** `'self'` can be used to match against all URLs of the same domain as the
10330   *     application document with the same protocol (allows sourcing https resources from http documents.)
10331   *
10332   *     Please note that **an empty whitelist array will block all URLs**!
10333   *
10334   * @return {Array} the currently set whitelist array.
10335   *
10336   * The **default value** when no whitelist has been explicitly set is `['self']`.
10337   *
10338   * @description
10339   * Sets/Gets the whitelist of trusted resource URLs.
10340   */
10341  this.resourceUrlWhitelist = function (value) {
10342    if (arguments.length) {
10343      resourceUrlWhitelist = value;
10344    }
10345    return resourceUrlWhitelist;
10346  };
10347
10348  /**
10349   * @ngdoc function
10350   * @name ng.sceDelegateProvider#resourceUrlBlacklist
10351   * @methodOf ng.$sceDelegateProvider
10352   * @function
10353   *
10354   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
10355   *     provided.  This must be an array.
10356   *
10357   *     Each element of this array must either be a regex or the special string `'self'` (see
10358   *     `resourceUrlWhitelist` for meaning - it's only really useful there.)
10359   *
10360   *     When a regex is used, it is matched against the normalized / absolute URL of the resource
10361   *     being tested.
10362   *
10363   *     The typical usage for the blacklist is to **block [open redirects](http://cwe.mitre.org/data/definitions/601.html)**
10364   *     served by your domain as these would otherwise be trusted but actually return content from the redirected
10365   *     domain.
10366   *
10367   *     Finally, **the blacklist overrides the whitelist** and has the final say.
10368   *
10369   * @return {Array} the currently set blacklist array.
10370   *
10371   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there is
10372   * no blacklist.)
10373   *
10374   * @description
10375   * Sets/Gets the blacklist of trusted resource URLs.
10376   */
10377
10378  this.resourceUrlBlacklist = function (value) {
10379    if (arguments.length) {
10380      resourceUrlBlacklist = value;
10381    }
10382    return resourceUrlBlacklist;
10383  };
10384
10385  // Helper functions for matching resource urls by policy.
10386  function isCompatibleProtocol(documentProtocol, resourceProtocol) {
10387    return ((documentProtocol === resourceProtocol) ||
10388            (documentProtocol === "http:" && resourceProtocol === "https:"));
10389  }
10390
10391  this.$get = ['$log', '$document', '$injector', '$$urlUtils', function(
10392                $log,   $document,   $injector,   $$urlUtils) {
10393
10394    var htmlSanitizer = function htmlSanitizer(html) {
10395      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
10396    };
10397
10398    if ($injector.has('$sanitize')) {
10399      htmlSanitizer = $injector.get('$sanitize');
10400    }
10401
10402
10403    function matchUrl(matcher, parsedUrl) {
10404      if (matcher === 'self') {
10405        return $$urlUtils.isSameOrigin(parsedUrl);
10406      } else {
10407        return !!parsedUrl.href.match(matcher);
10408      }
10409    }
10410
10411    function isResourceUrlAllowedByPolicy(url) {
10412      var parsedUrl = $$urlUtils.resolve(url.toString(), true);
10413      var i, n, allowed = false;
10414      // Ensure that at least one item from the whitelist allows this url.
10415      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
10416        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
10417          allowed = true;
10418          break;
10419        }
10420      }
10421      if (allowed) {
10422        // Ensure that no item from the blacklist blocked this url.
10423        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
10424          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
10425            allowed = false;
10426            break;
10427          }
10428        }
10429      }
10430      return allowed;
10431    }
10432
10433    function generateHolderType(base) {
10434      var holderType = function TrustedValueHolderType(trustedValue) {
10435        this.$$unwrapTrustedValue = function() {
10436          return trustedValue;
10437        };
10438      };
10439      if (base) {
10440        holderType.prototype = new base();
10441      }
10442      holderType.prototype.valueOf = function sceValueOf() {
10443        return this.$$unwrapTrustedValue();
10444      }
10445      holderType.prototype.toString = function sceToString() {
10446        return this.$$unwrapTrustedValue().toString();
10447      }
10448      return holderType;
10449    }
10450
10451    var trustedValueHolderBase = generateHolderType(),
10452        byType = {};
10453
10454    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
10455    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
10456    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
10457    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
10458    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
10459
10460    /**
10461     * @ngdoc method
10462     * @name ng.$sceDelegate#trustAs
10463     * @methodOf ng.$sceDelegate
10464     *
10465     * @description
10466     * Returns an object that is trusted by angular for use in specified strict
10467     * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
10468     * attribute interpolation, any dom event binding attribute interpolation
10469     * such as for onclick,  etc.) that uses the provided value.
10470     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
10471     *
10472     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
10473     *   resourceUrl, html, js and css.
10474     * @param {*} value The value that that should be considered trusted/safe.
10475     * @returns {*} A value that can be used to stand in for the provided `value` in places
10476     * where Angular expects a $sce.trustAs() return value.
10477     */
10478    function trustAs(type, trustedValue) {
10479      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
10480      if (!constructor) {
10481        throw $sceMinErr('icontext', 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
10482            type, trustedValue);
10483      }
10484      if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
10485        return trustedValue;
10486      }
10487      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
10488      // mutable objects, we ensure here that the value passed in is actually a string.
10489      if (typeof trustedValue !== 'string') {
10490        throw $sceMinErr('itype',
10491            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
10492            type);
10493      }
10494      return new constructor(trustedValue);
10495    }
10496
10497    /**
10498     * @ngdoc method
10499     * @name ng.$sceDelegate#valueOf
10500     * @methodOf ng.$sceDelegate
10501     *
10502     * @description
10503     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
10504     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
10505     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
10506     *
10507     * If the passed parameter is not a value that had been returned by {@link
10508     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
10509     *
10510     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
10511     *      call or anything else.
10512     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
10513     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns `value`
10514     *     unchanged.
10515     */
10516    function valueOf(maybeTrusted) {
10517      if (maybeTrusted instanceof trustedValueHolderBase) {
10518        return maybeTrusted.$$unwrapTrustedValue();
10519      } else {
10520        return maybeTrusted;
10521      }
10522    }
10523
10524    /**
10525     * @ngdoc method
10526     * @name ng.$sceDelegate#getTrusted
10527     * @methodOf ng.$sceDelegate
10528     *
10529     * @description
10530     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and returns the
10531     * originally supplied value if the queried context type is a supertype of the created type.  If
10532     * this condition isn't satisfied, throws an exception.
10533     *
10534     * @param {string} type The kind of context in which this value is to be used.
10535     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
10536     * `$sceDelegate.trustAs`} call.
10537     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
10538     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
10539     */
10540    function getTrusted(type, maybeTrusted) {
10541      if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
10542        return maybeTrusted;
10543      }
10544      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
10545      if (constructor && maybeTrusted instanceof constructor) {
10546        return maybeTrusted.$$unwrapTrustedValue();
10547      }
10548      // If we get here, then we may only take one of two actions.
10549      // 1. sanitize the value for the requested type, or
10550      // 2. throw an exception.
10551      if (type === SCE_CONTEXTS.RESOURCE_URL) {
10552        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
10553          return maybeTrusted;
10554        } else {
10555          throw $sceMinErr('insecurl',
10556              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}', maybeTrusted.toString());
10557        }
10558      } else if (type === SCE_CONTEXTS.HTML) {
10559        return htmlSanitizer(maybeTrusted);
10560      }
10561      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
10562    }
10563
10564    return { trustAs: trustAs,
10565             getTrusted: getTrusted,
10566             valueOf: valueOf };
10567  }];
10568}
10569
10570
10571/**
10572 * @ngdoc object
10573 * @name ng.$sceProvider
10574 * @description
10575 *
10576 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
10577 * -   enable/disable Strict Contextual Escaping (SCE) in a module
10578 * -   override the default implementation with a custom delegate
10579 *
10580 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
10581 */
10582
10583/**
10584 * @ngdoc service
10585 * @name ng.$sce
10586 * @function
10587 *
10588 * @description
10589 *
10590 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
10591 *
10592 * # Strict Contextual Escaping
10593 *
10594 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
10595 * contexts to result in a value that is marked as safe to use for that context One example of such
10596 * a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer to these
10597 * contexts as privileged or SCE contexts.
10598 *
10599 * As of version 1.2, Angular ships with SCE enabled by default.
10600 *
10601 * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
10602 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
10603 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
10604 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
10605 * to the top of your HTML document.
10606 *
10607 * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
10608 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
10609 *
10610 * Here's an example of a binding in a privileged context:
10611 *
10612 * <pre class="prettyprint">
10613 *     <input ng-model="userHtml">
10614 *     <div ng-bind-html="{{userHtml}}">
10615 * </pre>
10616 *
10617 * Notice that `ng-bind-html` is bound to `{{userHtml}}` controlled by the user.  With SCE
10618 * disabled, this application allows the user to render arbitrary HTML into the DIV.
10619 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
10620 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
10621 * security vulnerabilities.)
10622 *
10623 * For the case of HTML, you might use a library, either on the client side, or on the server side,
10624 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
10625 *
10626 * How would you ensure that every place that used these types of bindings was bound to a value that
10627 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
10628 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
10629 * properties/fields and forgot to update the binding to the sanitized value?
10630 *
10631 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
10632 * determine that something explicitly says it's safe to use a value for binding in that
10633 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
10634 * for those values that you can easily tell are safe - because they were received from your server,
10635 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
10636 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
10637 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
10638 *
10639 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} (and shorthand
10640 * methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to obtain values that will be
10641 * accepted by SCE / privileged contexts.
10642 *
10643 *
10644 * ## How does it work?
10645 *
10646 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
10647 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
10648 * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
10649 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
10650 *
10651 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
10652 * ng.$sce#parseHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
10653 * simplified):
10654 *
10655 * <pre class="prettyprint">
10656 *   var ngBindHtmlDirective = ['$sce', function($sce) {
10657 *     return function(scope, element, attr) {
10658 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
10659 *         element.html(value || '');
10660 *       });
10661 *     };
10662 *   }];
10663 * </pre>
10664 *
10665 * ## Impact on loading templates
10666 *
10667 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
10668 * `templateUrl`'s specified by {@link guide/directive directives}.
10669 *
10670 * By default, Angular only loads templates from the same domain and protocol as the application
10671 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
10672 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
10673 * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
10674 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
10675 *
10676 * *Please note*:
10677 * The browser's
10678 * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
10679 * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
10680 * policy apply in addition to this and may further restrict whether the template is successfully
10681 * loaded.  This means that without the right CORS policy, loading templates from a different domain
10682 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
10683 * browsers.
10684 *
10685 * ## This feels like too much overhead for the developer?
10686 *
10687 * It's important to remember that SCE only applies to interpolation expressions.
10688 *
10689 * If your expressions are constant literals, they're automatically trusted and you don't need to
10690 * call `$sce.trustAs` on them.  (e.g.
10691 * `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
10692 *
10693 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
10694 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
10695 *
10696 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
10697 * templates in `ng-include` from your application's domain without having to even know about SCE.
10698 * It blocks loading templates from other domains or loading templates over http from an https
10699 * served document.  You can change these by setting your own custom {@link
10700 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
10701 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
10702 *
10703 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
10704 * application that's secure and can be audited to verify that with much more ease than bolting
10705 * security onto an application later.
10706 *
10707 * ## What trusted context types are supported?<a name="contexts"></a>
10708 *
10709 * | Context             | Notes          |
10710 * |=====================|================|
10711 * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
10712 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
10713 * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
10714 * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
10715 * | `$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. |
10716 *
10717 * ## Show me an example.
10718 *
10719 *
10720 *
10721 * @example
10722 <example module="mySceApp">
10723  <file name="index.html">
10724    <div ng-controller="myAppController as myCtrl">
10725      <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
10726      <b>User comments</b><br>
10727      By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when $sanitize is available.  If $sanitize isn't available, this results in an error instead of an exploit.
10728      <div class="well">
10729        <div ng-repeat="userComment in myCtrl.userComments">
10730          <b>{{userComment.name}}</b>:
10731          <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
10732          <br>
10733        </div>
10734      </div>
10735    </div>
10736  </file>
10737
10738  <file name="script.js">
10739    var mySceApp = angular.module('mySceApp', ['ngSanitize']);
10740
10741    mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
10742      var self = this;
10743      $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
10744        self.userComments = userComments;
10745      });
10746      self.explicitlyTrustedHtml = $sce.trustAsHtml(
10747          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
10748          'sanitization.&quot;">Hover over this text.</span>');
10749    });
10750  </file>
10751
10752  <file name="test_data.json">
10753    [
10754      { "name": "Alice",
10755        "htmlComment": "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
10756      },
10757      { "name": "Bob",
10758        "htmlComment": "<i>Yes!</i>  Am I the only other one?"
10759      }
10760    ]
10761  </file>
10762
10763  <file name="scenario.js">
10764    describe('SCE doc demo', function() {
10765      it('should sanitize untrusted values', function() {
10766        expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
10767      });
10768      it('should NOT sanitize explicitly trusted values', function() {
10769        expect(element('#explicitlyTrustedHtml').html()).toBe(
10770            '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
10771            'sanitization.&quot;">Hover over this text.</span>');
10772      });
10773    });
10774  </file>
10775 </example>
10776 *
10777 *
10778 *
10779 * ## Can I disable SCE completely?
10780 *
10781 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
10782 * for little coding overhead.  It will be much harder to take an SCE disabled application and
10783 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
10784 * for cases where you have a lot of existing code that was written before SCE was introduced and
10785 * you're migrating them a module at a time.
10786 *
10787 * That said, here's how you can completely disable SCE:
10788 *
10789 * <pre class="prettyprint">
10790 *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
10791 *     // Completely disable SCE.  For demonstration purposes only!
10792 *     // Do not use in new projects.
10793 *     $sceProvider.enabled(false);
10794 *   });
10795 * </pre>
10796 *
10797 */
10798
10799function $SceProvider() {
10800  var enabled = true;
10801
10802  /**
10803   * @ngdoc function
10804   * @name ng.sceProvider#enabled
10805   * @methodOf ng.$sceProvider
10806   * @function
10807   *
10808   * @param {boolean=} value If provided, then enables/disables SCE.
10809   * @return {boolean} true if SCE is enabled, false otherwise.
10810   *
10811   * @description
10812   * Enables/disables SCE and returns the current value.
10813   */
10814  this.enabled = function (value) {
10815    if (arguments.length) {
10816      enabled = !!value;
10817    }
10818    return enabled;
10819  };
10820
10821
10822  /* Design notes on the default implementation for SCE.
10823   *
10824   * The API contract for the SCE delegate
10825   * -------------------------------------
10826   * The SCE delegate object must provide the following 3 methods:
10827   *
10828   * - trustAs(contextEnum, value)
10829   *     This method is used to tell the SCE service that the provided value is OK to use in the
10830   *     contexts specified by contextEnum.  It must return an object that will be accepted by
10831   *     getTrusted() for a compatible contextEnum and return this value.
10832   *
10833   * - valueOf(value)
10834   *     For values that were not produced by trustAs(), return them as is.  For values that were
10835   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
10836   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
10837   *     such a value.
10838   *
10839   * - getTrusted(contextEnum, value)
10840   *     This function should return the a value that is safe to use in the context specified by
10841   *     contextEnum or throw and exception otherwise.
10842   *
10843   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be opaque
10844   * or wrapped in some holder object.  That happens to be an implementation detail.  For instance,
10845   * an implementation could maintain a registry of all trusted objects by context.  In such a case,
10846   * trustAs() would return the same object that was passed in.  getTrusted() would return the same
10847   * object passed in if it was found in the registry under a compatible context or throw an
10848   * exception otherwise.  An implementation might only wrap values some of the time based on
10849   * some criteria.  getTrusted() might return a value and not throw an exception for special
10850   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
10851   *
10852   *
10853   * A note on the inheritance model for SCE contexts
10854   * ------------------------------------------------
10855   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
10856   * is purely an implementation details.
10857   *
10858   * The contract is simply this:
10859   *
10860   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
10861   *     will also succeed.
10862   *
10863   * Inheritance happens to capture this in a natural way.  In some future, we
10864   * may not use inheritance anymore.  That is OK because no code outside of
10865   * sce.js and sceSpecs.js would need to be aware of this detail.
10866   */
10867
10868  this.$get = ['$parse', '$document', '$sceDelegate', function(
10869                $parse,   $document,   $sceDelegate) {
10870    // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
10871    // the "expression(javascript expression)" syntax which is insecure.
10872    if (enabled && msie) {
10873      var documentMode = $document[0].documentMode;
10874      if (documentMode !== undefined && documentMode < 8) {
10875        throw $sceMinErr('iequirks',
10876          'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
10877          'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
10878          'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
10879      }
10880    }
10881
10882    var sce = copy(SCE_CONTEXTS);
10883
10884    /**
10885     * @ngdoc function
10886     * @name ng.sce#isEnabled
10887     * @methodOf ng.$sce
10888     * @function
10889     *
10890     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
10891     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
10892     *
10893     * @description
10894     * Returns a boolean indicating if SCE is enabled.
10895     */
10896    sce.isEnabled = function () {
10897      return enabled;
10898    };
10899    sce.trustAs = $sceDelegate.trustAs;
10900    sce.getTrusted = $sceDelegate.getTrusted;
10901    sce.valueOf = $sceDelegate.valueOf;
10902
10903    if (!enabled) {
10904      sce.trustAs = sce.getTrusted = function(type, value) { return value; },
10905      sce.valueOf = identity
10906    }
10907
10908    /**
10909     * @ngdoc method
10910     * @name ng.$sce#parse
10911     * @methodOf ng.$sce
10912     *
10913     * @description
10914     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
10915     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
10916     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
10917     * *result*)}
10918     *
10919     * @param {string} type The kind of SCE context in which this result will be used.
10920     * @param {string} expression String expression to compile.
10921     * @returns {function(context, locals)} a function which represents the compiled expression:
10922     *
10923     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
10924     *      are evaluated against (typically a scope object).
10925     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
10926     *      `context`.
10927     */
10928    sce.parseAs = function sceParseAs(type, expr) {
10929      var parsed = $parse(expr);
10930      if (parsed.literal && parsed.constant) {
10931        return parsed;
10932      } else {
10933        return function sceParseAsTrusted(self, locals) {
10934          return sce.getTrusted(type, parsed(self, locals));
10935        }
10936      }
10937    };
10938
10939    /**
10940     * @ngdoc method
10941     * @name ng.$sce#trustAs
10942     * @methodOf ng.$sce
10943     *
10944     * @description
10945     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such, returns an object
10946     * that is trusted by angular for use in specified strict contextual escaping contexts (such as
10947     * ng-html-bind-unsafe, ng-include, any src attribute interpolation, any dom event binding
10948     * attribute interpolation such as for onclick,  etc.) that uses the provided value.  See *
10949     * {@link ng.$sce $sce} for enabling strict contextual escaping.
10950     *
10951     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
10952     *   resource_url, html, js and css.
10953     * @param {*} value The value that that should be considered trusted/safe.
10954     * @returns {*} A value that can be used to stand in for the provided `value` in places
10955     * where Angular expects a $sce.trustAs() return value.
10956     */
10957
10958    /**
10959     * @ngdoc method
10960     * @name ng.$sce#trustAsHtml
10961     * @methodOf ng.$sce
10962     *
10963     * @description
10964     * Shorthand method.  `$sce.trustAsHtml(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
10965     *
10966     * @param {*} value The value to trustAs.
10967     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
10968     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
10969     *     only accept expressions that are either literal constants or are the
10970     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
10971     */
10972
10973    /**
10974     * @ngdoc method
10975     * @name ng.$sce#trustAsUrl
10976     * @methodOf ng.$sce
10977     *
10978     * @description
10979     * Shorthand method.  `$sce.trustAsUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
10980     *
10981     * @param {*} value The value to trustAs.
10982     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
10983     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
10984     *     only accept expressions that are either literal constants or are the
10985     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
10986     */
10987
10988    /**
10989     * @ngdoc method
10990     * @name ng.$sce#trustAsResourceUrl
10991     * @methodOf ng.$sce
10992     *
10993     * @description
10994     * Shorthand method.  `$sce.trustAsResourceUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
10995     *
10996     * @param {*} value The value to trustAs.
10997     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
10998     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
10999     *     only accept expressions that are either literal constants or are the return
11000     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
11001     */
11002
11003    /**
11004     * @ngdoc method
11005     * @name ng.$sce#trustAsJs
11006     * @methodOf ng.$sce
11007     *
11008     * @description
11009     * Shorthand method.  `$sce.trustAsJs(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
11010     *
11011     * @param {*} value The value to trustAs.
11012     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
11013     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
11014     *     only accept expressions that are either literal constants or are the
11015     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
11016     */
11017
11018    /**
11019     * @ngdoc method
11020     * @name ng.$sce#getTrusted
11021     * @methodOf ng.$sce
11022     *
11023     * @description
11024     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such, takes
11025     * the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the originally supplied
11026     * value if the queried context type is a supertype of the created type.  If this condition
11027     * isn't satisfied, throws an exception.
11028     *
11029     * @param {string} type The kind of context in which this value is to be used.
11030     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} call.
11031     * @returns {*} The value the was originally provided to {@link ng.$sce#trustAs `$sce.trustAs`} if
11032     *     valid in this context.  Otherwise, throws an exception.
11033     */
11034
11035    /**
11036     * @ngdoc method
11037     * @name ng.$sce#getTrustedHtml
11038     * @methodOf ng.$sce
11039     *
11040     * @description
11041     * Shorthand method.  `$sce.getTrustedHtml(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
11042     *
11043     * @param {*} value The value to pass to `$sce.getTrusted`.
11044     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
11045     */
11046
11047    /**
11048     * @ngdoc method
11049     * @name ng.$sce#getTrustedCss
11050     * @methodOf ng.$sce
11051     *
11052     * @description
11053     * Shorthand method.  `$sce.getTrustedCss(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
11054     *
11055     * @param {*} value The value to pass to `$sce.getTrusted`.
11056     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
11057     */
11058
11059    /**
11060     * @ngdoc method
11061     * @name ng.$sce#getTrustedUrl
11062     * @methodOf ng.$sce
11063     *
11064     * @description
11065     * Shorthand method.  `$sce.getTrustedUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
11066     *
11067     * @param {*} value The value to pass to `$sce.getTrusted`.
11068     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
11069     */
11070
11071    /**
11072     * @ngdoc method
11073     * @name ng.$sce#getTrustedResourceUrl
11074     * @methodOf ng.$sce
11075     *
11076     * @description
11077     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
11078     *
11079     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
11080     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
11081     */
11082
11083    /**
11084     * @ngdoc method
11085     * @name ng.$sce#getTrustedJs
11086     * @methodOf ng.$sce
11087     *
11088     * @description
11089     * Shorthand method.  `$sce.getTrustedJs(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
11090     *
11091     * @param {*} value The value to pass to `$sce.getTrusted`.
11092     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
11093     */
11094
11095    /**
11096     * @ngdoc method
11097     * @name ng.$sce#parseAsHtml
11098     * @methodOf ng.$sce
11099     *
11100     * @description
11101     * Shorthand method.  `$sce.parseAsHtml(expression string)` → {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
11102     *
11103     * @param {string} expression String expression to compile.
11104     * @returns {function(context, locals)} a function which represents the compiled expression:
11105     *
11106     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11107     *      are evaluated against (typically a scope object).
11108     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11109     *      `context`.
11110     */
11111
11112    /**
11113     * @ngdoc method
11114     * @name ng.$sce#parseAsCss
11115     * @methodOf ng.$sce
11116     *
11117     * @description
11118     * Shorthand method.  `$sce.parseAsCss(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
11119     *
11120     * @param {string} expression String expression to compile.
11121     * @returns {function(context, locals)} a function which represents the compiled expression:
11122     *
11123     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11124     *      are evaluated against (typically a scope object).
11125     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11126     *      `context`.
11127     */
11128
11129    /**
11130     * @ngdoc method
11131     * @name ng.$sce#parseAsUrl
11132     * @methodOf ng.$sce
11133     *
11134     * @description
11135     * Shorthand method.  `$sce.parseAsUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
11136     *
11137     * @param {string} expression String expression to compile.
11138     * @returns {function(context, locals)} a function which represents the compiled expression:
11139     *
11140     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11141     *      are evaluated against (typically a scope object).
11142     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11143     *      `context`.
11144     */
11145
11146    /**
11147     * @ngdoc method
11148     * @name ng.$sce#parseAsResourceUrl
11149     * @methodOf ng.$sce
11150     *
11151     * @description
11152     * Shorthand method.  `$sce.parseAsResourceUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
11153     *
11154     * @param {string} expression String expression to compile.
11155     * @returns {function(context, locals)} a function which represents the compiled expression:
11156     *
11157     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11158     *      are evaluated against (typically a scope object).
11159     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11160     *      `context`.
11161     */
11162
11163    /**
11164     * @ngdoc method
11165     * @name ng.$sce#parseAsJs
11166     * @methodOf ng.$sce
11167     *
11168     * @description
11169     * Shorthand method.  `$sce.parseAsJs(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
11170     *
11171     * @param {string} expression String expression to compile.
11172     * @returns {function(context, locals)} a function which represents the compiled expression:
11173     *
11174     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11175     *      are evaluated against (typically a scope object).
11176     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11177     *      `context`.
11178     */
11179
11180    // Shorthand delegations.
11181    var parse = sce.parseAs,
11182        getTrusted = sce.getTrusted,
11183        trustAs = sce.trustAs;
11184
11185    angular.forEach(SCE_CONTEXTS, function (enumValue, name) {
11186      var lName = lowercase(name);
11187      sce[camelCase("parse_as_" + lName)] = function (expr) {
11188        return parse(enumValue, expr);
11189      }
11190      sce[camelCase("get_trusted_" + lName)] = function (value) {
11191        return getTrusted(enumValue, value);
11192      }
11193      sce[camelCase("trust_as_" + lName)] = function (value) {
11194        return trustAs(enumValue, value);
11195      }
11196    });
11197
11198    return sce;
11199  }];
11200}
11201
11202/**
11203 * !!! This is an undocumented "private" service !!!
11204 *
11205 * @name ng.$sniffer
11206 * @requires $window
11207 * @requires $document
11208 *
11209 * @property {boolean} history Does the browser support html5 history api ?
11210 * @property {boolean} hashchange Does the browser support hashchange event ?
11211 * @property {boolean} transitions Does the browser support CSS transition events ?
11212 * @property {boolean} animations Does the browser support CSS animation events ?
11213 *
11214 * @description
11215 * This is very simple implementation of testing browser's features.
11216 */
11217function $SnifferProvider() {
11218  this.$get = ['$window', '$document', function($window, $document) {
11219    var eventSupport = {},
11220        android = int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
11221        document = $document[0] || {},
11222        vendorPrefix,
11223        vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
11224        bodyStyle = document.body && document.body.style,
11225        transitions = false,
11226        animations = false,
11227        match;
11228
11229    if (bodyStyle) {
11230      for(var prop in bodyStyle) {
11231        if(match = vendorRegex.exec(prop)) {
11232          vendorPrefix = match[0];
11233          vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
11234          break;
11235        }
11236      }
11237      transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
11238      animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
11239      
11240      if (android && (!transitions||!animations)) {
11241        transitions = isString(document.body.style.webkitTransition); 
11242        animations = isString(document.body.style.webkitAnimation); 
11243      }
11244    }
11245
11246
11247    return {
11248      // Android has history.pushState, but it does not update location correctly
11249      // so let's not use the history API at all.
11250      // http://code.google.com/p/android/issues/detail?id=17471
11251      // https://github.com/angular/angular.js/issues/904
11252      history: !!($window.history && $window.history.pushState && !(android < 4)),
11253      hashchange: 'onhashchange' in $window &&
11254                  // IE8 compatible mode lies
11255                  (!document.documentMode || document.documentMode > 7),
11256      hasEvent: function(event) {
11257        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
11258        // it. In particular the event is not fired when backspace or delete key are pressed or
11259        // when cut operation is performed.
11260        if (event == 'input' && msie == 9) return false;
11261
11262        if (isUndefined(eventSupport[event])) {
11263          var divElm = document.createElement('div');
11264          eventSupport[event] = 'on' + event in divElm;
11265        }
11266
11267        return eventSupport[event];
11268      },
11269      csp: document.securityPolicy ? document.securityPolicy.isActive : false,
11270      vendorPrefix: vendorPrefix,
11271      transitions : transitions,
11272      animations : animations
11273    };
11274  }];
11275}
11276
11277function $TimeoutProvider() {
11278  this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
11279       function($rootScope,   $browser,   $q,   $exceptionHandler) {
11280    var deferreds = {};
11281
11282
11283     /**
11284      * @ngdoc function
11285      * @name ng.$timeout
11286      * @requires $browser
11287      *
11288      * @description
11289      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
11290      * block and delegates any exceptions to
11291      * {@link ng.$exceptionHandler $exceptionHandler} service.
11292      *
11293      * The return value of registering a timeout function is a promise, which will be resolved when
11294      * the timeout is reached and the timeout function is executed.
11295      *
11296      * To cancel a timeout request, call `$timeout.cancel(promise)`.
11297      *
11298      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
11299      * synchronously flush the queue of deferred functions.
11300      *
11301      * @param {function()} fn A function, whose execution should be delayed.
11302      * @param {number=} [delay=0] Delay in milliseconds.
11303      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
11304      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
11305      * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
11306      *   promise will be resolved with is the return value of the `fn` function.
11307      */
11308    function timeout(fn, delay, invokeApply) {
11309      var deferred = $q.defer(),
11310          promise = deferred.promise,
11311          skipApply = (isDefined(invokeApply) && !invokeApply),
11312          timeoutId, cleanup;
11313
11314      timeoutId = $browser.defer(function() {
11315        try {
11316          deferred.resolve(fn());
11317        } catch(e) {
11318          deferred.reject(e);
11319          $exceptionHandler(e);
11320        }
11321
11322        if (!skipApply) $rootScope.$apply();
11323      }, delay);
11324
11325      cleanup = function() {
11326        delete deferreds[promise.$$timeoutId];
11327      };
11328
11329      promise.$$timeoutId = timeoutId;
11330      deferreds[timeoutId] = deferred;
11331      promise.then(cleanup, cleanup);
11332
11333      return promise;
11334    }
11335
11336
11337     /**
11338      * @ngdoc function
11339      * @name ng.$timeout#cancel
11340      * @methodOf ng.$timeout
11341      *
11342      * @description
11343      * Cancels a task associated with the `promise`. As a result of this, the promise will be
11344      * resolved with a rejection.
11345      *
11346      * @param {Promise=} promise Promise returned by the `$timeout` function.
11347      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
11348      *   canceled.
11349      */
11350    timeout.cancel = function(promise) {
11351      if (promise && promise.$$timeoutId in deferreds) {
11352        deferreds[promise.$$timeoutId].reject('canceled');
11353        return $browser.defer.cancel(promise.$$timeoutId);
11354      }
11355      return false;
11356    };
11357
11358    return timeout;
11359  }];
11360}
11361
11362function $$UrlUtilsProvider() {
11363  this.$get = [function() {
11364    var urlParsingNode = document.createElement("a"),
11365        // NOTE:  The usage of window and document instead of $window and $document here is
11366        // deliberate.  This service depends on the specific behavior of anchor nodes created by the
11367        // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
11368        // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
11369        // doesn't know about mocked locations and resolves URLs to the real document - which is
11370        // exactly the behavior needed here.  There is little value is mocking these our for this
11371        // service.
11372        originUrl = resolve(window.location.href, true);
11373
11374    /**
11375     * @description
11376     * Normalizes and optionally parses a URL.
11377     *
11378     * NOTE:  This is a private service.  The API is subject to change unpredictably in any commit.
11379     *
11380     * Implementation Notes for non-IE browsers
11381     * ----------------------------------------
11382     * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
11383     * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
11384     * URL will be resolved into an absolute URL in the context of the application document.
11385     * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
11386     * properties are all populated to reflect the normalized URL.  This approach has wide
11387     * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
11388     * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
11389     *
11390     * Implementation Notes for IE
11391     * ---------------------------
11392     * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
11393     * browsers.  However, the parsed components will not be set if the URL assigned did not specify
11394     * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
11395     * work around that by performing the parsing in a 2nd step by taking a previously normalized
11396     * URL (e.g. by assining to a.href) and assigning it a.href again.  This correctly populates the
11397     * properties such as protocol, hostname, port, etc.
11398     *
11399     * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
11400     * uses the inner HTML approach to assign the URL as part of an HTML snippet -
11401     * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
11402     * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
11403     * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
11404     * method and IE < 8 is unsupported.
11405     *
11406     * References:
11407     *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
11408     *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
11409     *   http://url.spec.whatwg.org/#urlutils
11410     *   https://github.com/angular/angular.js/pull/2902
11411     *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
11412     *
11413     * @param {string} url The URL to be parsed.
11414     * @param {boolean=} parse When true, returns an object for the parsed URL.  Otherwise, returns
11415     *   a single string that is the normalized URL.
11416     * @returns {object|string} When parse is true, returns the normalized URL as a string.
11417     * Otherwise, returns an object with the following members.
11418     *
11419     *   | member name   | Description    |
11420     *   |===============|================|
11421     *   | href          | A normalized version of the provided URL if it was not an absolute URL |
11422     *   | protocol      | The protocol including the trailing colon                              |
11423     *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
11424     *
11425     * These fields from the UrlUtils interface are currently not needed and hence not returned.
11426     *
11427     *   | member name   | Description    |
11428     *   |===============|================|
11429     *   | hostname      | The host without the port of the normalizedUrl                         |
11430     *   | pathname      | The path following the host in the normalizedUrl                       |
11431     *   | hash          | The URL hash if present                                                |
11432     *   | search        | The query string                                                       |
11433     *
11434     */
11435    function resolve(url, parse) {
11436      var href = url;
11437      if (msie) {
11438        // Normalize before parse.  Refer Implementation Notes on why this is
11439        // done in two steps on IE.
11440        urlParsingNode.setAttribute("href", href);
11441        href = urlParsingNode.href;
11442      }
11443      urlParsingNode.setAttribute('href', href);
11444
11445      if (!parse) {
11446        return urlParsingNode.href;
11447      }
11448      // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
11449      return {
11450        href: urlParsingNode.href,
11451        protocol: urlParsingNode.protocol,
11452        host: urlParsingNode.host
11453        // Currently unused and hence commented out.
11454        // hostname: urlParsingNode.hostname,
11455        // port: urlParsingNode.port,
11456        // pathname: urlParsingNode.pathname,
11457        // hash: urlParsingNode.hash,
11458        // search: urlParsingNode.search
11459      };
11460    }
11461
11462    return {
11463      resolve: resolve,
11464      /**
11465       * Parse a request URL and determine whether this is a same-origin request as the application document.
11466       *
11467       * @param {string|object} requestUrl The url of the request as a string that will be resolved
11468       * or a parsed URL object.
11469       * @returns {boolean} Whether the request is for the same origin as the application document.
11470       */
11471      isSameOrigin: function isSameOrigin(requestUrl) {
11472        var parsed = (typeof requestUrl === 'string') ? resolve(requestUrl, true) : requestUrl;
11473        return (parsed.protocol === originUrl.protocol &&
11474                parsed.host === originUrl.host);
11475      }
11476    };
11477  }];
11478}
11479
11480/**
11481 * @ngdoc object
11482 * @name ng.$window
11483 *
11484 * @description
11485 * A reference to the browser's `window` object. While `window`
11486 * is globally available in JavaScript, it causes testability problems, because
11487 * it is a global variable. In angular we always refer to it through the
11488 * `$window` service, so it may be overridden, removed or mocked for testing.
11489 *
11490 * Expressions, like the one defined for the `ngClick` directive in the example
11491 * below, are evaluated with respect to the current scope.  Therefore, there is
11492 * no risk of inadvertently coding in a dependency on a global value in such an
11493 * expression.
11494 *
11495 * @example
11496   <doc:example>
11497     <doc:source>
11498       <script>
11499         function Ctrl($scope, $window) {
11500           $scope.$window = $window;
11501           $scope.greeting = 'Hello, World!';
11502         }
11503       </script>
11504       <div ng-controller="Ctrl">
11505         <input type="text" ng-model="greeting" />
11506         <button ng-click="$window.alert(greeting)">ALERT</button>
11507       </div>
11508     </doc:source>
11509     <doc:scenario>
11510      it('should display the greeting in the input box', function() {
11511       input('greeting').enter('Hello, E2E Tests');
11512       // If we click the button it will block the test runner
11513       // element(':button').click();
11514      });
11515     </doc:scenario>
11516   </doc:example>
11517 */
11518function $WindowProvider(){
11519  this.$get = valueFn(window);
11520}
11521
11522/**
11523 * @ngdoc object
11524 * @name ng.$filterProvider
11525 * @description
11526 *
11527 * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
11528 * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
11529 * responsible for creating a filter function.
11530 *
11531 * <pre>
11532 *   // Filter registration
11533 *   function MyModule($provide, $filterProvider) {
11534 *     // create a service to demonstrate injection (not always needed)
11535 *     $provide.value('greet', function(name){
11536 *       return 'Hello ' + name + '!';
11537 *     });
11538 *
11539 *     // register a filter factory which uses the
11540 *     // greet service to demonstrate DI.
11541 *     $filterProvider.register('greet', function(greet){
11542 *       // return the filter function which uses the greet service
11543 *       // to generate salutation
11544 *       return function(text) {
11545 *         // filters need to be forgiving so check input validity
11546 *         return text && greet(text) || text;
11547 *       };
11548 *     });
11549 *   }
11550 * </pre>
11551 *
11552 * The filter function is registered with the `$injector` under the filter name suffix with `Filter`.
11553 * <pre>
11554 *   it('should be the same instance', inject(
11555 *     function($filterProvider) {
11556 *       $filterProvider.register('reverse', function(){
11557 *         return ...;
11558 *       });
11559 *     },
11560 *     function($filter, reverseFilter) {
11561 *       expect($filter('reverse')).toBe(reverseFilter);
11562 *     });
11563 * </pre>
11564 *
11565 *
11566 * For more information about how angular filters work, and how to create your own filters, see
11567 * {@link guide/dev_guide.templates.filters Understanding Angular Filters} in the angular Developer
11568 * Guide.
11569 */
11570/**
11571 * @ngdoc method
11572 * @name ng.$filterProvider#register
11573 * @methodOf ng.$filterProvider
11574 * @description
11575 * Register filter factory function.
11576 *
11577 * @param {String} name Name of the filter.
11578 * @param {function} fn The filter factory function which is injectable.
11579 */
11580
11581
11582/**
11583 * @ngdoc function
11584 * @name ng.$filter
11585 * @function
11586 * @description
11587 * Filters are used for formatting data displayed to the user.
11588 *
11589 * The general syntax in templates is as follows:
11590 *
11591 *         {{ expression [| filter_name[:parameter_value] ... ] }}
11592 *
11593 * @param {String} name Name of the filter function to retrieve
11594 * @return {Function} the filter function
11595 */
11596$FilterProvider.$inject = ['$provide'];
11597function $FilterProvider($provide) {
11598  var suffix = 'Filter';
11599
11600  function register(name, factory) {
11601    return $provide.factory(name + suffix, factory);
11602  }
11603  this.register = register;
11604
11605  this.$get = ['$injector', function($injector) {
11606    return function(name) {
11607      return $injector.get(name + suffix);
11608    }
11609  }];
11610
11611  ////////////////////////////////////////
11612
11613  register('currency', currencyFilter);
11614  register('date', dateFilter);
11615  register('filter', filterFilter);
11616  register('json', jsonFilter);
11617  register('limitTo', limitToFilter);
11618  register('lowercase', lowercaseFilter);
11619  register('number', numberFilter);
11620  register('orderBy', orderByFilter);
11621  register('uppercase', uppercaseFilter);
11622}
11623
11624/**
11625 * @ngdoc filter
11626 * @name ng.filter:filter
11627 * @function
11628 *
11629 * @description
11630 * Selects a subset of items from `array` and returns it as a new array.
11631 *
11632 * Note: This function is used to augment the `Array` type in Angular expressions. See
11633 * {@link ng.$filter} for more information about Angular arrays.
11634 *
11635 * @param {Array} array The source array.
11636 * @param {string|Object|function()} expression The predicate to be used for selecting items from
11637 *   `array`.
11638 *
11639 *   Can be one of:
11640 *
11641 *   - `string`: Predicate that results in a substring match using the value of `expression`
11642 *     string. All strings or objects with string properties in `array` that c
11642ontain this string
11643 *     will be returned. The predicate can be negated by prefixing the string with `!`.
11644 *
11645 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
11646 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
11647 *     which have property `name` containing "M" and property `phone` containing "1". A special
11648 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
11649 *     property of the object. That's equivalent to the simple substring match with a `string`
11650 *     as described above.
11651 *
11652 *   - `function`: A predicate function can be used to write arbitrary filters. The function is
11653 *     called for each element of `array`. The final result is an array of those elements that
11654 *     the predicate returned true for.
11655 *
11656 * @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
11657 *     determining if the expected value (from the filter expression) and actual value (from
11658 *     the object in the array) should be considered a match.
11659 *
11660 *   Can be one of:
11661 *
11662 *     - `function(expected, actual)`:
11663 *       The function will be given the object value and the predicate value to compare and
11664 *       should return true if the item should be included in filtered result.
11665 *
11666 *     - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`.
11667 *       this is essentially strict comparison of expected and actual.
11668 *
11669 *     - `false|undefined`: A short hand for a function which will look for a substring match in case
11670 *       insensitive way.
11671 *
11672 * @example
11673   <doc:example>
11674     <doc:source>
11675       <div ng-init="friends = [{name:'John', phone:'555-1276'},
11676                                {name:'Mary', phone:'800-BIG-MARY'},
11677                                {name:'Mike', phone:'555-4321'},
11678                                {name:'Adam', phone:'555-5678'},
11679                                {name:'Julie', phone:'555-8765'},
11680                                {name:'Juliette', phone:'555-5678'}]"></div>
11681
11682       Search: <input ng-model="searchText">
11683       <table id="searchTextResults">
11684         <tr><th>Name</th><th>Phone</th></tr>
11685         <tr ng-repeat="friend in friends | filter:searchText">
11686           <td>{{friend.name}}</td>
11687           <td>{{friend.phone}}</td>
11688         </tr>
11689       </table>
11690       <hr>
11691       Any: <input ng-model="search.$"> <br>
11692       Name only <input ng-model="search.name"><br>
11693       Phone only <input ng-model="search.phone"><br>
11694       Equality <input type="checkbox" ng-model="strict"><br>
11695       <table id="searchObjResults">
11696         <tr><th>Name</th><th>Phone</th></tr>
11697         <tr ng-repeat="friend in friends | filter:search:strict">
11698           <td>{{friend.name}}</td>
11699           <td>{{friend.phone}}</td>
11700         </tr>
11701       </table>
11702     </doc:source>
11703     <doc:scenario>
11704       it('should search across all fields when filtering with a string', function() {
11705         input('searchText').enter('m');
11706         expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
11707           toEqual(['Mary', 'Mike', 'Adam']);
11708
11709         input('searchText').enter('76');
11710         expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
11711           toEqual(['John', 'Julie']);
11712       });
11713
11714       it('should search in specific fields when filtering with a predicate object', function() {
11715         input('search.$').enter('i');
11716         expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
11717           toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
11718       });
11719       it('should use a equal comparison when comparator is true', function() {
11720         input('search.name').enter('Julie');
11721         input('strict').check();
11722         expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
11723           toEqual(['Julie']);
11724       });
11725     </doc:scenario>
11726   </doc:example>
11727 */
11728function filterFilter() {
11729  return function(array, expression, comperator) {
11730    if (!isArray(array)) return array;
11731    var predicates = [];
11732    predicates.check = function(value) {
11733      for (var j = 0; j < predicates.length; j++) {
11734        if(!predicates[j](value)) {
11735          return false;
11736        }
11737      }
11738      return true;
11739    };
11740    switch(typeof comperator) {
11741      case "function":
11742        break;
11743      case "boolean":
11744        if(comperator == true) {
11745          comperator = function(obj, text) {
11746            return angular.equals(obj, text);
11747          }
11748          break;
11749        }
11750      default:
11751        comperator = function(obj, text) {
11752          text = (''+text).toLowerCase();
11753          return (''+obj).toLowerCase().indexOf(text) > -1
11754        };
11755    }
11756    var search = function(obj, text){
11757      if (typeof text == 'string' && text.charAt(0) === '!') {
11758        return !search(obj, text.substr(1));
11759      }
11760      switch (typeof obj) {
11761        case "boolean":
11762        case "number":
11763        case "string":
11764          return comperator(obj, text);
11765        case "object":
11766          switch (typeof text) {
11767            case "object":
11768              return comperator(obj, text);
11769              break;
11770            default:
11771              for ( var objKey in obj) {
11772                if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
11773                  return true;
11774                }
11775              }
11776              break;
11777          }
11778          return false;
11779        case "array":
11780          for ( var i = 0; i < obj.length; i++) {
11781            if (search(obj[i], text)) {
11782              return true;
11783            }
11784          }
11785          return false;
11786        default:
11787          return false;
11788      }
11789    };
11790    switch (typeof expression) {
11791      case "boolean":
11792      case "number":
11793      case "string":
11794        expression = {$:expression};
11795      case "object":
11796        for (var key in expression) {
11797          if (key == '$') {
11798            (function() {
11799              if (!expression[key]) return;
11800              var path = key
11801              predicates.push(function(value) {
11802                return search(value, expression[path]);
11803              });
11804            })();
11805          } else {
11806            (function() {
11807              if (!expression[key]) return;
11808              var path = key;
11809              predicates.push(function(value) {
11810                return search(getter(value,path), expression[path]);
11811              });
11812            })();
11813          }
11814        }
11815        break;
11816      case 'function':
11817        predicates.push(expression);
11818        break;
11819      default:
11820        return array;
11821    }
11822    var filtered = [];
11823    for ( var j = 0; j < array.length; j++) {
11824      var value = array[j];
11825      if (predicates.check(value)) {
11826        filtered.push(value);
11827      }
11828    }
11829    return filtered;
11830  }
11831}
11832
11833/**
11834 * @ngdoc filter
11835 * @name ng.filter:currency
11836 * @function
11837 *
11838 * @description
11839 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
11840 * symbol for current locale is used.
11841 *
11842 * @param {number} amount Input to filter.
11843 * @param {string=} symbol Currency symbol or identifier to be displayed.
11844 * @returns {string} Formatted number.
11845 *
11846 *
11847 * @example
11848   <doc:example>
11849     <doc:source>
11850       <script>
11851         function Ctrl($scope) {
11852           $scope.amount = 1234.56;
11853         }
11854       </script>
11855       <div ng-controller="Ctrl">
11856         <input type="number" ng-model="amount"> <br>
11857         default currency symbol ($): {{amount | currency}}<br>
11858         custom currency identifier (USD$): {{amount | currency:"USD$"}}
11859       </div>
11860     </doc:source>
11861     <doc:scenario>
11862       it('should init with 1234.56', function() {
11863         expect(binding('amount | currency')).toBe('$1,234.56');
11864         expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
11865       });
11866       it('should update', function() {
11867         input('amount').enter('-1234');
11868         expect(binding('amount | currency')).toBe('($1,234.00)');
11869         expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
11870       });
11871     </doc:scenario>
11872   </doc:example>
11873 */
11874currencyFilter.$inject = ['$locale'];
11875function currencyFilter($locale) {
11876  var formats = $locale.NUMBER_FORMATS;
11877  return function(amount, currencySymbol){
11878    if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
11879    return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
11880                replace(/\u00A4/g, currencySymbol);
11881  };
11882}
11883
11884/**
11885 * @ngdoc filter
11886 * @name ng.filter:number
11887 * @function
11888 *
11889 * @description
11890 * Formats a number as text.
11891 *
11892 * If the input is not a number an empty string is returned.
11893 *
11894 * @param {number|string} number Number to format.
11895 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
11896 * If this is not provided then the fraction size is computed from the current locale's number
11897 * formatting pattern. In the case of the default locale, it will be 3.
11898 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
11899 *
11900 * @example
11901   <doc:example>
11902     <doc:source>
11903       <script>
11904         function Ctrl($scope) {
11905           $scope.val = 1234.56789;
11906         }
11907       </script>
11908       <div ng-controller="Ctrl">
11909         Enter number: <input ng-model='val'><br>
11910         Default formatting: {{val | number}}<br>
11911         No fractions: {{val | number:0}}<br>
11912         Negative number: {{-val | number:4}}
11913       </div>
11914     </doc:source>
11915     <doc:scenario>
11916       it('should format numbers', function() {
11917         expect(binding('val | number')).toBe('1,234.568');
11918         expect(binding('val | number:0')).toBe('1,235');
11919         expect(binding('-val | number:4')).toBe('-1,234.5679');
11920       });
11921
11922       it('should update', function() {
11923         input('val').enter('3374.333');
11924         expect(binding('val | number')).toBe('3,374.333');
11925         expect(binding('val | number:0')).toBe('3,374');
11926         expect(binding('-val | number:4')).toBe('-3,374.3330');
11927       });
11928     </doc:scenario>
11929   </doc:example>
11930 */
11931
11932
11933numberFilter.$inject = ['$locale'];
11934function numberFilter($locale) {
11935  var formats = $locale.NUMBER_FORMATS;
11936  return function(number, fractionSize) {
11937    return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
11938      fractionSize);
11939  };
11940}
11941
11942var DECIMAL_SEP = '.';
11943function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
11944  if (isNaN(number) || !isFinite(number)) return '';
11945
11946  var isNegative = number < 0;
11947  number = Math.abs(number);
11948  var numStr = number + '',
11949      formatedText = '',
11950      parts = [];
11951
11952  var hasExponent = false;
11953  if (numStr.indexOf('e') !== -1) {
11954    var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
11955    if (match && match[2] == '-' && match[3] > fractionSize + 1) {
11956      numStr = '0';
11957    } else {
11958      formatedText = numStr;
11959      hasExponent = true;
11960    }
11961  }
11962
11963  if (!hasExponent) {
11964    var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
11965
11966    // determine fractionSize if it is not specified
11967    if (isUndefined(fractionSize)) {
11968      fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
11969    }
11970
11971    var pow = Math.pow(10, fractionSize);
11972    number = Math.round(number * pow) / pow;
11973    var fraction = ('' + number).split(DECIMAL_SEP);
11974    var whole = fraction[0];
11975    fraction = fraction[1] || '';
11976
11977    var pos = 0,
11978        lgroup = pattern.lgSize,
11979        group = pattern.gSize;
11980
11981    if (whole.length >= (lgroup + group)) {
11982      pos = whole.length - lgroup;
11983      for (var i = 0; i < pos; i++) {
11984        if ((pos - i)%group === 0 && i !== 0) {
11985          formatedText += groupSep;
11986        }
11987        formatedText += whole.charAt(i);
11988      }
11989    }
11990
11991    for (i = pos; i < whole.length; i++) {
11992      if ((whole.length - i)%lgroup === 0 && i !== 0) {
11993        formatedText += groupSep;
11994      }
11995      formatedText += whole.charAt(i);
11996    }
11997
11998    // format fraction part.
11999    while(fraction.length < fractionSize) {
12000      fraction += '0';
12001    }
12002
12003    if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
12004  } else {
12005
12006    if (fractionSize > 0 && number > -1 && number < 1) {
12007      formatedText = number.toFixed(fractionSize);
12008    }
12009  }
12010
12011  parts.push(isNegative ? pattern.negPre : pattern.posPre);
12012  parts.push(formatedText);
12013  parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
12014  return parts.join('');
12015}
12016
12017function padNumber(num, digits, trim) {
12018  var neg = '';
12019  if (num < 0) {
12020    neg =  '-';
12021    num = -num;
12022  }
12023  num = '' + num;
12024  while(num.length < digits) num = '0' + num;
12025  if (trim)
12026    num = num.substr(num.length - digits);
12027  return neg + num;
12028}
12029
12030
12031function dateGetter(name, size, offset, trim) {
12032  offset = offset || 0;
12033  return function(date) {
12034    var value = date['get' + name]();
12035    if (offset > 0 || value > -offset)
12036      value += offset;
12037    if (value === 0 && offset == -12 ) value = 12;
12038    return padNumber(value, size, trim);
12039  };
12040}
12041
12042function dateStrGetter(name, shortForm) {
12043  return function(date, formats) {
12044    var value = date['get' + name]();
12045    var get = uppercase(shortForm ? ('SHORT' + name) : name);
12046
12047    return formats[get][value];
12048  };
12049}
12050
12051function timeZoneGetter(date) {
12052  var zone = -1 * date.getTimezoneOffset();
12053  var paddedZone = (zone >= 0) ? "+" : "";
12054
12055  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
12056                padNumber(Math.abs(zone % 60), 2);
12057
12058  return paddedZone;
12059}
12060
12061function ampmGetter(date, formats) {
12062  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
12063}
12064
12065var DATE_FORMATS = {
12066  yyyy: dateGetter('FullYear', 4),
12067    yy: dateGetter('FullYear', 2, 0, true),
12068     y: dateGetter('FullYear', 1),
12069  MMMM: dateStrGetter('Month'),
12070   MMM: dateStrGetter('Month', true),
12071    MM: dateGetter('Month', 2, 1),
12072     M: dateGetter('Month', 1, 1),
12073    dd: dateGetter('Date', 2),
12074     d: dateGetter('Date', 1),
12075    HH: dateGetter('Hours', 2),
12076     H: dateGetter('Hours', 1),
12077    hh: dateGetter('Hours', 2, -12),
12078     h: dateGetter('Hours', 1, -12),
12079    mm: dateGetter('Minutes', 2),
12080     m: dateGetter('Minutes', 1),
12081    ss: dateGetter('Seconds', 2),
12082     s: dateGetter('Seconds', 1),
12083     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
12084     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
12085   sss: dateGetter('Milliseconds', 3),
12086  EEEE: dateStrGetter('Day'),
12087   EEE: dateStrGetter('Day', true),
12088     a: ampmGetter,
12089     Z: timeZoneGetter
12090};
12091
12092var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
12093    NUMBER_STRING = /^\d+$/;
12094
12095/**
12096 * @ngdoc filter
12097 * @name ng.filter:date
12098 * @function
12099 *
12100 * @description
12101 *   Formats `date` to a string based on the requested `format`.
12102 *
12103 *   `format` string can be composed of the following elements:
12104 *
12105 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
12106 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
12107 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
12108 *   * `'MMMM'`: Month in year (January-December)
12109 *   * `'MMM'`: Month in year (Jan-Dec)
12110 *   * `'MM'`: Month in year, padded (01-12)
12111 *   * `'M'`: Month in year (1-12)
12112 *   * `'dd'`: Day in month, padded (01-31)
12113 *   * `'d'`: Day in month (1-31)
12114 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
12115 *   * `'EEE'`: Day in Week, (Sun-Sat)
12116 *   * `'HH'`: Hour in day, padded (00-23)
12117 *   * `'H'`: Hour in day (0-23)
12118 *   * `'hh'`: Hour in am/pm, padded (01-12)
12119 *   * `'h'`: Hour in am/pm, (1-12)
12120 *   * `'mm'`: Minute in hour, padded (00-59)
12121 *   * `'m'`: Minute in hour (0-59)
12122 *   * `'ss'`: Second in minute, padded (00-59)
12123 *   * `'s'`: Second in minute (0-59)
12124 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
12125 *   * `'a'`: am/pm marker
12126 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
12127 *
12128 *   `format` string can also be one of the following predefined
12129 *   {@link guide/i18n localizable formats}:
12130 *
12131 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
12132 *     (e.g. Sep 3, 2010 12:05:08 pm)
12133 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
12134 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
12135 *     (e.g. Friday, September 3, 2010)
12136 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
12137 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
12138 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
12139 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
12140 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
12141 *
12142 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
12143 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
12144 *   (e.g. `"h 'o''clock'"`).
12145 *
12146 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
12147 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
12148 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
12149 *    specified in the string input, the time is considered to be in the local timezone.
12150 * @param {string=} format Formatting rules (see Description). If not specified,
12151 *    `mediumDate` is used.
12152 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
12153 *
12154 * @example
12155   <doc:example>
12156     <doc:source>
12157       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
12158           {{1288323623006 | date:'medium'}}<br>
12159       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
12160          {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
12161       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
12162          {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
12163     </doc:source>
12164     <doc:scenario>
12165       it('should format date', function() {
12166         expect(binding("1288323623006 | date:'medium'")).
12167            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
12168         expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
12169            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
12170         expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
12171            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
12172       });
12173     </doc:scenario>
12174   </doc:example>
12175 */
12176dateFilter.$inject = ['$locale'];
12177function dateFilter($locale) {
12178
12179
12180  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
12181                     // 1        2       3         4          5          6          7          8  9     10      11
12182  function jsonStringToDate(string) {
12183    var match;
12184    if (match = string.match(R_ISO8601_STR)) {
12185      var date = new Date(0),
12186          tzHour = 0,
12187          tzMin  = 0,
12188          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
12189          timeSetter = match[8] ? date.setUTCHours : date.setHours;
12190
12191      if (match[9]) {
12192        tzHour = int(match[9] + match[10]);
12193        tzMin = int(match[9] + match[11]);
12194      }
12195      dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
12196      var h = int(match[4]||0) - tzHour;
12197      var m = int(match[5]||0) - tzMin
12198      var s = int(match[6]||0);
12199      var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
12200      timeSetter.call(date, h, m, s, ms);
12201      return date;
12202    }
12203    return string;
12204  }
12205
12206
12207  return function(date, format) {
12208    var text = '',
12209        parts = [],
12210        fn, match;
12211
12212    format = format || 'mediumDate';
12213    format = $locale.DATETIME_FORMATS[format] || format;
12214    if (isString(date)) {
12215      if (NUMBER_STRING.test(date)) {
12216        date = int(date);
12217      } else {
12218        date = jsonStringToDate(date);
12219      }
12220    }
12221
12222    if (isNumber(date)) {
12223      date = new Date(date);
12224    }
12225
12226    if (!isDate(date)) {
12227      return date;
12228    }
12229
12230    while(format) {
12231      match = DATE_FORMATS_SPLIT.exec(format);
12232      if (match) {
12233        parts = concat(parts, match, 1);
12234        format = parts.pop();
12235      } else {
12236        parts.push(format);
12237        format = null;
12238      }
12239    }
12240
12241    forEach(parts, function(value){
12242      fn = DATE_FORMATS[value];
12243      text += fn ? fn(date, $locale.DATETIME_FORMATS)
12244                 : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
12245    });
12246
12247    return text;
12248  };
12249}
12250
12251
12252/**
12253 * @ngdoc filter
12254 * @name ng.filter:json
12255 * @function
12256 *
12257 * @description
12258 *   Allows you to convert a JavaScript object into JSON string.
12259 *
12260 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
12261 *   the binding is automatically converted to JSON.
12262 *
12263 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
12264 * @returns {string} JSON string.
12265 *
12266 *
12267 * @example:
12268   <doc:example>
12269     <doc:source>
12270       <pre>{{ {'name':'value'} | json }}</pre>
12271     </doc:source>
12272     <doc:scenario>
12273       it('should jsonify filtered objects', function() {
12274         expect(binding("{'name':'value'}")).toMatch(/\{\n  "name": ?"value"\n}/);
12275       });
12276     </doc:scenario>
12277   </doc:example>
12278 *
12279 */
12280function jsonFilter() {
12281  return function(object) {
12282    return toJson(object, true);
12283  };
12284}
12285
12286
12287/**
12288 * @ngdoc filter
12289 * @name ng.filter:lowercase
12290 * @function
12291 * @description
12292 * Converts string to lowercase.
12293 * @see angular.lowercase
12294 */
12295var lowercaseFilter = valueFn(lowercase);
12296
12297
12298/**
12299 * @ngdoc filter
12300 * @name ng.filter:uppercase
12301 * @function
12302 * @description
12303 * Converts string to uppercase.
12304 * @see angular.uppercase
12305 */
12306var uppercaseFilter = valueFn(uppercase);
12307
12308/**
12309 * @ngdoc function
12310 * @name ng.filter:limitTo
12311 * @function
12312 *
12313 * @description
12314 * Creates a new array or string containing only a specified number of elements. The elements
12315 * are taken from either the beginning or the end of the source array or string, as specified by
12316 * the value and sign (positive or negative) of `limit`.
12317 *
12318 * Note: This function is used to augment the `Array` type in Angular expressions. See
12319 * {@link ng.$filter} for more information about Angular arrays.
12320 *
12321 * @param {Array|string} input Source array or string to be limited.
12322 * @param {string|number} limit The length of the returned array or string. If the `limit` number 
12323 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
12324 *     If the number is negative, `limit` number  of items from the end of the source array/string 
12325 *     are copied. The `limit` will be trimmed if it exceeds `array.length`
12326 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
12327 *     had less than `limit` elements.
12328 *
12329 * @example
12330   <doc:example>
12331     <doc:source>
12332       <script>
12333         function Ctrl($scope) {
12334           $scope.numbers = [1,2,3,4,5,6,7,8,9];
12335           $scope.letters = "abcdefghi";
12336           $scope.numLimit = 3;
12337           $scope.letterLimit = 3;
12338         }
12339       </script>
12340       <div ng-controller="Ctrl">
12341         Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
12342         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
12343         Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
12344         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
12345       </div>
12346     </doc:source>
12347     <doc:scenario>
12348       it('should limit the number array to first three items', function() {
12349         expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
12350         expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
12351         expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
12352         expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
12353       });
12354
12355       it('should update the output when -3 is entered', function() {
12356         input('numLimit').enter(-3);
12357         input('letterLimit').enter(-3);
12358         expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
12359         expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
12360       });
12361
12362       it('should not exceed the maximum size of input array', function() {
12363         input('numLimit').enter(100);
12364         input('letterLimit').enter(100);
12365         expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
12366         expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
12367       });
12368     </doc:scenario>
12369   </doc:example>
12370 */
12371function limitToFilter(){
12372  return function(input, limit) {
12373    if (!isArray(input) && !isString(input)) return input;
12374    
12375    limit = int(limit);
12376
12377    if (isString(input)) {
12378      //NaN check on limit
12379      if (limit) {
12380        return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
12381      } else {
12382        return "";
12383      }
12384    }
12385
12386    var out = [],
12387      i, n;
12388
12389    // if abs(limit) exceeds maximum length, trim it
12390    if (limit > input.length)
12391      limit = input.length;
12392    else if (limit < -input.length)
12393      limit = -input.length;
12394
12395    if (limit > 0) {
12396      i = 0;
12397      n = limit;
12398    } else {
12399      i = input.length + limit;
12400      n = input.length;
12401    }
12402
12403    for (; i<n; i++) {
12404      out.push(input[i]);
12405    }
12406
12407    return out;
12408  }
12409}
12410
12411/**
12412 * @ngdoc function
12413 * @name ng.filter:orderBy
12414 * @function
12415 *
12416 * @description
12417 * Orders a specified `array` by the `expression` predicate.
12418 *
12419 * Note: this function is used to augment the `Array` type in Angular expressions. See
12420 * {@link ng.$filter} for more information about Angular arrays.
12421 *
12422 * @param {Array} array The array to sort.
12423 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
12424 *    used by the comparator to determine the order of elements.
12425 *
12426 *    Can be one of:
12427 *
12428 *    - `function`: Getter function. The result of this function will be sorted using the
12429 *      `<`, `=`, `>` operator.
12430 *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
12431 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
12432 *      ascending or descending sort order (for example, +name or -name).
12433 *    - `Array`: An array of function or string predicates. The first predicate in the array
12434 *      is used for sorting, but when two items are equivalent, the next predicate is used.
12435 *
12436 * @param {boolean=} reverse Reverse the order the array.
12437 * @returns {Array} Sorted copy of the source array.
12438 *
12439 * @example
12440   <doc:example>
12441     <doc:source>
12442       <script>
12443         function Ctrl($scope) {
12444           $scope.friends =
12445               [{name:'John', phone:'555-1212', age:10},
12446                {name:'Mary', phone:'555-9876', age:19},
12447                {name:'Mike', phone:'555-4321', age:21},
12448                {name:'Adam', phone:'555-5678', age:35},
12449                {name:'Julie', phone:'555-8765', age:29}]
12450           $scope.predicate = '-age';
12451         }
12452       </script>
12453       <div ng-controller="Ctrl">
12454         <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
12455         <hr/>
12456         [ <a href="" ng-click="predicate=''">unsorted</a> ]
12457         <table class="friend">
12458           <tr>
12459             <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
12460                 (<a href ng-click="predicate = '-name'; reverse=false">^</a>)</th>
12461             <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
12462             <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
12463           </tr>
12464           <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
12465             <td>{{friend.name}}</td>
12466             <td>{{friend.phone}}</td>
12467             <td>{{friend.age}}</td>
12468           </tr>
12469         </table>
12470       </div>
12471     </doc:source>
12472     <doc:scenario>
12473       it('should be reverse ordered by aged', function() {
12474         expect(binding('predicate')).toBe('-age');
12475         expect(repeater('table.friend', 'friend in friends').column('friend.age')).
12476           toEqual(['35', '29', '21', '19', '10']);
12477         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
12478           toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
12479       });
12480
12481       it('should reorder the table when user selects different predicate', function() {
12482         element('.doc-example-live a:contains("Name")').click();
12483         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
12484           toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
12485         expect(repeater('table.friend', 'friend in friends').column('friend.age')).
12486           toEqual(['35', '10', '29', '19', '21']);
12487
12488         element('.doc-example-live a:contains("Phone")').click();
12489         expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
12490           toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
12491         expect(repeater('table.friend', 'friend in friends').column('friend.name')).
12492           toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
12493       });
12494     </doc:scenario>
12495   </doc:example>
12496 */
12497orderByFilter.$inject = ['$parse'];
12498function orderByFilter($parse){
12499  return function(array, sortPredicate, reverseOrder) {
12500    if (!isArray(array)) return array;
12501    if (!sortPredicate) return array;
12502    sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
12503    sortPredicate = map(sortPredicate, function(predicate){
12504      var descending = false, get = predicate || identity;
12505      if (isString(predicate)) {
12506        if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
12507          descending = predicate.charAt(0) == '-';
12508          predicate = predicate.substring(1);
12509        }
12510        get = $parse(predicate);
12511      }
12512      return reverseComparator(function(a,b){
12513        return compare(get(a),get(b));
12514      }, descending);
12515    });
12516    var arrayCopy = [];
12517    for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
12518    return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
12519
12520    function comparator(o1, o2){
12521      for ( var i = 0; i < sortPredicate.length; i++) {
12522        var comp = sortPredicate[i](o1, o2);
12523        if (comp !== 0) return comp;
12524      }
12525      return 0;
12526    }
12527    function reverseComparator(comp, descending) {
12528      return toBoolean(descending)
12529          ? function(a,b){return comp(b,a);}
12530          : comp;
12531    }
12532    function compare(v1, v2){
12533      var t1 = typeof v1;
12534      var t2 = typeof v2;
12535      if (t1 == t2) {
12536        if (t1 == "string") v1 = v1.toLowerCase();
12537        if (t1 == "string") v2 = v2.toLowerCase();
12538        if (v1 === v2) return 0;
12539        return v1 < v2 ? -1 : 1;
12540      } else {
12541        return t1 < t2 ? -1 : 1;
12542      }
12543    }
12544  }
12545}
12546
12547function ngDirective(directive) {
12548  if (isFunction(directive)) {
12549    directive = {
12550      link: directive
12551    }
12552  }
12553  directive.restrict = directive.restrict || 'AC';
12554  return valueFn(directive);
12555}
12556
12557/**
12558 * @ngdoc directive
12559 * @name ng.directive:a
12560 * @restrict E
12561 *
12562 * @description
12563 * Modifies the default behavior of html A tag, so that the default action is prevented when href
12564 * attribute is empty.
12565 *
12566 * The reasoning for this change is to allow easy creation of action links with `ngClick` directive
12567 * without changing the location or causing page reloads, e.g.:
12568 * `<a href="" ng-click="model.$save()">Save</a>`
12569 */
12570var htmlAnchorDirective = valueFn({
12571  restrict: 'E',
12572  compile: function(element, attr) {
12573
12574    if (msie <= 8) {
12575
12576      // turn <a href ng-click="..">link</a> into a stylable link in IE
12577      // but only if it doesn't have name attribute, in which case it's an anchor
12578      if (!attr.href && !attr.name) {
12579        attr.$set('href', '');
12580      }
12581
12582      // add a comment node to anchors to workaround IE bug that causes element content to be reset
12583      // to new attribute content if attribute is updated with value containing @ and element also
12584      // contains value with @
12585      // see issue #1949
12586      element.append(document.createComment('IE fix'));
12587    }
12588
12589    return function(scope, element) {
12590      element.on('click', function(event){
12591        // if we have no href url, then don't navigate anywhere.
12592        if (!element.attr('href')) {
12593          event.preventDefault();
12594        }
12595      });
12596    }
12597  }
12598});
12599
12600/**
12601 * @ngdoc directive
12602 * @name ng.directive:ngHref
12603 * @restrict A
12604 *
12605 * @description
12606 * Using Angular markup like {{hash}} in an href attribute makes
12607 * the page open to a wrong URL, if the user clicks that link before
12608 * angular has a chance to replace the {{hash}} with actual URL, the
12609 * link will be broken and will most likely return a 404 error.
12610 * The `ngHref` directive solves this problem.
12611 *
12612 * The buggy way to write it:
12613 * <pre>
12614 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
12615 * </pre>
12616 *
12617 * The correct way to write it:
12618 * <pre>
12619 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
12620 * </pre>
12621 *
12622 * @element A
12623 * @param {template} ngHref any string which can contain `{{}}` markup.
12624 *
12625 * @example
12626 * This example uses `link` variable inside `href` attribute:
12627    <doc:example>
12628      <doc:source>
12629        <input ng-model="value" /><br />
12630        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
12631        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
12632        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
12633        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
12634        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
12635        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
12636      </doc:source>
12637      <doc:scenario>
12638        it('should execute ng-click but not reload when href without value', function() {
12639          element('#link-1').click();
12640          expect(input('value').val()).toEqual('1');
12641          expect(element('#link-1').attr('href')).toBe("");
12642        });
12643
12644        it('should execute ng-click but not reload when href empty string', function() {
12645          element('#link-2').click();
12646          expect(input('value').val()).toEqual('2');
12647          expect(element('#link-2').attr('href')).toBe("");
12648        });
12649
12650        it('should execute ng-click and change url when ng-href specified', function() {
12651          expect(element('#link-3').attr('href')).toBe("/123");
12652
12653          element('#link-3').click();
12654          expect(browser().window().path()).toEqual('/123');
12655        });
12656
12657        it('should execute ng-click but not reload when href empty string and name specified', function() {
12658          element('#link-4').click();
12659          expect(input('value').val()).toEqual('4');
12660          expect(element('#link-4').attr('href')).toBe('');
12661        });
12662
12663        it('should execute ng-click but not reload when no href but name specified', function() {
12664          element('#link-5').click();
12665          expect(input('value').val()).toEqual('5');
12666          expect(element('#link-5').attr('href')).toBe(undefined);
12667        });
12668
12669        it('should only change url when only ng-href', function() {
12670          input('value').enter('6');
12671          expect(element('#link-6').attr('href')).toBe('6');
12672
12673          element('#link-6').click();
12674          expect(browser().location().url()).toEqual('/6');
12675        });
12676      </doc:scenario>
12677    </doc:example>
12678 */
12679
12680/**
12681 * @ngdoc directive
12682 * @name ng.directive:ngSrc
12683 * @restrict A
12684 *
12685 * @description
12686 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
12687 * work right: The browser will fetch from the URL with the literal
12688 * text `{{hash}}` until Angular replaces the expression inside
12689 * `{{hash}}`. The `ngSrc` directive solves this problem.
12690 *
12691 * The buggy way to write it:
12692 * <pre>
12693 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
12694 * </pre>
12695 *
12696 * The correct way to write it:
12697 * <pre>
12698 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
12699 * </pre>
12700 *
12701 * @element IMG
12702 * @param {template} ngSrc any string which can contain `{{}}` markup.
12703 */
12704
12705/**
12706 * @ngdoc directive
12707 * @name ng.directive:ngSrcset
12708 * @restrict A
12709 *
12710 * @description
12711 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
12712 * work right: The browser will fetch from the URL with the literal
12713 * text `{{hash}}` until Angular replaces the expression inside
12714 * `{{hash}}`. The `ngSrcset` directive solves this problem.
12715 *
12716 * The buggy way to write it:
12717 * <pre>
12718 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
12719 * </pre>
12720 *
12721 * The correct way to write it:
12722 * <pre>
12723 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
12724 * </pre>
12725 *
12726 * @element IMG
12727 * @param {template} ngSrcset any string which can contain `{{}}` markup.
12728 */
12729
12730/**
12731 * @ngdoc directive
12732 * @name ng.directive:ngDisabled
12733 * @restrict A
12734 *
12735 * @description
12736 *
12737 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
12738 * <pre>
12739 * <div ng-init="scope = { isDisabled: false }">
12740 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
12741 * </div>
12742 * </pre>
12743 *
12744 * The HTML specs do not require browsers to preserve the special attributes such as disabled.
12745 * (The presence of them means true and absence means false)
12746 * This prevents the angular compiler from correctly retrieving the binding expression.
12747 * To solve this problem, we introduce the `ngDisabled` directive.
12748 *
12749 * @example
12750    <doc:example>
12751      <doc:source>
12752        Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
12753        <button ng-model="button" ng-disabled="checked">Button</button>
12754      </doc:source>
12755      <doc:scenario>
12756        it('should toggle button', function() {
12757          expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
12758          input('checked').check();
12759          expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
12760        });
12761      </doc:scenario>
12762    </doc:example>
12763 *
12764 * @element INPUT
12765 * @param {expression} ngDisabled Angular expression that will be evaluated.
12766 */
12767
12768
12769/**
12770 * @ngdoc directive
12771 * @name ng.directive:ngChecked
12772 * @restrict A
12773 *
12774 * @description
12775 * The HTML specs do not require browsers to preserve the special attributes such as checked.
12776 * (The presence of them means true and absence means false)
12777 * This prevents the angular compiler from correctly retrieving the binding expression.
12778 * To solve this problem, we introduce the `ngChecked` directive.
12779 * @example
12780    <doc:example>
12781      <doc:source>
12782        Check me to check both: <input type="checkbox" ng-model="master"><br/>
12783        <input id="checkSlave" type="checkbox" ng-checked="master">
12784      </doc:source>
12785      <doc:scenario>
12786        it('should check both checkBoxes', function() {
12787          expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
12788          input('master').check();
12789          expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
12790        });
12791      </doc:scenario>
12792    </doc:example>
12793 *
12794 * @element INPUT
12795 * @param {expression} ngChecked Angular expression that will be evaluated.
12796 */
12797
12798
12799/**
12800 * @ngdoc directive
12801 * @name ng.directive:ngReadonly
12802 * @restrict A
12803 *
12804 * @description
12805 * The HTML specs do not require browsers to preserve the special attributes such as readonly.
12806 * (The presence of them means true and absence means false)
12807 * This prevents the angular compiler from correctly retrieving the binding expression.
12808 * To solve this problem, we introduce the `ngReadonly` directive.
12809 * @example
12810    <doc:example>
12811      <doc:source>
12812        Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
12813        <input type="text" ng-readonly="checked" value="I'm Angular"/>
12814      </doc:source>
12815      <doc:scenario>
12816        it('should toggle readonly attr', function() {
12817          expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
12818          input('checked').check();
12819          expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
12820        });
12821      </doc:scenario>
12822    </doc:example>
12823 *
12824 * @element INPUT
12825 * @param {string} expression Angular expression that will be evaluated.
12826 */
12827
12828
12829/**
12830 * @ngdoc directive
12831 * @name ng.directive:ngSelected
12832 * @restrict A
12833 *
12834 * @description
12835 * The HTML specs do not require browsers to preserve the special attributes such as selected.
12836 * (The presence of them means true and absence means false)
12837 * This prevents the angular compiler from correctly retrieving the binding expression.
12838 * To solve this problem, we introduced the `ngSelected` directive.
12839 * @example
12840    <doc:example>
12841      <doc:source>
12842        Check me to select: <input type="checkbox" ng-model="selected"><br/>
12843        <select>
12844          <option>Hello!</option>
12845          <option id="greet" ng-selected="selected">Greetings!</option>
12846        </select>
12847      </doc:source>
12848      <doc:scenario>
12849        it('should select Greetings!', function() {
12850          expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
12851          input('selected').check();
12852          expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
12853        });
12854      </doc:scenario>
12855    </doc:example>
12856 *
12857 * @element OPTION
12858 * @param {string} expression Angular expression that will be evaluated.
12859 */
12860
12861/**
12862 * @ngdoc directive
12863 * @name ng.directive:ngOpen
12864 * @restrict A
12865 *
12866 * @description
12867 * The HTML specs do not require browsers to preserve the special attributes such as open.
12868 * (The presence of them means true and absence means false)
12869 * This prevents the angular compiler from correctly retrieving the binding expression.
12870 * To solve this problem, we introduce the `ngOpen` directive.
12871 *
12872 * @example
12873     <doc:example>
12874       <doc:source>
12875         Check me check multiple: <input type="checkbox" ng-model="open"><br/>
12876         <details id="details" ng-open="open">
12877            <summary>Show/Hide me</summary>
12878         </details>
12879       </doc:source>
12880       <doc:scenario>
12881         it('should toggle open', function() {
12882           expect(element('#details').prop('open')).toBeFalsy();
12883           input('open').check();
12884           expect(element('#details').prop('open')).toBeTruthy();
12885         });
12886       </doc:scenario>
12887     </doc:example>
12888 *
12889 * @element DETAILS
12890 * @param {string} expression Angular expression that will be evaluated.
12891 */
12892
12893var ngAttributeAliasDirectives = {};
12894
12895
12896// boolean attrs are evaluated
12897forEach(BOOLEAN_ATTR, function(propName, attrName) {
12898  // binding to multiple is not supported
12899  if (propName == "multiple") return;
12900
12901  var normalized = directiveNormalize('ng-' + attrName);
12902  ngAttributeAliasDirectives[normalized] = function() {
12903    return {
12904      priority: 100,
12905      compile: function() {
12906        return function(scope, element, attr) {
12907          scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
12908            attr.$set(attrName, !!value);
12909          });
12910        };
12911      }
12912    };
12913  };
12914});
12915
12916
12917// ng-src, ng-srcset, ng-href are interpolated
12918forEach(['src', 'srcset', 'href'], function(attrName) {
12919  var normalized = directiveNormalize('ng-' + attrName);
12920  ngAttributeAliasDirectives[normalized] = function() {
12921    return {
12922      priority: 99, // it needs to run after the attributes are interpolated
12923      link: function(scope, element, attr) {
12924        attr.$observe(normalized, function(value) {
12925          if (!value)
12926             return;
12927
12928          attr.$set(attrName, value);
12929
12930          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
12931          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
12932          // to set the property as well to achieve the desired effect.
12933          // we use attr[attrName] value since $set can sanitize the url.
12934          if (msie) element.prop(attrName, attr[attrName]);
12935        });
12936      }
12937    };
12938  };
12939});
12940
12941var nullFormCtrl = {
12942  $addControl: noop,
12943  $removeControl: noop,
12944  $setValidity: noop,
12945  $setDirty: noop,
12946  $setPristine: noop
12947};
12948
12949/**
12950 * @ngdoc object
12951 * @name ng.directive:form.FormController
12952 *
12953 * @property {boolean} $pristine True if user has not interacted with the form yet.
12954 * @property {boolean} $dirty True if user has already interacted with the form.
12955 * @property {boolean} $valid True if all of the containing forms and controls are valid.
12956 * @property {boolean} $invalid True if at least one containing control or form is invalid.
12957 *
12958 * @property {Object} $error Is an object hash, containing references to all invalid controls or
12959 *  forms, where:
12960 *
12961 *  - keys are validation tokens (error names) — such as `required`, `url` or `email`),
12962 *  - values are arrays of controls or forms that are invalid with given error.
12963 *
12964 * @description
12965 * `FormController` keeps track of all its controls and nested forms as well as state of them,
12966 * such as being valid/invalid or dirty/pristine.
12967 *
12968 * Each {@link ng.directive:form form} directive creates an instance
12969 * of `FormController`.
12970 *
12971 */
12972//asks for $scope to fool the BC controller module
12973FormController.$inject = ['$element', '$attrs', '$scope'];
12974function FormController(element, attrs) {
12975  var form = this,
12976      parentForm = element.parent().controller('form') || nullFormCtrl,
12977      invalidCount = 0, // used to easily determine if we are valid
12978      errors = form.$error = {},
12979      controls = [];
12980
12981  // init state
12982  form.$name = attrs.name || attrs.ngForm;
12983  form.$dirty = false;
12984  form.$pristine = true;
12985  form.$valid = true;
12986  form.$invalid = false;
12987
12988  parentForm.$addControl(form);
12989
12990  // Setup initial state of the control
12991  element.addClass(PRISTINE_CLASS);
12992  toggleValidCss(true);
12993
12994  // convenience method for easy toggling of classes
12995  function toggleValidCss(isValid, validationErrorKey) {
12996    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
12997    element.
12998      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
12999      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
13000  }
13001
13002  /**
13003   * @ngdoc function
13004   * @name ng.directive:form.FormController#$addControl
13005   * @methodOf ng.directive:form.FormController
13006   *
13007   * @description
13008   * Register a control with the form.
13009   *
13010   * Input elements using ngModelController do this automatically when they are linked.
13011   */
13012  form.$addControl = function(control) {
13013    controls.push(control);
13014
13015    if (control.$name && !form.hasOwnProperty(control.$name)) {
13016      form[control.$name] = control;
13017    }
13018  };
13019
13020  /**
13021   * @ngdoc function
13022   * @name ng.directive:form.FormController#$removeControl
13023   * @methodOf ng.directive:form.FormController
13024   *
13025   * @description
13026   * Deregister a control from the form.
13027   *
13028   * Input elements using ngModelController do this automatically when they are destroyed.
13029   */
13030  form.$removeControl = function(control) {
13031    if (control.$name && form[control.$name] === control) {
13032      delete form[control.$name];
13033    }
13034    forEach(errors, function(queue, validationToken) {
13035      form.$setValidity(validationToken, true, control);
13036    });
13037
13038    arrayRemove(controls, control);
13039  };
13040
13041  /**
13042   * @ngdoc function
13043   * @name ng.directive:form.FormController#$setValidity
13044   * @methodOf ng.directive:form.FormController
13045   *
13046   * @description
13047   * Sets the validity of a form control.
13048   *
13049   * This method will also propagate to parent forms.
13050   */
13051  form.$setValidity = function(validationToken, isValid, control) {
13052    var queue = errors[validationToken];
13053
13054    if (isValid) {
13055      if (queue) {
13056        arrayRemove(queue, control);
13057        if (!queue.length) {
13058          invalidCount--;
13059          if (!invalidCount) {
13060            toggleValidCss(isValid);
13061            form.$valid = true;
13062            form.$invalid = false;
13063          }
13064          errors[validationToken] = false;
13065          toggleValidCss(true, validationToken);
13066          parentForm.$setValidity(validationToken, true, form);
13067        }
13068      }
13069
13070    } else {
13071      if (!invalidCount) {
13072        toggleValidCss(isValid);
13073      }
13074      if (queue) {
13075        if (includes(queue, control)) return;
13076      } else {
13077        errors[validationToken] = queue = [];
13078        invalidCount++;
13079        toggleValidCss(false, validationToken);
13080        parentForm.$setValidity(validationToken, false, form);
13081      }
13082      queue.push(control);
13083
13084      form.$valid = false;
13085      form.$invalid = true;
13086    }
13087  };
13088
13089  /**
13090   * @ngdoc function
13091   * @name ng.directive:form.FormController#$setDirty
13092   * @methodOf ng.directive:form.FormController
13093   *
13094   * @description
13095   * Sets the form to a dirty state.
13096   *
13097   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
13098   * state (ng-dirty class). This method will also propagate to parent forms.
13099   */
13100  form.$setDirty = function() {
13101    element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
13102    form.$dirty = true;
13103    form.$pristine = false;
13104    parentForm.$setDirty();
13105  };
13106
13107  /**
13108   * @ngdoc function
13109   * @name ng.directive:form.FormController#$setPristine
13110   * @methodOf ng.directive:form.FormController
13111   *
13112   * @description
13113   * Sets the form to its pristine state.
13114   *
13115   * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
13116   * state (ng-pristine class). This method will also propagate to all the controls contained
13117   * in this form.
13118   *
13119   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
13120   * saving or resetting it.
13121   */
13122  form.$setPristine = function () {
13123    element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
13124    form.$dirty = false;
13125    form.$pristine = true;
13126    forEach(controls, function(control) {
13127      control.$setPristine();
13128    });
13129  };
13130}
13131
13132
13133/**
13134 * @ngdoc directive
13135 * @name ng.directive:ngForm
13136 * @restrict EAC
13137 *
13138 * @description
13139 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
13140 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
13141 * sub-group of controls needs to be determined.
13142 *
13143 * @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
13144 *                       related scope, under this name.
13145 *
13146 */
13147
13148 /**
13149 * @ngdoc directive
13150 * @name ng.directive:form
13151 * @restrict E
13152 *
13153 * @description
13154 * Directive that instantiates
13155 * {@link ng.directive:form.FormController FormController}.
13156 *
13157 * If `name` attribute is specified, the form controller is published onto the current scope under
13158 * this name.
13159 *
13160 * # Alias: {@link ng.directive:ngForm `ngForm`}
13161 *
13162 * In angular forms can be nested. This means that the outer form is valid when all of the child
13163 * forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
13164 * reason angular provides {@link ng.directive:ngForm `ngForm`} alias
13165 * which behaves identical to `<form>` but allows form nesting.
13166 *
13167 *
13168 * # CSS classes
13169 *  - `ng-valid` Is set if the form is valid.
13170 *  - `ng-invalid` Is set if the form is invalid.
13171 *  - `ng-pristine` Is set if the form is pristine.
13172 *  - `ng-dirty` Is set if the form is dirty.
13173 *
13174 *
13175 * # Submitting a form and preventing default action
13176 *
13177 * Since the role of forms in client-side Angular applications is different than in classical
13178 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
13179 * page reload that sends the data to the server. Instead some javascript logic should be triggered
13180 * to handle the form submission in application specific way.
13181 *
13182 * For this reason, Angular prevents the default action (form submission to the server) unless the
13183 * `<form>` element has an `action` attribute specified.
13184 *
13185 * You can use one of the following two ways to specify what javascript method should be called when
13186 * a form is submitted:
13187 *
13188 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
13189 * - {@link ng.directive:ngClick ngClick} directive on the first
13190  *  button or input field of type submit (input[type=submit])
13191 *
13192 * To prevent double execution of the handler, use only one of ngSubmit or ngClick directives. This
13193 * is because of the following form submission rules coming from the html spec:
13194 *
13195 * - If a form has only one input field then hitting enter in this field triggers form submit
13196 * (`ngSubmit`)
13197 * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
13198 * doesn't trigger submit
13199 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
13200 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
13201 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
13202 *
13203 * @param {string=} name Name of the form. If specified, the form controller will be published into
13204 *                       related scope, under this name.
13205 *
13206 * @example
13207    <doc:example>
13208      <doc:source>
13209       <script>
13210         function Ctrl($scope) {
13211           $scope.userType = 'guest';
13212         }
13213       </script>
13214       <form name="myForm" ng-controller="Ctrl">
13215         userType: <input name="input" ng-model="userType" required>
13216         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
13217         <tt>userType = {{userType}}</tt><br>
13218         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
13219         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
13220         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
13221         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
13222        </form>
13223      </doc:source>
13224      <doc:scenario>
13225        it('should initialize to model', function() {
13226         expect(binding('userType')).toEqual('guest');
13227         expect(binding('myForm.input.$valid')).toEqual('true');
13228        });
13229
13230        it('should be invalid if empty', function() {
13231         input('userType').enter('');
13232         expect(binding('userType')).toEqual('');
13233         expect(binding('myForm.input.$valid')).toEqual('false');
13234        });
13235      </doc:scenario>
13236    </doc:example>
13237 */
13238var formDirectiveFactory = function(isNgForm) {
13239  return ['$timeout', function($timeout) {
13240    var formDirective = {
13241      name: 'form',
13242      restrict: 'E',
13243      controller: FormController,
13244      compile: function() {
13245        return {
13246          pre: function(scope, formElement, attr, controller) {
13247            if (!attr.action) {
13248              // we can't use jq events because if a form is destroyed during submission the default
13249              // action is not prevented. see #1238
13250              //
13251              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
13252              // page reload if the form was destroyed by submission of the form via a click handler
13253              // on a button in the form. Looks like an IE9 specific bug.
13254              var preventDefaultListener = function(event) {
13255                event.preventDefault
13256                  ? event.preventDefault()
13257                  : event.returnValue = false; // IE
13258              };
13259
13260              addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
13261
13262              // unregister the preventDefault listener so that we don't not leak memory but in a
13263              // way that will achieve the prevention of the default action.
13264              formElement.on('$destroy', function() {
13265                $timeout(function() {
13266                  removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
13267                }, 0, false);
13268              });
13269            }
13270
13271            var parentFormCtrl = formElement.parent().controller('form'),
13272                alias = attr.name || attr.ngForm;
13273
13274            if (alias) {
13275              setter(scope, alias, controller, alias);
13276            }
13277            if (parentFormCtrl) {
13278              formElement.on('$destroy', function() {
13279                parentFormCtrl.$removeControl(controller);
13280                if (alias) {
13281                  setter(scope, alias, undefined, alias);
13282                }
13283                extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
13284              });
13285            }
13286          }
13287        };
13288      }
13289    };
13290
13291    return isNgForm ? extend(copy(formDirective), {restrict: 'EAC'}) : formDirective;
13292  }];
13293};
13294
13295var formDirective = formDirectiveFactory();
13296var ngFormDirective = formDirectiveFactory(true);
13297
13298var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
13299var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
13300var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
13301
13302var inputType = {
13303
13304  /**
13305   * @ngdoc inputType
13306   * @name ng.directive:input.text
13307   *
13308   * @description
13309   * Standard HTML text input with angular data binding.
13310   *
13311   * @param {string} ngModel Assignable angular expression to data-bind to.
13312   * @param {string=} name Property name of the form under which the control is published.
13313   * @param {string=} required Adds `required` validation error key if the value is not entered.
13314   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13315   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13316   *    `required` when you want to data-bind to the `required` attribute.
13317   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
13318   *    minlength.
13319   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
13320   *    maxlength.
13321   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
13322   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
13323   *    patterns defined as scope expressions.
13324   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13325   *    interaction with the input element.
13326   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trimming the
13327   *    input.
13328   *
13329   * @example
13330      <doc:example>
13331        <doc:source>
13332         <script>
13333           function Ctrl($scope) {
13334             $scope.text = 'guest';
13335             $scope.word = /^\s*\w*\s*$/;
13336           }
13337         </script>
13338         <form name="myForm" ng-controller="Ctrl">
13339           Single word: <input type="text" name="input" ng-model="text"
13340                               ng-pattern="word" required ng-trim="false">
13341           <span class="error" ng-show="myForm.input.$error.required">
13342             Required!</span>
13343           <span class="error" ng-show="myForm.input.$error.pattern">
13344             Single word only!</span>
13345
13346           <tt>text = {{text}}</tt><br/>
13347           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
13348           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
13349           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
13350           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
13351          </form>
13352        </doc:source>
13353        <doc:scenario>
13354          it('should initialize to model', function() {
13355            expect(binding('text')).toEqual('guest');
13356            expect(binding('myForm.input.$valid')).toEqual('true');
13357          });
13358
13359          it('should be invalid if empty', function() {
13360            input('text').enter('');
13361            expect(binding('text')).toEqual('');
13362            expect(binding('myForm.input.$valid')).toEqual('false');
13363          });
13364
13365          it('should be invalid if multi word', function() {
13366            input('text').enter('hello world');
13367            expect(binding('myForm.input.$valid')).toEqual('false');
13368          });
13369
13370          it('should not be trimmed', function() {
13371            input('text').enter('untrimmed ');
13372            expect(binding('text')).toEqual('untrimmed ');
13373            expect(binding('myForm.input.$valid')).toEqual('true');
13374          });
13375        </doc:scenario>
13376      </doc:example>
13377   */
13378  'text': textInputType,
13379
13380
13381  /**
13382   * @ngdoc inputType
13383   * @name ng.directive:input.number
13384   *
13385   * @description
13386   * Text input with number validation and transformation. Sets the `number` validation
13387   * error if not a valid number.
13388   *
13389   * @param {string} ngModel Assignable angular expression to data-bind to.
13390   * @param {string=} name Property name of the form under which the control is published.
13391   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
13392   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
13393   * @param {string=} required Sets `required` validation error key if the value is not entered.
13394   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13395   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13396   *    `required` when you want to data-bind to the `required` attribute.
13397   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
13398   *    minlength.
13399   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
13400   *    maxlength.
13401   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
13402   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
13403   *    patterns defined as scope expressions.
13404   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13405   *    interaction with the input element.
13406   *
13407   * @example
13408      <doc:example>
13409        <doc:source>
13410         <script>
13411           function Ctrl($scope) {
13412             $scope.value = 12;
13413           }
13414         </script>
13415         <form name="myForm" ng-controller="Ctrl">
13416           Number: <input type="number" name="input" ng-model="value"
13417                          min="0" max="99" required>
13418           <span class="error" ng-show="myForm.input.$error.required">
13419             Required!</span>
13420           <span class="error" ng-show="myForm.input.$error.number">
13421             Not valid number!</span>
13422           <tt>value = {{value}}</tt><br/>
13423           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
13424           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
13425           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
13426           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
13427          </form>
13428        </doc:source>
13429        <doc:scenario>
13430          it('should initialize to model', function() {
13431           expect(binding('value')).toEqual('12');
13432           expect(binding('myForm.input.$valid')).toEqual('true');
13433          });
13434
13435          it('should be invalid if empty', function() {
13436           input('value').enter('');
13437           expect(binding('value')).toEqual('');
13438           expect(binding('myForm.input.$valid')).toEqual('false');
13439          });
13440
13441          it('should be invalid if over max', function() {
13442           input('value').enter('123');
13443           expect(binding('value')).toEqual('');
13444           expect(binding('myForm.input.$valid')).toEqual('false');
13445          });
13446        </doc:scenario>
13447      </doc:example>
13448   */
13449  'number': numberInputType,
13450
13451
13452  /**
13453   * @ngdoc inputType
13454   * @name ng.directive:input.url
13455   *
13456   * @description
13457   * Text input with URL validation. Sets the `url` validation error key if the content is not a
13458   * valid URL.
13459   *
13460   * @param {string} ngModel Assignable angular expression to data-bind to.
13461   * @param {string=} name Property name of the form under which the control is published.
13462   * @param {string=} required Sets `required` validation error key if the value is not entered.
13463   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13464   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13465   *    `required` when you want to data-bind to the `required` attribute.
13466   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
13467   *    minlength.
13468   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
13469   *    maxlength.
13470   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
13471   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
13472   *    patterns defined as scope expressions.
13473   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13474   *    interaction with the input element.
13475   *
13476   * @example
13477      <doc:example>
13478        <doc:source>
13479         <script>
13480           function Ctrl($scope) {
13481             $scope.text = 'http://google.com';
13482           }
13483         </script>
13484         <form name="myForm" ng-controller="Ctrl">
13485           URL: <input type="url" name="input" ng-model="text" required>
13486           <span class="error" ng-show="myForm.input.$error.required">
13487             Required!</span>
13488           <span class="error" ng-show="myForm.input.$error.url">
13489             Not valid url!</span>
13490           <tt>text = {{text}}</tt><br/>
13491           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
13492           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
13493           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
13494           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
13495           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
13496          </form>
13497        </doc:source>
13498        <doc:scenario>
13499          it('should initialize to model', function() {
13500            expect(binding('text')).toEqual('http://google.com');
13501            expect(binding('myForm.input.$valid')).toEqual('true');
13502          });
13503
13504          it('should be invalid if empty', function() {
13505            input('text').enter('');
13506            expect(binding('text')).toEqual('');
13507            expect(binding('myForm.input.$valid')).toEqual('false');
13508          });
13509
13510          it('should be invalid if not url', function() {
13511            input('text').enter('xxx');
13512            expect(binding('myForm.input.$valid')).toEqual('false');
13513          });
13514        </doc:scenario>
13515      </doc:example>
13516   */
13517  'url': urlInputType,
13518
13519
13520  /**
13521   * @ngdoc inputType
13522   * @name ng.directive:input.email
13523   *
13524   * @description
13525   * Text input with email validation. Sets the `email` validation error key if not a valid email
13526   * address.
13527   *
13528   * @param {string} ngModel Assignable angular expression to data-bind to.
13529   * @param {string=} name Property name of the form under which the control is published.
13530   * @param {string=} required Sets `required` validation error key if the value is not entered.
13531   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13532   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13533   *    `required` when you want to data-bind to the `required` attribute.
13534   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
13535   *    minlength.
13536   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
13537   *    maxlength.
13538   * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
13539   *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
13540   *    patterns defined as scope expressions.
13541   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13542   *    interaction with the input element.
13543   *
13544   * @example
13545      <doc:example>
13546        <doc:source>
13547         <script>
13548           function Ctrl($scope) {
13549             $scope.text = '[email protected]';
13550           }
13551         </script>
13552           <form name="myForm" ng-controller="Ctrl">
13553             Email: <input type="email" name="input" ng-model="text" required>
13554             <span class="error" ng-show="myForm.input.$error.required">
13555               Required!</span>
13556             <span class="error" ng-show="myForm.input.$error.email">
13557               Not valid email!</span>
13558             <tt>text = {{text}}</tt><br/>
13559             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
13560             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
13561             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
13562             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
13563             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
13564           </form>
13565        </doc:source>
13566        <doc:scenario>
13567          it('should initialize to model', function() {
13568            expect(binding('text')).toEqual('[email protected]');
13569            expect(binding('myForm.input.$valid')).toEqual('true');
13570          });
13571
13572          it('should be invalid if empty', function() {
13573            input('text').enter('');
13574            expect(binding('text')).toEqual('');
13575            expect(binding('myForm.input.$valid')).toEqual('false');
13576          });
13577
13578          it('should be invalid if not email', function() {
13579            input('text').enter('xxx');
13580            expect(binding('myForm.input.$valid')).toEqual('false');
13581          });
13582        </doc:scenario>
13583      </doc:example>
13584   */
13585  'email': emailInputType,
13586
13587
13588  /**
13589   * @ngdoc inputType
13590   * @name ng.directive:input.radio
13591   *
13592   * @description
13593   * HTML radio button.
13594   *
13595   * @param {string} ngModel Assignable angular expression to data-bind to.
13596   * @param {string} value The value to which the expression should be set when selected.
13597   * @param {string=} name Property name of the form under which the control is published.
13598   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13599   *    interaction with the input element.
13600   *
13601   * @example
13602      <doc:example>
13603        <doc:source>
13604         <script>
13605           function Ctrl($scope) {
13606             $scope.color = 'blue';
13607           }
13608         </script>
13609         <form name="myForm" ng-controller="Ctrl">
13610           <input type="radio" ng-model="color" value="red">  Red <br/>
13611           <input type="radio" ng-model="color" value="green"> Green <br/>
13612           <input type="radio" ng-model="color" value="blue"> Blue <br/>
13613           <tt>color = {{color}}</tt><br/>
13614          </form>
13615        </doc:source>
13616        <doc:scenario>
13617          it('should change state', function() {
13618            expect(binding('color')).toEqual('blue');
13619
13620            input('color').select('red');
13621            expect(binding('color')).toEqual('red');
13622          });
13623        </doc:scenario>
13624      </doc:example>
13625   */
13626  'radio': radioInputType,
13627
13628
13629  /**
13630   * @ngdoc inputType
13631   * @name ng.directive:input.checkbox
13632   *
13633   * @description
13634   * HTML checkbox.
13635   *
13636   * @param {string} ngModel Assignable angular expression to data-bind to.
13637   * @param {string=} name Property name of the form under which the control is published.
13638   * @param {string=} ngTrueValue The value to which the expression should be set when selected.
13639   * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
13640   * @param {string=} ngChange Angular expression to be executed when input changes due to user
13641   *    interaction with the input element.
13642   *
13643   * @example
13644      <doc:example>
13645        <doc:source>
13646         <script>
13647           function Ctrl($scope) {
13648             $scope.value1 = true;
13649             $scope.value2 = 'YES'
13650           }
13651         </script>
13652         <form name="myForm" ng-controller="Ctrl">
13653           Value1: <input type="checkbox" ng-model="value1"> <br/>
13654           Value2: <input type="checkbox" ng-model="value2"
13655                          ng-true-value="YES" ng-false-value="NO"> <br/>
13656           <tt>value1 = {{value1}}</tt><br/>
13657           <tt>value2 = {{value2}}</tt><br/>
13658          </form>
13659        </doc:source>
13660        <doc:scenario>
13661          it('should change state', function() {
13662            expect(binding('value1')).toEqual('true');
13663            expect(binding('value2')).toEqual('YES');
13664
13665            input('value1').check();
13666            input('value2').check();
13667            expect(binding('value1')).toEqual('false');
13668            expect(binding('value2')).toEqual('NO');
13669          });
13670        </doc:scenario>
13671      </doc:example>
13672   */
13673  'checkbox': checkboxInputType,
13674
13675  'hidden': noop,
13676  'button': noop,
13677  'submit': noop,
13678  'reset': noop
13679};
13680
13681
13682function isEmpty(value) {
13683  return isUndefined(value) || value === '' || value === null || value !== value;
13684}
13685
13686
13687function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
13688
13689  var listener = function() {
13690    var value = element.val();
13691
13692    // By default we will trim the value
13693    // If the attribute ng-trim exists we will avoid trimming
13694    // e.g. <input ng-model="foo" ng-trim="false">
13695    if (toBoolean(attr.ngTrim || 'T')) {
13696      value = trim(value);
13697    }
13698
13699    if (ctrl.$viewValue !== value) {
13700      scope.$apply(function() {
13701        ctrl.$setViewValue(value);
13702      });
13703    }
13704  };
13705
13706  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
13707  // input event on backspace, delete or cut
13708  if ($sniffer.hasEvent('input')) {
13709    element.on('input', listener);
13710  } else {
13711    var timeout;
13712
13713    var deferListener = function() {
13714      if (!timeout) {
13715        timeout = $browser.defer(function() {
13716          listener();
13717          timeout = null;
13718        });
13719      }
13720    };
13721
13722    element.on('keydown', function(event) {
13723      var key = event.keyCode;
13724
13725      // ignore
13726      //    command            modifiers                   arrows
13727      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
13728
13729      deferListener();
13730    });
13731
13732    // if user paste into input using mouse, we need "change" event to catch it
13733    element.on('change', listener);
13734
13735    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
13736    if ($sniffer.hasEvent('paste')) {
13737      element.on('paste cut', deferListener);
13738    }
13739  }
13740
13741
13742  ctrl.$render = function() {
13743    element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
13744  };
13745
13746  // pattern validator
13747  var pattern = attr.ngPattern,
13748      patternValidator,
13749      match;
13750
13751  var validate = function(regexp, value) {
13752    if (isEmpty(value) || regexp.test(value)) {
13753      ctrl.$setValidity('pattern', true);
13754      return value;
13755    } else {
13756      ctrl.$setValidity('pattern', false);
13757      return undefined;
13758    }
13759  };
13760
13761  if (pattern) {
13762    match = pattern.match(/^\/(.*)\/([gim]*)$/);
13763    if (match) {
13764      pattern = new RegExp(match[1], match[2]);
13765      patternValidator = function(value) {
13766        return validate(pattern, value)
13767      };
13768    } else {
13769      patternValidator = function(value) {
13770        var patternObj = scope.$eval(pattern);
13771
13772        if (!patternObj || !patternObj.test) {
13773          throw minErr('ngPattern')('noregexp',
13774            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
13775            patternObj, startingTag(element));
13776        }
13777        return validate(patternObj, value);
13778      };
13779    }
13780
13781    ctrl.$formatters.push(patternValidator);
13782    ctrl.$parsers.push(patternValidator);
13783  }
13784
13785  // min length validator
13786  if (attr.ngMinlength) {
13787    var minlength = int(attr.ngMinlength);
13788    var minLengthValidator = function(value) {
13789      if (!isEmpty(value) && value.length < minlength) {
13790        ctrl.$setValidity('minlength', false);
13791        return undefined;
13792      } else {
13793        ctrl.$setValidity('minlength', true);
13794        return value;
13795      }
13796    };
13797
13798    ctrl.$parsers.push(minLengthValidator);
13799    ctrl.$formatters.push(minLengthValidator);
13800  }
13801
13802  // max length validator
13803  if (attr.ngMaxlength) {
13804    var maxlength = int(attr.ngMaxlength);
13805    var maxLengthValidator = function(value) {
13806      if (!isEmpty(value) && value.length > maxlength) {
13807        ctrl.$setValidity('maxlength', false);
13808        return undefined;
13809      } else {
13810        ctrl.$setValidity('maxlength', true);
13811        return value;
13812      }
13813    };
13814
13815    ctrl.$parsers.push(maxLengthValidator);
13816    ctrl.$formatters.push(maxLengthValidator);
13817  }
13818}
13819
13820function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
13821  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
13822
13823  ctrl.$parsers.push(function(value) {
13824    var empty = isEmpty(value);
13825    if (empty || NUMBER_REGEXP.test(value)) {
13826      ctrl.$setValidity('number', true);
13827      return value === '' ? null : (empty ? value : parseFloat(value));
13828    } else {
13829      ctrl.$setValidity('number', false);
13830      return undefined;
13831    }
13832  });
13833
13834  ctrl.$formatters.push(function(value) {
13835    return isEmpty(value) ? '' : '' + value;
13836  });
13837
13838  if (attr.min) {
13839    var min = parseFloat(attr.min);
13840    var minValidator = function(value) {
13841      if (!isEmpty(value) && value < min) {
13842        ctrl.$setValidity('min', false);
13843        return undefined;
13844      } else {
13845        ctrl.$setValidity('min', true);
13846        return value;
13847      }
13848    };
13849
13850    ctrl.$parsers.push(minValidator);
13851    ctrl.$formatters.push(minValidator);
13852  }
13853
13854  if (attr.max) {
13855    var max = parseFloat(attr.max);
13856    var maxValidator = function(value) {
13857      if (!isEmpty(value) && value > max) {
13858        ctrl.$setValidity('max', false);
13859        return undefined;
13860      } else {
13861        ctrl.$setValidity('max', true);
13862        return value;
13863      }
13864    };
13865
13866    ctrl.$parsers.push(maxValidator);
13867    ctrl.$formatters.push(maxValidator);
13868  }
13869
13870  ctrl.$formatters.push(function(value) {
13871
13872    if (isEmpty(value) || isNumber(value)) {
13873      ctrl.$setValidity('number', true);
13874      return value;
13875    } else {
13876      ctrl.$setValidity('number', false);
13877      return undefined;
13878    }
13879  });
13880}
13881
13882function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
13883  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
13884
13885  var urlValidator = function(value) {
13886    if (isEmpty(value) || URL_REGEXP.test(value)) {
13887      ctrl.$setValidity('url', true);
13888      return value;
13889    } else {
13890      ctrl.$setValidity('url', false);
13891      return undefined;
13892    }
13893  };
13894
13895  ctrl.$formatters.push(urlValidator);
13896  ctrl.$parsers.push(urlValidator);
13897}
13898
13899function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
13900  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
13901
13902  var emailValidator = function(value) {
13903    if (isEmpty(value) || EMAIL_REGEXP.test(value)) {
13904      ctrl.$setValidity('email', true);
13905      return value;
13906    } else {
13907      ctrl.$setValidity('email', false);
13908      return undefined;
13909    }
13910  };
13911
13912  ctrl.$formatters.push(emailValidator);
13913  ctrl.$parsers.push(emailValidator);
13914}
13915
13916function radioInputType(scope, element, attr, ctrl) {
13917  // make the name unique, if not defined
13918  if (isUndefined(attr.name)) {
13919    element.attr('name', nextUid());
13920  }
13921
13922  element.on('click', function() {
13923    if (element[0].checked) {
13924      scope.$apply(function() {
13925        ctrl.$setViewValue(attr.value);
13926      });
13927    }
13928  });
13929
13930  ctrl.$render = function() {
13931    var value = attr.value;
13932    element[0].checked = (value == ctrl.$viewValue);
13933  };
13934
13935  attr.$observe('value', ctrl.$render);
13936}
13937
13938function checkboxInputType(scope, element, attr, ctrl) {
13939  var trueValue = attr.ngTrueValue,
13940      falseValue = attr.ngFalseValue;
13941
13942  if (!isString(trueValue)) trueValue = true;
13943  if (!isString(falseValue)) falseValue = false;
13944
13945  element.on('click', function() {
13946    scope.$apply(function() {
13947      ctrl.$setViewValue(element[0].checked);
13948    });
13949  });
13950
13951  ctrl.$render = function() {
13952    element[0].checked = ctrl.$viewValue;
13953  };
13954
13955  ctrl.$formatters.push(function(value) {
13956    return value === trueValue;
13957  });
13958
13959  ctrl.$parsers.push(function(value) {
13960    return value ? trueValue : falseValue;
13961  });
13962}
13963
13964
13965/**
13966 * @ngdoc directive
13967 * @name ng.directive:textarea
13968 * @restrict E
13969 *
13970 * @description
13971 * HTML textarea element control with angular data-binding. The data-binding and validation
13972 * properties of this element are exactly the same as those of the
13973 * {@link ng.directive:input input element}.
13974 *
13975 * @param {string} ngModel Assignable angular expression to data-bind to.
13976 * @param {string=} name Property name of the form under which the control is published.
13977 * @param {string=} required Sets `required` validation error key if the value is not entered.
13978 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
13979 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
13980 *    `required` when you want to data-bind to the `required` attribute.
13981 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
13982 *    minlength.
13983 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
13984 *    maxlength.
13985 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
13986 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
13987 *    patterns defined as scope expressions.
13988 * @param {string=} ngChange Angular expression to be executed when input changes due to user
13989 *    interaction with the input element.
13990 */
13991
13992
13993/**
13994 * @ngdoc directive
13995 * @name ng.directive:input
13996 * @restrict E
13997 *
13998 * @description
13999 * HTML input element control with angular data-binding. Input control follows HTML5 input types
14000 * and polyfills the HTML5 validation behavior for older browsers.
14001 *
14002 * @param {string} ngModel Assignable angular expression to data-bind to.
14003 * @param {string=} name Property name of the form under which the control is published.
14004 * @param {string=} required Sets `required` validation error key if the value is not entered.
14005 * @param {boolean=} ngRequired Sets `required` attribute if set to true
14006 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
14007 *    minlength.
14008 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
14009 *    maxlength.
14010 * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
14011 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
14012 *    patterns defined as scope expressions.
14013 * @param {string=} ngChange Angular expression to be executed when input changes due to user
14014 *    interaction with the input element.
14015 *
14016 * @example
14017    <doc:example>
14018      <doc:source>
14019       <script>
14020         function Ctrl($scope) {
14021           $scope.user = {name: 'guest', last: 'visitor'};
14022         }
14023       </script>
14024       <div ng-controller="Ctrl">
14025         <form name="myForm">
14026           User name: <input type="text" name="userName" ng-model="user.name" required>
14027           <span class="error" ng-show="myForm.userName.$error.required">
14028             Required!</span><br>
14029           Last name: <input type="text" name="lastName" ng-model="user.last"
14030             ng-minlength="3" ng-maxlength="10">
14031           <span class="error" ng-show="myForm.lastName.$error.minlength">
14032             Too short!</span>
14033           <span class="error" ng-show="myForm.lastName.$error.maxlength">
14034             Too long!</span><br>
14035         </form>
14036         <hr>
14037         <tt>user = {{user}}</tt><br/>
14038         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
14039         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
14040         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
14041         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
14042         <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
14043         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
14044         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
14045         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
14046       </div>
14047      </doc:source>
14048      <doc:scenario>
14049        it('should initialize to model', function() {
14050          expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
14051          expect(binding('myForm.userName.$valid')).toEqual('true');
14052          expect(binding('myForm.$valid')).toEqual('true');
14053        });
14054
14055        it('should be invalid if empty when required', function() {
14056          input('user.name').enter('');
14057          expect(binding('user')).toEqual('{"last":"visitor"}');
14058          expect(binding('myForm.userName.$valid')).toEqual('false');
14059          expect(binding('myForm.$valid')).toEqual('false');
14060        });
14061
14062        it('should be valid if empty when min length is set', function() {
14063          input('user.last').enter('');
14064          expect(binding('user')).toEqual('{"name":"guest","last":""}');
14065          expect(binding('myForm.lastName.$valid')).toEqual('true');
14066          expect(binding('myForm.$valid')).toEqual('true');
14067        });
14068
14069        it('should be invalid if less than required min length', function() {
14070          input('user.last').enter('xx');
14071          expect(binding('user')).toEqual('{"name":"guest"}');
14072          expect(binding('myForm.lastName.$valid')).toEqual('false');
14073          expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
14074          expect(binding('myForm.$valid')).toEqual('false');
14075        });
14076
14077        it('should be invalid if longer than max length', function() {
14078          input('user.last').enter('some ridiculously long name');
14079          expect(binding('user'))
14080            .toEqual('{"name":"guest"}');
14081          expect(binding('myForm.lastName.$valid')).toEqual('false');
14082          expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
14083          expect(binding('myForm.$valid')).toEqual('false');
14084        });
14085      </doc:scenario>
14086    </doc:example>
14087 */
14088var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
14089  return {
14090    restrict: 'E',
14091    require: '?ngModel',
14092    link: function(scope, element, attr, ctrl) {
14093      if (ctrl) {
14094        (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
14095                                                            $browser);
14096      }
14097    }
14098  };
14099}];
14100
14101var VALID_CLASS = 'ng-valid',
14102    INVALID_CLASS = 'ng-invalid',
14103    PRISTINE_CLASS = 'ng-pristine',
14104    DIRTY_CLASS = 'ng-dirty';
14105
14106/**
14107 * @ngdoc object
14108 * @name ng.directive:ngModel.NgModelController
14109 *
14110 * @property {string} $viewValue Actual string value in the view.
14111 * @property {*} $modelValue The value in the model, that the control is bound to.
14112 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
14113       the control reads value from the DOM.  Each function is called, in turn, passing the value
14114       through to the next. Used to sanitize / convert the value as well as validation.
14115       For validation, the parsers should update the validity state using
14116       {@link ng.directive:ngModel.NgModelController#$setValidity $setValidity()},
14117       and return `undefined` for invalid values.
14118
14119 *
14120 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
14121       the model value changes. Each function is called, in turn, passing the value through to the
14122       next. Used to format / convert values for display in the control and validation.
14123 *      <pre>
14124 *      function formatter(value) {
14125 *        if (value) {
14126 *          return value.toUpperCase();
14127 *        }
14128 *      }
14129 *      ngModel.$formatters.push(formatter);
14130 *      </pre>
14131 * @property {Object} $error An object hash with all errors as keys.
14132 *
14133 * @property {boolean} $pristine True if user has not interacted with the control yet.
14134 * @property {boolean} $dirty True if user has already interacted with the control.
14135 * @property {boolean} $valid True if there is no error.
14136 * @property {boolean} $invalid True if at least one error on the control.
14137 *
14138 * @description
14139 *
14140 * `NgModelController` provides API for the `ng-model` directive. The controller contains
14141 * services for data-binding, validation, CSS update, value formatting and parsing. It
14142 * specifically does not contain any logic which deals with DOM rendering or listening to
14143 * DOM events. The `NgModelController` is meant to be extended by other directives where, the
14144 * directive provides DOM manipulation and the `NgModelController` provides the data-binding.
14145 * Note that you cannot use `NgModelController` in a directive with an isolated scope,
14146 * as, in that case, the `ng-model` value gets put into the isolated scope and does not get
14147 * propogated to the parent scope.
14148 *
14149 *
14150 * This example shows how to use `NgModelController` with a custom control to achieve
14151 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
14152 * collaborate together to achieve the desired result.
14153 *
14154 * <example module="customControl">
14155    <file name="style.css">
14156      [contenteditable] {
14157        border: 1px solid black;
14158        background-color: white;
14159        min-height: 20px;
14160      }
14161
14162      .ng-invalid {
14163        border: 1px solid red;
14164      }
14165
14166    </file>
14167    <file name="script.js">
14168      angular.module('customControl', []).
14169        directive('contenteditable', function() {
14170          return {
14171            restrict: 'A', // only activate on element attribute
14172            require: '?ngModel', // get a hold of NgModelController
14173            link: function(scope, element, attrs, ngModel) {
14174              if(!ngModel) return; // do nothing if no ng-model
14175
14176              // Specify how UI should be updated
14177              ngModel.$render = function() {
14178                element.html(ngModel.$viewValue || '');
14179              };
14180
14181              // Listen for change events to enable binding
14182              element.on('blur keyup change', function() {
14183                scope.$apply(read);
14184              });
14185              read(); // initialize
14186
14187              // Write data to the model
14188              function read() {
14189                var html = element.html();
14190                // When we clear the content editable the browser leaves a <br> behind
14191                // If strip-br attribute is provided then we strip this out
14192                if( attrs.stripBr && html == '<br>' ) {
14193                  html = '';
14194                }
14195                ngModel.$setViewValue(html);
14196              }
14197            }
14198          };
14199        });
14200    </file>
14201    <file name="index.html">
14202      <form name="myForm">
14203       <div contenteditable
14204            name="myWidget" ng-model="userContent"
14205            strip-br="true"
14206            required>Change me!</div>
14207        <span ng-show="myForm.myWidget.$error.required">Required!</span>
14208       <hr>
14209       <textarea ng-model="userContent"></textarea>
14210      </form>
14211    </file>
14212    <file name="scenario.js">
14213      it('should data-bind and become invalid', function() {
14214        var contentEditable = element('[contenteditable]');
14215
14216        expect(contentEditable.text()).toEqual('Change me!');
14217        input('userContent').enter('');
14218        expect(contentEditable.text()).toEqual('');
14219        expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
14220      });
14221    </file>
14222 * </example>
14223 *
14224 */
14225var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
14226    function($scope, $exceptionHandler, $attr, $element, $parse) {
14227  this.$viewValue = Number.NaN;
14228  this.$modelValue = Number.NaN;
14229  this.$parsers = [];
14230  this.$formatters = [];
14231  this.$viewChangeListeners = [];
14232  this.$pristine = true;
14233  this.$dirty = false;
14234  this.$valid = true;
14235  this.$invalid = false;
14236  this.$name = $attr.name;
14237
14238  var ngModelGet = $parse($attr.ngModel),
14239      ngModelSet = ngModelGet.assign;
14240
14241  if (!ngModelSet) {
14242    throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
14243        $attr.ngModel, startingTag($element));
14244  }
14245
14246  /**
14247   * @ngdoc function
14248   * @name ng.directive:ngModel.NgModelController#$render
14249   * @methodOf ng.directive:ngModel.NgModelController
14250   *
14251   * @description
14252   * Called when the view needs to be updated. It is expected that the user of the ng-model
14253   * directive will implement this method.
14254   */
14255  this.$render = noop;
14256
14257  var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
14258      invalidCount = 0, // used to easily determine if we are valid
14259      $error = this.$error = {}; // keep invalid keys here
14260
14261
14262  // Setup initial state of the control
14263  $element.addClass(PRISTINE_CLASS);
14264  toggleValidCss(true);
14265
14266  // convenience method for easy toggling of classes
14267  function toggleValidCss(isValid, validationErrorKey) {
14268    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
14269    $element.
14270      removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
14271      addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
14272  }
14273
14274  /**
14275   * @ngdoc function
14276   * @name ng.directive:ngModel.NgModelController#$setValidity
14277   * @methodOf ng.directive:ngModel.NgModelController
14278   *
14279   * @description
14280   * Change the validity state, and notifies the form when the control changes validity. (i.e. it
14281   * does not notify form if given validator is already marked as invalid).
14282   *
14283   * This method should be called by validators - i.e. the parser or formatter functions.
14284   *
14285   * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
14286   *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
14287   *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
14288   *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
14289   *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
14290   * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
14291   */
14292  this.$setValidity = function(validationErrorKey, isValid) {
14293    if ($error[validationErrorKey] === !isValid) return;
14294
14295    if (isValid) {
14296      if ($error[validationErrorKey]) invalidCount--;
14297      if (!invalidCount) {
14298        toggleValidCss(true);
14299        this.$valid = true;
14300        this.$invalid = false;
14301      }
14302    } else {
14303      toggleValidCss(false);
14304      this.$invalid = true;
14305      this.$valid = false;
14306      invalidCount++;
14307    }
14308
14309    $error[validationErrorKey] = !isValid;
14310    toggleValidCss(isValid, validationErrorKey);
14311
14312    parentForm.$setValidity(validationErrorKey, isValid, this);
14313  };
14314
14315  /**
14316   * @ngdoc function
14317   * @name ng.directive:ngModel.NgModelController#$setPristine
14318   * @methodOf ng.directive:ngModel.NgModelController
14319   *
14320   * @description
14321   * Sets the control to its pristine state.
14322   *
14323   * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
14324   * state (ng-pristine class).
14325   */
14326  this.$setPristine = function () {
14327    this.$dirty = false;
14328    this.$pristine = true;
14329    $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
14330  };
14331
14332  /**
14333   * @ngdoc function
14334   * @name ng.directive:ngModel.NgModelController#$setViewValue
14335   * @methodOf ng.directive:ngModel.NgModelController
14336   *
14337   * @description
14338   * Read a value from view.
14339   *
14340   * This method should be called from within a DOM event handler.
14341   * For example {@link ng.directive:input input} or
14342   * {@link ng.directive:select select} directives call it.
14343   *
14344   * It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
14345   * Lastly it calls all registered change listeners.
14346   *
14347   * @param {string} value Value from the view.
14348   */
14349  this.$setViewValue = function(value) {
14350    this.$viewValue = value;
14351
14352    // change to dirty
14353    if (this.$pristine) {
14354      this.$dirty = true;
14355      this.$pristine = false;
14356      $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
14357      parentForm.$setDirty();
14358    }
14359
14360    forEach(this.$parsers, function(fn) {
14361      value = fn(value);
14362    });
14363
14364    if (this.$modelValue !== value) {
14365      this.$modelValue = value;
14366      ngModelSet($scope, value);
14367      forEach(this.$viewChangeListeners, function(listener) {
14368        try {
14369          listener();
14370        } catch(e) {
14371          $exceptionHandler(e);
14372        }
14373      })
14374    }
14375  };
14376
14377  // model -> value
14378  var ctrl = this;
14379
14380  $scope.$watch(function ngModelWatch() {
14381    var value = ngModelGet($scope);
14382
14383    // if scope model value and ngModel value are out of sync
14384    if (ctrl.$modelValue !== value) {
14385
14386      var formatters = ctrl.$formatters,
14387          idx = formatters.length;
14388
14389      ctrl.$modelValue = value;
14390      while(idx--) {
14391        value = formatters[idx](value);
14392      }
14393
14394      if (ctrl.$viewValue !== value) {
14395        ctrl.$viewValue = value;
14396        ctrl.$render();
14397      }
14398    }
14399  });
14400}];
14401
14402
14403/**
14404 * @ngdoc directive
14405 * @name ng.directive:ngModel
14406 *
14407 * @element input
14408 *
14409 * @description
14410 * Is a directive that tells Angular to do two-way data binding. It works together with `input`,
14411 * `select`, `textarea` and even custom form controls that use {@link ng.directive:ngModel.NgModelController
14412 * NgModelController} exposed by this directive.
14413 *
14414 * `ngModel` is responsible for:
14415 *
14416 * - binding the view into the model, which other directives such as `input`, `textarea` or `select`
14417 *   require,
14418 * - providing validation behavior (i.e. required, number, email, url),
14419 * - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
14420 * - setting related css class onto the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`),
14421 * - register the control with parent {@link ng.directive:form form}.
14422 *
14423 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
14424 * current scope. If the property doesn't already exist on this scope, it will be created
14425 * implicitly and added to the scope.
14426 *
14427 * For basic examples, how to use `ngModel`, see:
14428 *
14429 *  - {@link ng.directive:input input}
14430 *    - {@link ng.directive:input.text text}
14431 *    - {@link ng.directive:input.checkbox checkbox}
14432 *    - {@link ng.directive:input.radio radio}
14433 *    - {@link ng.directive:input.number number}
14434 *    - {@link ng.directive:input.email email}
14435 *    - {@link ng.directive:input.url url}
14436 *  - {@link ng.directive:select select}
14437 *  - {@link ng.directive:textarea textarea}
14438 *
14439 */
14440var ngModelDirective = function() {
14441  return {
14442    require: ['ngModel', '^?form'],
14443    controller: NgModelController,
14444    link: function(scope, element, attr, ctrls) {
14445      // notify others, especially parent forms
14446
14447      var modelCtrl = ctrls[0],
14448          formCtrl = ctrls[1] || nullFormCtrl;
14449
14450      formCtrl.$addControl(modelCtrl);
14451
14452      element.on('$destroy', function() {
14453        formCtrl.$removeControl(modelCtrl);
14454      });
14455    }
14456  };
14457};
14458
14459
14460/**
14461 * @ngdoc directive
14462 * @name ng.directive:ngChange
14463 * @restrict E
14464 *
14465 * @description
14466 * Evaluate given expression when user changes the input.
14467 * The expression is not evaluated when the value change is coming from the model.
14468 *
14469 * Note, this directive requires `ngModel` to be present.
14470 *
14471 * @element input
14472 *
14473 * @example
14474 * <doc:example>
14475 *   <doc:source>
14476 *     <script>
14477 *       function Controller($scope) {
14478 *         $scope.counter = 0;
14479 *         $scope.change = function() {
14480 *           $scope.counter++;
14481 *         };
14482 *       }
14483 *     </script>
14484 *     <div ng-controller="Controller">
14485 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
14486 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
14487 *       <label for="ng-change-example2">Confirmed</label><br />
14488 *       debug = {{confirmed}}<br />
14489 *       counter = {{counter}}
14490 *     </div>
14491 *   </doc:source>
14492 *   <doc:scenario>
14493 *     it('should evaluate the expression if changing from view', function() {
14494 *       expect(binding('counter')).toEqual('0');
14495 *       element('#ng-change-example1').click();
14496 *       expect(binding('counter')).toEqual('1');
14497 *       expect(binding('confirmed')).toEqual('true');
14498 *     });
14499 *
14500 *     it('should not evaluate the expression if changing from model', function() {
14501 *       element('#ng-change-example2').click();
14502 *       expect(binding('counter')).toEqual('0');
14503 *       expect(binding('confirmed')).toEqual('true');
14504 *     });
14505 *   </doc:scenario>
14506 * </doc:example>
14507 */
14508var ngChangeDirective = valueFn({
14509  require: 'ngModel',
14510  link: function(scope, element, attr, ctrl) {
14511    ctrl.$viewChangeListeners.push(function() {
14512      scope.$eval(attr.ngChange);
14513    });
14514  }
14515});
14516
14517
14518var requiredDirective = function() {
14519  return {
14520    require: '?ngModel',
14521    link: function(scope, elm, attr, ctrl) {
14522      if (!ctrl) return;
14523      attr.required = true; // force truthy in case we are on non input element
14524
14525      var validator = function(value) {
14526        if (attr.required && (isEmpty(value) || value === false)) {
14527          ctrl.$setValidity('required', false);
14528          return;
14529        } else {
14530          ctrl.$setValidity('required', true);
14531          return value;
14532        }
14533      };
14534
14535      ctrl.$formatters.push(validator);
14536      ctrl.$parsers.unshift(validator);
14537
14538      attr.$observe('required', function() {
14539        validator(ctrl.$viewValue);
14540      });
14541    }
14542  };
14543};
14544
14545
14546/**
14547 * @ngdoc directive
14548 * @name ng.directive:ngList
14549 *
14550 * @description
14551 * Text input that converts between comma-separated string into an array of strings.
14552 *
14553 * @element input
14554 * @param {string=} ngList optional delimiter that should be used to split the value. If
14555 *   specified in form `/something/` then the value will be converted into a regular expression.
14556 *
14557 * @example
14558    <doc:example>
14559      <doc:source>
14560       <script>
14561         function Ctrl($scope) {
14562           $scope.names = ['igor', 'misko', 'vojta'];
14563         }
14564       </script>
14565       <form name="myForm" ng-controller="Ctrl">
14566         List: <input name="namesInput" ng-model="names" ng-list required>
14567         <span class="error" ng-show="myForm.namesInput.$error.required">
14568           Required!</span>
14569         <br>
14570         <tt>names = {{names}}</tt><br/>
14571         <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
14572         <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
14573         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
14574         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
14575        </form>
14576      </doc:source>
14577      <doc:scenario>
14578        it('should initialize to model', function() {
14579          expect(binding('names')).toEqual('["igor","misko","vojta"]');
14580          expect(binding('myForm.namesInput.$valid')).toEqual('true');
14581          expect(element('span.error').css('display')).toBe('none');
14582        });
14583
14584        it('should be invalid if empty', function() {
14585          input('names').enter('');
14586          expect(binding('names')).toEqual('[]');
14587          expect(binding('myForm.namesInput.$valid')).toEqual('false');
14588          expect(element('span.error').css('display')).not().toBe('none');
14589        });
14590      </doc:scenario>
14591    </doc:example>
14592 */
14593var ngListDirective = function() {
14594  return {
14595    require: 'ngModel',
14596    link: function(scope, element, attr, ctrl) {
14597      var match = /\/(.*)\//.exec(attr.ngList),
14598          separator = match && new RegExp(match[1]) || attr.ngList || ',';
14599
14600      var parse = function(viewValue) {
14601        var list = [];
14602
14603        if (viewValue) {
14604          forEach(viewValue.split(separator), function(value) {
14605            if (value) list.push(trim(value));
14606          });
14607        }
14608
14609        return list;
14610      };
14611
14612      ctrl.$parsers.push(parse);
14613      ctrl.$formatters.push(function(value) {
14614        if (isArray(value)) {
14615          return value.join(', ');
14616        }
14617
14618        return undefined;
14619      });
14620    }
14621  };
14622};
14623
14624
14625var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
14626
14627var ngValueDirective = function() {
14628  return {
14629    priority: 100,
14630    compile: function(tpl, tplAttr) {
14631      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
14632        return function(scope, elm, attr) {
14633          attr.$set('value', scope.$eval(attr.ngValue));
14634        };
14635      } else {
14636        return function(scope, elm, attr) {
14637          scope.$watch(attr.ngValue, function valueWatchAction(value) {
14638            attr.$set('value', value);
14639          });
14640        };
14641      }
14642    }
14643  };
14644};
14645
14646/**
14647 * @ngdoc directive
14648 * @name ng.directive:ngBind
14649 *
14650 * @description
14651 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
14652 * with the value of a given expression, and to update the text content when the value of that
14653 * expression changes.
14654 *
14655 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
14656 * `{{ expression }}` which is similar but less verbose.
14657 *
14658 * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily 
14659 * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an 
14660 * element attribute, it makes the bindings invisible to the user while the page is loading.
14661 *
14662 * An alternative solution to this problem would be using the
14663 * {@link ng.directive:ngCloak ngCloak} directive.
14664 *
14665 *
14666 * @element ANY
14667 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
14668 *
14669 * @example
14670 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
14671   <doc:example>
14672     <doc:source>
14673       <script>
14674         function Ctrl($scope) {
14675           $scope.name = 'Whirled';
14676         }
14677       </script>
14678       <div ng-controller="Ctrl">
14679         Enter name: <input type="text" ng-model="name"><br>
14680         Hello <span ng-bind="name"></span>!
14681       </div>
14682     </doc:source>
14683     <doc:scenario>
14684       it('should check ng-bind', function() {
14685         expect(using('.doc-example-live').binding('name')).toBe('Whirled');
14686         using('.doc-example-live').input('name').enter('world');
14687         expect(using('.doc-example-live').binding('name')).toBe('world');
14688       });
14689     </doc:scenario>
14690   </doc:example>
14691 */
14692var ngBindDirective = ngDirective(function(scope, element, attr) {
14693  element.addClass('ng-binding').data('$binding', attr.ngBind);
14694  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
14695    element.text(value == undefined ? '' : value);
14696  });
14697});
14698
14699
14700/**
14701 * @ngdoc directive
14702 * @name ng.directive:ngBindTemplate
14703 *
14704 * @description
14705 * The `ngBindTemplate` directive specifies that the element
14706 * text content should be replaced with the interpolation of the template
14707 * in the `ngBindTemplate` attribute.
14708 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
14709 * expressions. This directive is needed since some HTML elements
14710 * (such as TITLE and OPTION) cannot contain SPAN elements.
14711 *
14712 * @element ANY
14713 * @param {string} ngBindTemplate template of form
14714 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
14715 *
14716 * @example
14717 * Try it here: enter text in text box and watch the greeting change.
14718   <doc:example>
14719     <doc:source>
14720       <script>
14721         function Ctrl($scope) {
14722           $scope.salutation = 'Hello';
14723           $scope.name = 'World';
14724         }
14725       </script>
14726       <div ng-controller="Ctrl">
14727        Salutation: <input type="text" ng-model="salutation"><br>
14728        Name: <input type="text" ng-model="name"><br>
14729        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
14730       </div>
14731     </doc:source>
14732     <doc:scenario>
14733       it('should check ng-bind', function() {
14734         expect(using('.doc-example-live').binding('salutation')).
14735           toBe('Hello');
14736         expect(using('.doc-example-live').binding('name')).
14737           toBe('World');
14738         using('.doc-example-live').input('salutation').enter('Greetings');
14739         using('.doc-example-live').input('name').enter('user');
14740         expect(using('.doc-example-live').binding('salutation')).
14741           toBe('Greetings');
14742         expect(using('.doc-example-live').binding('name')).
14743           toBe('user');
14744       });
14745     </doc:scenario>
14746   </doc:example>
14747 */
14748var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
14749  return function(scope, element, attr) {
14750    // TODO: move this to scenario runner
14751    var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
14752    element.addClass('ng-binding').data('$binding', interpolateFn);
14753    attr.$observe('ngBindTemplate', function(value) {
14754      element.text(value);
14755    });
14756  }
14757}];
14758
14759
14760/**
14761 * @ngdoc directive
14762 * @name ng.directive:ngBindHtml
14763 *
14764 * @description
14765 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
14766 * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
14767 * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
14768 * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
14769 * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
14770 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
14771 * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
14772 *
14773 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
14774 * will have an exception (instead of an exploit.)
14775 *
14776 * @element ANY
14777 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
14778 */
14779var ngBindHtmlDirective = ['$sce', function($sce) {
14780  return function(scope, element, attr) {
14781    element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
14782    scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function ngBindHtmlWatchAction(value) {
14783      element.html(value || '');
14784    });
14785  };
14786}];
14787
14788function classDirective(name, selector) {
14789  name = 'ngClass' + name;
14790  return function() {
14791    return {
14792      restrict: 'AC',
14793      link: function(scope, element, attr) {
14794        var oldVal = undefined;
14795
14796        scope.$watch(attr[name], ngClassWatchAction, true);
14797
14798        attr.$observe('class', function(value) {
14799          ngClassWatchAction(scope.$eval(attr[name]));
14800        });
14801
14802
14803        if (name !== 'ngClass') {
14804          scope.$watch('$index', function($index, old$index) {
14805            var mod = $index & 1;
14806            if (mod !== old$index & 1) {
14807              if (mod === selector) {
14808                addClass(scope.$eval(attr[name]));
14809              } else {
14810                removeClass(scope.$eval(attr[name]));
14811              }
14812            }
14813          });
14814        }
14815
14816
14817        function ngClassWatchAction(newVal) {
14818          if (selector === true || scope.$index % 2 === selector) {
14819            if (oldVal && !equals(newVal,oldVal)) {
14820              removeClass(oldVal);
14821            }
14822            addClass(newVal);
14823          }
14824          oldVal = copy(newVal);
14825        }
14826
14827
14828        function removeClass(classVal) {
14829          attr.$removeClass(flattenClasses(classVal));
14830        }
14831
14832
14833        function addClass(classVal) {
14834          attr.$addClass(flattenClasses(classVal));
14835        }
14836
14837        function flattenClasses(classVal) {
14838          if(isArray(classVal)) {
14839            return classVal.join(' ');
14840          } else if (isObject(classVal)) {
14841            var classes = [], i = 0;
14842            forEach(classVal, function(v, k) {
14843              if (v) {
14844                classes.push(k);
14845              }
14846            });
14847            return classes.join(' ');
14848          }
14849
14850          return classVal;
14851        };
14852      }
14853    };
14854  };
14855}
14856
14857/**
14858 * @ngdoc directive
14859 * @name ng.directive:ngClass
14860 *
14861 * @description
14862 * The `ngClass` allows you to set CSS classes on HTML an element, dynamically, by databinding
14863 * an expression that represents all classes to be added.
14864 *
14865 * The directive won't add duplicate classes if a particular class was already set.
14866 *
14867 * When the expression changes, the previously added classes are removed and only then the
14868 * new classes are added.
14869 *
14870 * @animations
14871 * add - happens just before the class is applied to the element
14872 * remove - happens just before the class is removed from the element
14873 *
14874 * @element ANY
14875 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
14876 *   of the evaluation can be a string representing space delimited class
14877 *   names, an array, or a map of class names to boolean values. In the case of a map, the
14878 *   names of the properties whose values are truthy will be added as css classes to the
14879 *   element.
14880 *
14881 * @example Example that demostrates basic bindings via ngClass directive.
14882   <example>
14883     <file name="index.html">
14884       <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
14885       <input type="checkbox" ng-model="bold"> bold
14886       <input type="checkbox" ng-model="strike"> strike
14887       <input type="checkbox" ng-model="red"> red
14888       <hr>
14889       <p ng-class="style">Using String Syntax</p>
14890       <input type="text" ng-model="style" placeholder="Type: bold strike red">
14891       <hr>
14892       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
14893       <input ng-model="style1" placeholder="Type: bold"><br>
14894       <input ng-model="style2" placeholder="Type: strike"><br>
14895       <input ng-model="style3" placeholder="Type: red"><br>
14896     </file>
14897     <file name="style.css">
14898       .strike {
14899         text-decoration: line-through;
14900       }
14901       .bold {
14902           font-weight: bold;
14903       }
14904       .red {
14905           color: red;
14906       }
14907     </file>
14908     <file name="scenario.js">
14909       it('should let you toggle the class', function() {
14910
14911         expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
14912         expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
14913
14914         input('bold').check();
14915         expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
14916
14917         input('red').check();
14918         expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
14919       });
14920
14921       it('should let you toggle string example', function() {
14922         expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
14923         input('style').enter('red');
14924         expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red');
14925       });
14926
14927       it('array example should have 3 classes', function() {
14928         expect(element('.doc-example-live p:last').prop('className')).toBe('');
14929         input('style1').enter('bold');
14930         input('style2').enter('strike');
14931         input('style3').enter('red');
14932         expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red');
14933       });
14934     </file>
14935   </example>
14936
14937   ## Animations
14938
14939   Example that demostrates how addition and removal of classes can be animated.
14940
14941   <example animations="true">
14942     <file name="index.html">
14943      <input type="button" value="set" ng-click="myVar='my-class'">
14944      <input type="button" value="clear" ng-click="myVar=''">
14945      <br>
14946      <span ng-class="myVar">Sample Text</span>
14947     </file>
14948     <file name="style.css">
14949       .my-class-add, .my-class-remove {
14950         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
14951         -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
14952         -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
14953         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
14954       }
14955
14956       .my-class,
14957       .my-class-add.my-class-add-active {
14958         color: red;
14959         font-size:3em;
14960       }
14961
14962       .my-class-remove.my-class-remove-active {
14963         font-size:1.0em;
14964         color:black;
14965       }
14966     </file>
14967     <file name="scenario.js">
14968       it('should check ng-class', function() {
14969         expect(element('.doc-example-live span').prop('className')).not().
14970           toMatch(/my-class/);
14971
14972         using('.doc-example-live').element(':button:first').click();
14973
14974         expect(element('.doc-example-live span').prop('className')).
14975           toMatch(/my-class/);
14976
14977         using('.doc-example-live').element(':button:last').click();
14978
14979         expect(element('.doc-example-live span').prop('className')).not().
14980           toMatch(/my-class/);
14981       });
14982     </file>
14983   </example>
14984 */
14985var ngClassDirective = classDirective('', true);
14986
14987/**
14988 * @ngdoc directive
14989 * @name ng.directive:ngClassOdd
14990 *
14991 * @description
14992 * The `ngClassOdd` and `ngClassEven` directives work exactly as
14993 * {@link ng.directive:ngClass ngClass}, except it works in
14994 * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
14995 *
14996 * This directive can be applied only within a scope of an
14997 * {@link ng.directive:ngRepeat ngRepeat}.
14998 *
14999 * @element ANY
15000 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
15001 *   of the evaluation can be a string representing space delimited class names or an array.
15002 *
15003 * @example
15004   <example>
15005     <file name="index.html">
15006        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
15007          <li ng-repeat="name in names">
15008           <span ng-class-odd="'odd'" ng-class-even="'even'">
15009             {{name}}
15010           </span>
15011          </li>
15012        </ol>
15013     </file>
15014     <file name="style.css">
15015       .odd {
15016         color: red;
15017       }
15018       .even {
15019         color: blue;
15020       }
15021     </file>
15022     <file name="scenario.js">
15023       it('should check ng-class-odd and ng-class-even', function() {
15024         expect(element('.doc-example-live li:first span').prop('className')).
15025           toMatch(/odd/);
15026         expect(element('.doc-example-live li:last span').prop('className')).
15027           toMatch(/even/);
15028       });
15029     </file>
15030   </example>
15031 */
15032var ngClassOddDirective = classDirective('Odd', 0);
15033
15034/**
15035 * @ngdoc directive
15036 * @name ng.directive:ngClassEven
15037 *
15038 * @description
15039 * The `ngClassOdd` and `ngClassEven` directives work exactly as
15040 * {@link ng.directive:ngClass ngClass}, except it works in
15041 * conjunction with `ngRepeat` and takes affect only on odd (even) rows.
15042 *
15043 * This directive can be applied only within a scope of an
15044 * {@link ng.directive:ngRepeat ngRepeat}.
15045 *
15046 * @element ANY
15047 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
15048 *   result of the evaluation can be a string representing space delimited class names or an array.
15049 *
15050 * @example
15051   <example>
15052     <file name="index.html">
15053        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
15054          <li ng-repeat="name in names">
15055           <span ng-class-odd="'odd'" ng-class-even="'even'">
15056             {{name}} &nbsp; &nbsp; &nbsp;
15057           </span>
15058          </li>
15059        </ol>
15060     </file>
15061     <file name="style.css">
15062       .odd {
15063         color: red;
15064       }
15065       .even {
15066         color: blue;
15067       }
15068     </file>
15069     <file name="scenario.js">
15070       it('should check ng-class-odd and ng-class-even', function() {
15071         expect(element('.doc-example-live li:first span').prop('className')).
15072           toMatch(/odd/);
15073         expect(element('.doc-example-live li:last span').prop('className')).
15074           toMatch(/even/);
15075       });
15076     </file>
15077   </example>
15078 */
15079var ngClassEvenDirective = classDirective('Even', 1);
15080
15081/**
15082 * @ngdoc directive
15083 * @name ng.directive:ngCloak
15084 *
15085 * @description
15086 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
15087 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
15088 * directive to avoid the undesirable flicker effect caused by the html template display.
15089 *
15090 * The directive can be applied to the `<body>` element, but typically a fine-grained application is
15091 * preferred in order to benefit from progressive rendering of the browser view.
15092 *
15093 * `ngCloak` works in cooperation with a css rule that is embedded within `angular.js` and
15094 *  `angular.min.js` files. Following is the css rule:
15095 *
15096 * <pre>
15097 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
15098 *   display: none !important;
15099 * }
15100 * </pre>
15101 *
15102 * When this css rule is loaded by the browser, all html elements (including their children) that
15103 * are tagged with the `ng-cloak` directive are hidden. When Angular comes across this directive
15104 * during the compilation of the template it deletes the `ngCloak` element attribute, which
15105 * makes the compiled element visible.
15106 *
15107 * For the best result, `angular.js` script must be loaded in the head section of the html file;
15108 * alternatively, the css rule (above) must be included in the external stylesheet of the
15109 * application.
15110 *
15111 * Legacy browsers, like IE7, do not provide attribute selector support (a
15111dded in CSS 2.1) so they
15112 * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
15113 * class `ngCloak` in addition to `ngCloak` directive as shown in the example below.
15114 *
15115 * @element ANY
15116 *
15117 * @example
15118   <doc:example>
15119     <doc:source>
15120        <div id="template1" ng-cloak>{{ 'hello' }}</div>
15121        <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
15122     </doc:source>
15123     <doc:scenario>
15124       it('should remove the template directive and css class', function() {
15125         expect(element('.doc-example-live #template1').attr('ng-cloak')).
15126           not().toBeDefined();
15127         expect(element('.doc-example-live #template2').attr('ng-cloak')).
15128           not().toBeDefined();
15129       });
15130     </doc:scenario>
15131   </doc:example>
15132 *
15133 */
15134var ngCloakDirective = ngDirective({
15135  compile: function(element, attr) {
15136    attr.$set('ngCloak', undefined);
15137    element.removeClass('ng-cloak');
15138  }
15139});
15140
15141/**
15142 * @ngdoc directive
15143 * @name ng.directive:ngController
15144 *
15145 * @description
15146 * The `ngController` directive assigns behavior to a scope. This is a key aspect of how angular
15147 * supports the principles behind the Model-View-Controller design pattern.
15148 *
15149 * MVC components in angular:
15150 *
15151 * * Model — The Model is data in scope properties; scopes are attached to the DOM.
15152 * * View — The template (HTML with data bindings) is rendered into the View.
15153 * * Controller — The `ngController` directive specifies a Controller class; the class has
15154 *   methods that typically express the business logic behind the application.
15155 *
15156 * Note that an alternative way to define controllers is via the {@link ngRoute.$route $route} service.
15157 *
15158 * @element ANY
15159 * @scope
15160 * @param {expression} ngController Name of a globally accessible constructor function or an
15161 *     {@link guide/expression expression} that on the current scope evaluates to a
15162 *     constructor function. The controller instance can further be published into the scope
15163 *     by adding `as localName` the controller name attribute.
15164 *
15165 * @example
15166 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
15167 * greeting are methods declared on the controller (see source tab). These methods can
15168 * easily be called from the angular markup. Notice that the scope becomes the `this` for the
15169 * controller's instance. This allows for easy access to the view data from the controller. Also
15170 * notice that any changes to the data are automatically reflected in the View without the need
15171 * for a manual update. The example is included in two different declaration styles based on
15172 * your style preferences.
15173   <doc:example>
15174     <doc:source>
15175      <script>
15176        function SettingsController1() {
15177          this.name = "John Smith";
15178          this.contacts = [
15179            {type: 'phone', value: '408 555 1212'},
15180            {type: 'email', value: '[email protected]'} ];
15181          };
15182
15183        SettingsController1.prototype.greet = function() {
15184          alert(this.name);
15185        };
15186
15187        SettingsController1.prototype.addContact = function() {
15188          this.contacts.push({type: 'email', value: '[email protected]'});
15189        };
15190
15191        SettingsController1.prototype.removeContact = function(contactToRemove) {
15192         var index = this.contacts.indexOf(contactToRemove);
15193          this.contacts.splice(index, 1);
15194        };
15195
15196        SettingsController1.prototype.clearContact = function(contact) {
15197          contact.type = 'phone';
15198          contact.value = '';
15199        };
15200      </script>
15201      <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
15202        Name: <input type="text" ng-model="settings.name"/>
15203        [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
15204        Contact:
15205        <ul>
15206          <li ng-repeat="contact in settings.contacts">
15207            <select ng-model="contact.type">
15208               <option>phone</option>
15209               <option>email</option>
15210            </select>
15211            <input type="text" ng-model="contact.value"/>
15212            [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
15213            | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
15214          </li>
15215          <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
15216       </ul>
15217      </div>
15218     </doc:source>
15219     <doc:scenario>
15220       it('should check controller as', function() {
15221         expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
15222         expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
15223           .toBe('408 555 1212');
15224         expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
15225           .toBe('[email protected]');
15226
15227         element('#ctrl-as-exmpl li:first a:contains("clear")').click();
15228         expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');
15229
15230         element('#ctrl-as-exmpl li:last a:contains("add")').click();
15231         expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
15232           .toBe('[email protected]');
15233       });
15234     </doc:scenario>
15235   </doc:example>
15236    <doc:example>
15237     <doc:source>
15238      <script>
15239        function SettingsController2($scope) {
15240          $scope.name = "John Smith";
15241          $scope.contacts = [
15242            {type:'phone', value:'408 555 1212'},
15243            {type:'email', value:'[email protected]'} ];
15244
15245          $scope.greet = function() {
15246           alert(this.name);
15247          };
15248
15249          $scope.addContact = function() {
15250           this.contacts.push({type:'email', value:'[email protected]'});
15251          };
15252
15253          $scope.removeContact = function(contactToRemove) {
15254           var index = this.contacts.indexOf(contactToRemove);
15255           this.contacts.splice(index, 1);
15256          };
15257
15258          $scope.clearContact = function(contact) {
15259           contact.type = 'phone';
15260           contact.value = '';
15261          };
15262        }
15263      </script>
15264      <div id="ctrl-exmpl" ng-controller="SettingsController2">
15265        Name: <input type="text" ng-model="name"/>
15266        [ <a href="" ng-click="greet()">greet</a> ]<br/>
15267        Contact:
15268        <ul>
15269          <li ng-repeat="contact in contacts">
15270            <select ng-model="contact.type">
15271               <option>phone</option>
15272               <option>email</option>
15273            </select>
15274            <input type="text" ng-model="contact.value"/>
15275            [ <a href="" ng-click="clearContact(contact)">clear</a>
15276            | <a href="" ng-click="removeContact(contact)">X</a> ]
15277          </li>
15278          <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
15279       </ul>
15280      </div>
15281     </doc:source>
15282     <doc:scenario>
15283       it('should check controller', function() {
15284         expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
15285         expect(element('#ctrl-exmpl li:nth-child(1) input').val())
15286           .toBe('408 555 1212');
15287         expect(element('#ctrl-exmpl li:nth-child(2) input').val())
15288           .toBe('[email protected]');
15289
15290         element('#ctrl-exmpl li:first a:contains("clear")').click();
15291         expect(element('#ctrl-exmpl li:first input').val()).toBe('');
15292
15293         element('#ctrl-exmpl li:last a:contains("add")').click();
15294         expect(element('#ctrl-exmpl li:nth-child(3) input').val())
15295           .toBe('[email protected]');
15296       });
15297     </doc:scenario>
15298   </doc:example>
15299
15300 */
15301var ngControllerDirective = [function() {
15302  return {
15303    scope: true,
15304    controller: '@'
15305  };
15306}];
15307
15308/**
15309 * @ngdoc directive
15310 * @name ng.directive:ngCsp
15311 * @priority 1000
15312 *
15313 * @element html
15314 * @description
15315 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
15316 * 
15317 * This is necessary when developing things like Google Chrome Extensions.
15318 * 
15319 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
15320 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
15321 * any of these restrictions.
15322 * 
15323 * AngularJS uses `Function(string)` generated functions as a speed optimization. By applying `ngCsp`
15324 * it is be possible to opt into the CSP compatible mode. When this mode is on AngularJS will
15325 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
15326 * be raised.
15327 * 
15328 * In order to use this feature put `ngCsp` directive on the root element of the application.
15329 * 
15330 * @example
15331 * This example shows how to apply the `ngCsp` directive to the `html` tag.
15332   <pre>
15333     <!doctype html>
15334     <html ng-app ng-csp>
15335     ...
15336     ...
15337     </html>
15338   </pre>
15339 */
15340
15341var ngCspDirective = ['$sniffer', function($sniffer) {
15342  return {
15343    priority: 1000,
15344    compile: function() {
15345      $sniffer.csp = true;
15346    }
15347  };
15348}];
15349
15350/**
15351 * @ngdoc directive
15352 * @name ng.directive:ngClick
15353 *
15354 * @description
15355 * The ngClick allows you to specify custom behavior when
15356 * element is clicked.
15357 *
15358 * @element ANY
15359 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
15360 * click. (Event object is available as `$event`)
15361 *
15362 * @example
15363   <doc:example>
15364     <doc:source>
15365      <button ng-click="count = count + 1" ng-init="count=0">
15366        Increment
15367      </button>
15368      count: {{count}}
15369     </doc:source>
15370     <doc:scenario>
15371       it('should check ng-click', function() {
15372         expect(binding('count')).toBe('0');
15373         element('.doc-example-live :button').click();
15374         expect(binding('count')).toBe('1');
15375       });
15376     </doc:scenario>
15377   </doc:example>
15378 */
15379/*
15380 * A directive that allows creation of custom onclick handlers that are defined as angular
15381 * expressions and are compiled and executed within the current scope.
15382 *
15383 * Events that are handled via these handler are always configured not to propagate further.
15384 */
15385var ngEventDirectives = {};
15386forEach(
15387  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur'.split(' '),
15388  function(name) {
15389    var directiveName = directiveNormalize('ng-' + name);
15390    ngEventDirectives[directiveName] = ['$parse', function($parse) {
15391      return function(scope, element, attr) {
15392        var fn = $parse(attr[directiveName]);
15393        element.on(lowercase(name), function(event) {
15394          scope.$apply(function() {
15395            fn(scope, {$event:event});
15396          });
15397        });
15398      };
15399    }];
15400  }
15401);
15402
15403/**
15404 * @ngdoc directive
15405 * @name ng.directive:ngDblclick
15406 *
15407 * @description
15408 * The `ngDblclick` directive allows you to specify custom behavior on dblclick event.
15409 *
15410 * @element ANY
15411 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
15412 * dblclick. (Event object is available as `$event`)
15413 *
15414 * @example
15415 * See {@link ng.directive:ngClick ngClick}
15416 */
15417
15418
15419/**
15420 * @ngdoc directive
15421 * @name ng.directive:ngMousedown
15422 *
15423 * @description
15424 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
15425 *
15426 * @element ANY
15427 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
15428 * mousedown. (Event object is available as `$event`)
15429 *
15430 * @example
15431 * See {@link ng.directive:ngClick ngClick}
15432 */
15433
15434
15435/**
15436 * @ngdoc directive
15437 * @name ng.directive:ngMouseup
15438 *
15439 * @description
15440 * Specify custom behavior on mouseup event.
15441 *
15442 * @element ANY
15443 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
15444 * mouseup. (Event object is available as `$event`)
15445 *
15446 * @example
15447 * See {@link ng.directive:ngClick ngClick}
15448 */
15449
15450/**
15451 * @ngdoc directive
15452 * @name ng.directive:ngMouseover
15453 *
15454 * @description
15455 * Specify custom behavior on mouseover event.
15456 *
15457 * @element ANY
15458 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
15459 * mouseover. (Event object is available as `$event`)
15460 *
15461 * @example
15462 * See {@link ng.directive:ngClick ngClick}
15463 */
15464
15465
15466/**
15467 * @ngdoc directive
15468 * @name ng.directive:ngMouseenter
15469 *
15470 * @description
15471 * Specify custom behavior on mouseenter event.
15472 *
15473 * @element ANY
15474 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
15475 * mouseenter. (Event object is available as `$event`)
15476 *
15477 * @example
15478 * See {@link ng.directive:ngClick ngClick}
15479 */
15480
15481
15482/**
15483 * @ngdoc directive
15484 * @name ng.directive:ngMouseleave
15485 *
15486 * @description
15487 * Specify custom behavior on mouseleave event.
15488 *
15489 * @element ANY
15490 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
15491 * mouseleave. (Event object is available as `$event`)
15492 *
15493 * @example
15494 * See {@link ng.directive:ngClick ngClick}
15495 */
15496
15497
15498/**
15499 * @ngdoc directive
15500 * @name ng.directive:ngMousemove
15501 *
15502 * @description
15503 * Specify custom behavior on mousemove event.
15504 *
15505 * @element ANY
15506 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
15507 * mousemove. (Event object is available as `$event`)
15508 *
15509 * @example
15510 * See {@link ng.directive:ngClick ngClick}
15511 */
15512
15513
15514/**
15515 * @ngdoc directive
15516 * @name ng.directive:ngKeydown
15517 *
15518 * @description
15519 * Specify custom behavior on keydown event.
15520 *
15521 * @element ANY
15522 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
15523 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
15524 *
15525 * @example
15526 * See {@link ng.directive:ngClick ngClick}
15527 */
15528
15529
15530/**
15531 * @ngdoc directive
15532 * @name ng.directive:ngKeyup
15533 *
15534 * @description
15535 * Specify custom behavior on keyup event.
15536 *
15537 * @element ANY
15538 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
15539 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
15540 *
15541 * @example
15542 * See {@link ng.directive:ngClick ngClick}
15542
15543 */
15544
15545
15546/**
15547 * @ngdoc directive
15548 * @name ng.directive:ngKeypress
15549 *
15550 * @description
15551 * Specify custom behavior on keypress event.
15552 *
15553 * @element ANY
15554 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
15555 * keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
15556 *
15557 * @example
15558 * See {@link ng.directive:ngClick ngClick}
15559 */
15560
15561
15562/**
15563 * @ngdoc directive
15564 * @name ng.directive:ngSubmit
15565 *
15566 * @description
15567 * Enables binding angular expressions to onsubmit events.
15568 *
15569 * Additionally it prevents the default action (which for form means sending the request to the
15570 * server and reloading the current page) **but only if the form does not contain an `action`
15571 * attribute**.
15572 *
15573 * @element form
15574 * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
15575 *
15576 * @example
15577   <doc:example>
15578     <doc:source>
15579      <script>
15580        function Ctrl($scope) {
15581          $scope.list = [];
15582          $scope.text = 'hello';
15583          $scope.submit = function() {
15584            if (this.text) {
15585              this.list.push(this.text);
15586              this.text = '';
15587            }
15588          };
15589        }
15590      </script>
15591      <form ng-submit="submit()" ng-controller="Ctrl">
15592        Enter text and hit enter:
15593        <input type="text" ng-model="text" name="text" />
15594        <input type="submit" id="submit" value="Submit" />
15595        <pre>list={{list}}</pre>
15596      </form>
15597     </doc:source>
15598     <doc:scenario>
15599       it('should check ng-submit', function() {
15600         expect(binding('list')).toBe('[]');
15601         element('.doc-example-live #submit').click();
15602         expect(binding('list')).toBe('["hello"]');
15603         expect(input('text').val()).toBe('');
15604       });
15605       it('should ignore empty strings', function() {
15606         expect(binding('list')).toBe('[]');
15607         element('.doc-example-live #submit').click();
15608         element('.doc-example-live #submit').click();
15609         expect(binding('list')).toBe('["hello"]');
15610       });
15611     </doc:scenario>
15612   </doc:example>
15613 */
15614
15615/**
15616 * @ngdoc directive
15617 * @name ng.directive:ngFocus
15618 *
15619 * @description
15620 * Specify custom behavior on focus event.
15621 *
15622 * @element window, input, select, textarea, a
15623 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
15624 * focus. (Event object is available as `$event`)
15625 *
15626 * @example
15627 * See {@link ng.directive:ngClick ngClick}
15628 */
15629
15630/**
15631 * @ngdoc directive
15632 * @name ng.directive:ngBlur
15633 *
15634 * @description
15635 * Specify custom behavior on blur event.
15636 *
15637 * @element window, input, select, textarea, a
15638 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
15639 * blur. (Event object is available as `$event`)
15640 *
15641 * @example
15642 * See {@link ng.directive:ngClick ngClick}
15643 */
15644
15645/**
15646 * @ngdoc directive
15647 * @name ng.directive:ngIf
15648 * @restrict A
15649 *
15650 * @description
15651 * The `ngIf` directive removes and recreates a portion of the DOM tree (HTML)
15652 * conditionally based on **"falsy"** and **"truthy"** values, respectively, evaluated within
15653 * an {expression}. In other words, if the expression assigned to **ngIf evaluates to a false
15654 * value** then **the element is removed from the DOM** and **if true** then **a clone of the
15655 * element is reinserted into the DOM**.
15656 *
15657 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
15658 * element in the DOM rather than changing its visibility via the `display` css property.  A common
15659 * case when this difference is significant is when using css selectors that rely on an element's
15660 * position within the DOM (HTML), such as the `:first-child` or `:last-child` pseudo-classes.
15661 *
15662 * Note that **when an element is removed using ngIf its scope is destroyed** and **a new scope
15663 * is created when the element is restored**.  The scope created within `ngIf` inherits from 
15664 * its parent scope using
15665 * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
15666 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
15667 * a javascript primitive defined in the parent scope. In this case any modifications made to the
15668 * variable within the child scope will override (hide) the value in the parent scope.
15669 *
15670 * Also, `ngIf` recreates elements using their compiled state. An example scenario of this behavior
15671 * is if an element's class attribute is directly modified after it's compiled, using something like 
15672 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
15673 * the added class will be lost because the original compiled state is used to regenerate the element.
15674 *
15675 * Additionally, you can provide animations via the ngAnimate module to animate the **enter**
15676 * and **leave** effects.
15677 *
15678 * @animations
15679 * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
15680 * leave - happens just before the ngIf contents are removed from the DOM
15681 *
15682 * @element ANY
15683 * @scope
15684 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
15685 *     the element is removed from the DOM tree (HTML).
15686 *
15687 * @example
15688  <example animations="true">
15689    <file name="index.html">
15690      Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
15691      Show when checked:
15692      <span ng-if="checked" class="animate-if">
15693        I'm removed when the checkbox is unchecked.
15694      </span>
15695    </file>
15696    <file name="animations.css">
15697      .animate-if {
15698        background:white;
15699        border:1px solid black;
15700        padding:10px;
15701      }
15702
15703      .animate-if.ng-enter, .animate-if.ng-leave {
15704        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15705        -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15706        -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15707        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15708      }
15709
15710      .animate-if.ng-enter,
15711      .animate-if.ng-leave.ng-leave-active {
15712        opacity:0;
15713      }
15714
15715      .animate-if.ng-enter.ng-enter-active,
15716      .animate-if.ng-leave {
15717        opacity:1;
15718      }
15719    </file>
15720  </example>
15721 */
15722var ngIfDirective = ['$animate', function($animate) {
15723  return {
15724    transclude: 'element',
15725    priority: 1000,
15726    terminal: true,
15727    restrict: 'A',
15728    compile: function (element, attr, transclude) {
15729      return function ($scope, $element, $attr) {
15730        var childElement, childScope;
15731        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
15732          if (childElement) {
15733            $animate.leave(childElement);
15734            childElement = undefined;
15735          }
15736          if (childScope) {
15737            childScope.$destroy();
15738            childScope = undefined;
15739          }
15740          if (toBoolean(value)) {
15741            childScope = $scope.$new();
15742            transclude(childScope, function (clone) {
15743              childElement = clone;
15744              $animate.enter(clone, $element.parent(), $element);
15745            });
15746          }
15747        });
15748      }
15749    }
15750  }
15751}];
15752
15753/**
15754 * @ngdoc directive
15755 * @name ng.directive:ngInclude
15756 * @restrict ECA
15757 *
15758 * @description
15759 * Fetches, compiles and includes an external HTML fragment.
15760 *
15761 * Keep in mind that:
15762 *
15763 * -    by default, the template URL is restricted to the same domain and protocol as the
15764 *      application document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
15765 *      $sce.getTrustedResourceUrl} on it.  To load templates from other domains and/or protocols,
15766 *      you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
15767 *      {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.  Refer Angular's {@link
15768 *      ng.$sce Strict Contextual Escaping}.
15769 * -    in addition, the browser's
15770 *      {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
15771 *      Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
15772 *      (CORS)} policy apply that may further restrict whether the template is successfully loaded.
15773 *      (e.g.  ngInclude won't work for cross-domain requests on all browsers and for `file://`
15774 *      access on some browsers)
15775 *
15776 * @animations
15777 * enter - animation is used to bring new content into the browser.
15778 * leave - animation is used to animate existing content away.
15779 *
15780 * The enter and leave animation occur concurrently.
15781 *
15782 * @scope
15783 *
15784 * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
15785 *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
15786 * @param {string=} onload Expression to evaluate when a new partial is loaded.
15787 *
15788 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
15789 *                  $anchorScroll} to scroll the viewport after the content is loaded.
15790 *
15791 *                  - If the attribute is not set, disable scrolling.
15792 *                  - If the attribute is set without value, enable scrolling.
15793 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
15794 *
15795 * @example
15796  <example animations="true">
15797    <file name="index.html">
15798     <div ng-controller="Ctrl">
15799       <select ng-model="template" ng-options="t.name for t in templates">
15800        <option value="">(blank)</option>
15801       </select>
15802       url of the template: <tt>{{template.url}}</tt>
15803       <hr/>
15804       <div class="example-animate-container">
15805         <div class="include-example" ng-include="template.url"></div>
15806       </div>
15807     </div>
15808    </file>
15809    <file name="script.js">
15810      function Ctrl($scope) {
15811        $scope.templates =
15812          [ { name: 'template1.html', url: 'template1.html'}
15813          , { name: 'template2.html', url: 'template2.html'} ];
15814        $scope.template = $scope.templates[0];
15815      }
15816     </file>
15817    <file name="template1.html">
15818      Content of template1.html
15819    </file>
15820    <file name="template2.html">
15821      Content of template2.html
15822    </file>
15823    <file name="animations.css">
15824      .example-animate-container {
15825        position:relative;
15826        background:white;
15827        border:1px solid black;
15828        height:40px;
15829        overflow:hidden;
15830      }
15831
15832      .example-animate-container > div {
15833        padding:10px;
15834      }
15835
15836      .include-example.ng-enter, .include-example.ng-leave {
15837        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15838        -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15839        -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15840        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
15841
15842        position:absolute;
15843        top:0;
15844        left:0;
15845        right:0;
15846        bottom:0;
15847        display:block;
15848        padding:10px;
15849      }
15850
15851      .include-example.ng-enter {
15852        top:-50px;
15853      }
15854      .include-example.ng-enter.ng-enter-active {
15855        top:0;
15856      }
15857
15858      .include-example.ng-leave {
15859        top:0;
15860      }
15861      .include-example.ng-leave.ng-leave-active {
15862        top:50px;
15863      }
15864    </file>
15865    <file name="scenario.js">
15866      it('should load template1.html', function() {
15867       expect(element('.doc-example-live [ng-include]').text()).
15868         toMatch(/Content of template1.html/);
15869      });
15870      it('should load template2.html', function() {
15871       select('template').option('1');
15872       expect(element('.doc-example-live [ng-include]').text()).
15873         toMatch(/Content of template2.html/);
15874      });
15875      it('should change to blank', function() {
15876       select('template').option('');
15877       expect(element('.doc-example-live [ng-include]')).toBe(undefined);
15878      });
15879    </file>
15880  </example>
15881 */
15882
15883
15884/**
15885 * @ngdoc event
15886 * @name ng.directive:ngInclude#$includeContentRequested
15887 * @eventOf ng.directive:ngInclude
15888 * @eventType emit on the scope ngInclude was declared in
15889 * @description
15890 * Emitted every time the ngInclude content is requested.
15891 */
15892
15893
15894/**
15895 * @ngdoc event
15896 * @name ng.directive:ngInclude#$includeContentLoaded
15897 * @eventOf ng.directive:ngInclude
15898 * @eventType emit on the current ngInclude scope
15899 * @description
15900 * Emitted every time the ngInclude content is reloaded.
15901 */
15902var NG_INCLUDE_PRIORITY = 500;
15903var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile', '$animate', '$sce',
15904                  function($http,   $templateCache,   $anchorScroll,   $compile,   $animate,   $sce) {
15905  return {
15906    restrict: 'ECA',
15907    terminal: true,
15908    priority: NG_INCLUDE_PRIORITY,
15909    compile: function(element, attr) {
15910      var srcExp = attr.ngInclude || attr.src,
15911          onloadExp = attr.onload || '',
15912          autoScrollExp = attr.autoscroll;
15913
15914      element.html('');
15915      var anchor = jqLite(document.createComment(' ngInclude: ' + srcExp + ' '));
15916      element.replaceWith(anchor);
15917
15918      return function(scope) {
15919        var changeCounter = 0,
15920            currentScope,
15921            currentElement;
15922
15923        var cleanupLastIncludeContent = function() {
15924          if (currentScope) {
15925            currentScope.$destroy();
15926            currentScope = null;
15927          }
15928          if(currentElement) {
15929            $animate.leave(currentElement);
15930            currentElement = null;
15931          }
15932        };
15933
15934        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
15935          var thisChangeId = ++changeCounter;
15936
15937          if (src) {
15938            $http.get(src, {cache: $templateCache}).success(function(response) {
15939              if (thisChangeId !== changeCounter) return;
15940              var newScope = scope.$new();
15941
15942              cleanupLastIncludeContent();
15943
15944              currentScope = newScope;
15945              currentElement = element.clone();
15946              currentElement.html(response);
15947              $animate.enter(currentElement, null, anchor);
15948
15949              $compile(currentElement, false, NG_INCLUDE_PRIORITY - 1)(currentScope);
15950
15951              if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
15952                $anchorScroll();
15953              }
15954
15955              currentScope.$emit('$includeContentLoaded');
15956              scope.$eval(onloadExp);
15957            }).error(function() {
15958              if (thisChangeId === changeCounter) cleanupLastIncludeContent();
15959            });
15960            scope.$emit('$includeContentRequested');
15961          } else {
15962            cleanupLastIncludeContent();
15963          }
15964        });
15965      };
15966    }
15967  };
15968}];
15969
15970/**
15971 * @ngdoc directive
15972 * @name ng.directive:ngInit
15973 *
15974 * @description
15975 * The `ngInit` directive specifies initialization tasks to be executed
15976 *  before the template enters execution mode during bootstrap.
15977 *
15978 * @element ANY
15979 * @param {expression} ngInit {@link guide/expression Expression} to eval.
15980 *
15981 * @example
15982   <doc:example>
15983     <doc:source>
15984    <div ng-init="greeting='Hello'; person='World'">
15985      {{greeting}} {{person}}!
15986    </div>
15987     </doc:source>
15988     <doc:scenario>
15989       it('should check greeting', function() {
15990         expect(binding('greeting')).toBe('Hello');
15991         expect(binding('person')).toBe('World');
15992       });
15993     </doc:scenario>
15994   </doc:example>
15995 */
15996var ngInitDirective = ngDirective({
15997  compile: function() {
15998    return {
15999      pre: function(scope, element, attrs) {
16000        scope.$eval(attrs.ngInit);
16001      }
16002    }
16003  }
16004});
16005
16006/**
16007 * @ngdoc directive
16008 * @name ng.directive:ngNonBindable
16009 * @priority 1000
16010 *
16011 * @description
16012 * Sometimes it is necessary to write code which looks like bindings but which should be left alone
16013 * by angular. Use `ngNonBindable` to make angular ignore a chunk of HTML.
16014 *
16015 * @element ANY
16016 *
16017 * @example
16018 * In this example there are two location where a simple binding (`{{}}`) is present, but the one
16019 * wrapped in `ngNonBindable` is left alone.
16020 *
16021 * @example
16022    <doc:example>
16023      <doc:source>
16024        <div>Normal: {{1 + 2}}</div>
16025        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
16026      </doc:source>
16027      <doc:scenario>
16028       it('should check ng-non-bindable', function() {
16029         expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
16030         expect(using('.doc-example-live').element('div:last').text()).
16031           toMatch(/1 \+ 2/);
16032       });
16033      </doc:scenario>
16034    </doc:example>
16035 */
16036var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
16037
16038/**
16039 * @ngdoc directive
16040 * @name ng.directive:ngPluralize
16041 * @restrict EA
16042 *
16043 * @description
16044 * # Overview
16045 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
16046 * These rules are bundled with angular.js, but can be overridden
16047 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
16048 * by specifying the mappings between
16049 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
16050 * plural categories} and the strings to be displayed.
16051 *
16052 * # Plural categories and explicit number rules
16053 * There are two
16054 * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
16055 * plural categories} in Angular's default en-US locale: "one" and "other".
16056 *
16057 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
16058 * any number that is not 1), an explicit number rule can only match one number. For example, the
16059 * explicit number rule for "3" matches the number 3. There are examples of plural categories
16060 * and explicit number rules throughout the rest of this documentation.
16061 *
16062 * # Configuring ngPluralize
16063 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
16064 * You can also provide an optional attribute, `offset`.
16065 *
16066 * The value of the `count` attribute can be either a string or an {@link guide/expression
16067 * Angular expression}; these are evaluated on the current scope for its bound value.
16068 *
16069 * The `when` attribute specifies the mappings between plural categories and the actual
16070 * string to be displayed. The value of the attribute should be a JSON object.
16071 *
16072 * The following example shows how to configure ngPluralize:
16073 *
16074 * <pre>
16075 * <ng-pluralize count="personCount"
16076                 when="{'0': 'Nobody is viewing.',
16077 *                      'one': '1 person is viewing.',
16078 *                      'other': '{} people are viewing.'}">
16079 * </ng-pluralize>
16080 *</pre>
16081 *
16082 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
16083 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
16084 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
16085 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
16086 * show "a dozen people are viewing".
16087 *
16088 * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted
16089 * into pluralized strings. In the previous example, Angular will replace `{}` with
16090 * <span ng-non-bindable>`{{personCount}}
16090`</span>. The closed braces `{}` is a placeholder
16091 * for <span ng-non-bindable>{{numberExpression}}</span>.
16092 *
16093 * # Configuring ngPluralize with offset
16094 * The `offset` attribute allows further customization of pluralized text, which can result in
16095 * a better user experience. For example, instead of the message "4 people are viewing this document",
16096 * you might display "John, Kate and 2 others are viewing this document".
16097 * The offset attribute allows you to offset a number by any desired value.
16098 * Let's take a look at an example:
16099 *
16100 * <pre>
16101 * <ng-pluralize count="personCount" offset=2
16102 *               when="{'0': 'Nobody is viewing.',
16103 *                      '1': '{{person1}} is viewing.',
16104 *                      '2': '{{person1}} and {{person2}} are viewing.',
16105 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
16106 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
16107 * </ng-pluralize>
16108 * </pre>
16109 *
16110 * Notice that we are still using two plural categories(one, other), but we added
16111 * three explicit number rules 0, 1 and 2.
16112 * When one person, perhaps John, views the document, "John is viewing" will be shown.
16113 * When three people view the document, no explicit number rule is found, so
16114 * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
16115 * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
16116 * is shown.
16117 *
16118 * Note that when you specify offsets, you must provide explicit number rules for
16119 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
16120 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
16121 * plural categories "one" and "other".
16122 *
16123 * @param {string|expression} count The variable to be bounded to.
16124 * @param {string} when The mapping between plural category to its corresponding strings.
16125 * @param {number=} offset Offset to deduct from the total number.
16126 *
16127 * @example
16128    <doc:example>
16129      <doc:source>
16130        <script>
16131          function Ctrl($scope) {
16132            $scope.person1 = 'Igor';
16133            $scope.person2 = 'Misko';
16134            $scope.personCount = 1;
16135          }
16136        </script>
16137        <div ng-controller="Ctrl">
16138          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
16139          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
16140          Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
16141
16142          <!--- Example with simple pluralization rules for en locale --->
16143          Without Offset:
16144          <ng-pluralize count="personCount"
16145                        when="{'0': 'Nobody is viewing.',
16146                               'one': '1 person is viewing.',
16147                               'other': '{} people are viewing.'}">
16148          </ng-pluralize><br>
16149
16150          <!--- Example with offset --->
16151          With Offset(2):
16152          <ng-pluralize count="personCount" offset=2
16153                        when="{'0': 'Nobody is viewing.',
16154                               '1': '{{person1}} is viewing.',
16155                               '2': '{{person1}} and {{person2}} are viewing.',
16156                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
16157                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
16158          </ng-pluralize>
16159        </div>
16160      </doc:source>
16161      <doc:scenario>
16162        it('should show correct pluralized string', function() {
16163          expect(element('.doc-example-live ng-pluralize:first').text()).
16164                                             toBe('1 person is viewing.');
16165          expect(element('.doc-example-live ng-pluralize:last').text()).
16166                                                toBe('Igor is viewing.');
16167
16168          using('.doc-example-live').input('personCount').enter('0');
16169          expect(element('.doc-example-live ng-pluralize:first').text()).
16170                                               toBe('Nobody is viewing.');
16171          expect(element('.doc-example-live ng-pluralize:last').text()).
16172                                              toBe('Nobody is viewing.');
16173
16174          using('.doc-example-live').input('personCount').enter('2');
16175          expect(element('.doc-example-live ng-pluralize:first').text()).
16176                                            toBe('2 people are viewing.');
16177          expect(element('.doc-example-live ng-pluralize:last').text()).
16178                              toBe('Igor and Misko are viewing.');
16179
16180          using('.doc-example-live').input('personCount').enter('3');
16181          expect(element('.doc-example-live ng-pluralize:first').text()).
16182                                            toBe('3 people are viewing.');
16183          expect(element('.doc-example-live ng-pluralize:last').text()).
16184                              toBe('Igor, Misko and one other person are viewing.');
16185
16186          using('.doc-example-live').input('personCount').enter('4');
16187          expect(element('.doc-example-live ng-pluralize:first').text()).
16188                                            toBe('4 people are viewing.');
16189          expect(element('.doc-example-live ng-pluralize:last').text()).
16190                              toBe('Igor, Misko and 2 other people are viewing.');
16191        });
16192
16193        it('should show data-binded names', function() {
16194          using('.doc-example-live').input('personCount').enter('4');
16195          expect(element('.doc-example-live ng-pluralize:last').text()).
16196              toBe('Igor, Misko and 2 other people are viewing.');
16197
16198          using('.doc-example-live').input('person1').enter('Di');
16199          using('.doc-example-live').input('person2').enter('Vojta');
16200          expect(element('.doc-example-live ng-pluralize:last').text()).
16201              toBe('Di, Vojta and 2 other people are viewing.');
16202        });
16203      </doc:scenario>
16204    </doc:example>
16205 */
16206var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
16207  var BRACE = /{}/g;
16208  return {
16209    restrict: 'EA',
16210    link: function(scope, element, attr) {
16211      var numberExp = attr.count,
16212          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
16213          offset = attr.offset || 0,
16214          whens = scope.$eval(whenExp) || {},
16215          whensExpFns = {},
16216          startSymbol = $interpolate.startSymbol(),
16217          endSymbol = $interpolate.endSymbol(),
16218          isWhen = /^when(Minus)?(.+)$/;
16219
16220      forEach(attr, function(expression, attributeName) {
16221        if (isWhen.test(attributeName)) {
16222          whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
16223            element.attr(attr.$attr[attributeName]);
16224        }
16225      });
16226      forEach(whens, function(expression, key) {
16227        whensExpFns[key] =
16228          $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
16229            offset + endSymbol));
16230      });
16231
16232      scope.$watch(function ngPluralizeWatch() {
16233        var value = parseFloat(scope.$eval(numberExp));
16234
16235        if (!isNaN(value)) {
16236          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
16237          //check it against pluralization rules in $locale service
16238          if (!(value in whens)) value = $locale.pluralCat(value - offset);
16239           return whensExpFns[value](scope, element, true);
16240        } else {
16241          return '';
16242        }
16243      }, function ngPluralizeWatchAction(newVal) {
16244        element.text(newVal);
16245      });
16246    }
16247  };
16248}];
16249
16250/**
16251 * @ngdoc directive
16252 * @name ng.directive:ngRepeat
16253 *
16254 * @description
16255 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
16256 * instance gets its own scope, where the given loop variable is set to the current collection item,
16257 * and `$index` is set to the item index or key.
16258 *
16259 * Special properties are exposed on the local scope of each template instance, including:
16260 *
16261 * | Variable  | Type            | Details                                                                     |
16262 * |-----------|-----------------|-----------------------------------------------------------------------------|
16263 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
16264 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
16265 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
16266 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
16267 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
16268 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
16269 *
16270 *
16271 * # Special repeat start and end points
16272 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
16273 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
16274 * 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)
16275 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
16276 *
16277 * The example below makes use of this feature:
16278 * <pre>
16279 *   <header ng-repeat-start="item in items">
16280 *     Header {{ item }}
16281 *   </header>
16282 *   <div class="body">
16283 *     Body {{ item }}
16284 *   </div>
16285 *   <footer ng-repeat-end>
16286 *     Footer {{ item }}
16287 *   </footer>
16288 * </pre>
16289 *
16290 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
16291 * <pre>
16292 *   <header>
16293 *     Header A
16294 *   </header>
16295 *   <div class="body">
16296 *     Body A
16297 *   </div>
16298 *   <footer>
16299 *     Footer A
16300 *   </footer>
16301 *   <header>
16302 *     Header B
16303 *   </header>
16304 *   <div class="body">
16305 *     Body B
16306 *   </div>
16307 *   <footer>
16308 *     Footer B
16309 *   </footer>
16310 * </pre>
16311 *
16312 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
16313 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
16314 *
16315 * @animations
16316 * enter - when a new item is added to the list or when an item is revealed after a filter
16317 * leave - when an item is removed from the list or when an item is filtered out
16318 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
16319 *
16320 * @element ANY
16321 * @scope
16322 * @priority 1000
16323 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
16324 *   formats are currently supported:
16325 *
16326 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
16327 *     is a scope expression giving the collection to enumerate.
16328 *
16329 *     For example: `album in artist.albums`.
16330 *
16331 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
16332 *     and `expression` is the scope expression giving the collection to enumerate.
16333 *
16334 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
16335 *
16336 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
16337 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
16338 *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
16339 *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
16340 *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
16341 *     before specifying a tracking expression.
16342 *
16343 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
16344 *     will be associated by item identity in the array.
16345 *
16346 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
16347 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
16348 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
16349 *     element in the same way ian the DOM.
16350 *
16351 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
16352 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
16353 *     property is same.
16354 *
16355 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
16356 *     to items in conjunction with a tracking expression.
16357 *
16358 * @example
16359 * This example initializes the scope to a list of names and
16360 * then uses `ngRepeat` to display every person:
16361  <example animations="true">
16362    <file name="index.html">
16363      <div ng-init="friends = [
16364        {name:'John', age:25, gender:'boy'},
16365        {name:'Jessie', age:30, gender:'girl'},
16366        {name:'Johanna', age:28, gender:'girl'},
16367        {name:'Joy', age:15, gender:'girl'},
16368        {name:'Mary', age:28, gender:'girl'},
16369        {name:'Peter', age:95, gender:'boy'},
16370        {name:'Sebastian', age:50, gender:'boy'},
16371        {name:'Erika', age:27, gender:'girl'},
16372        {name:'Patrick', age:40, gender:'boy'},
16373        {name:'Samantha', age:60, gender:'girl'}
16374      ]">
16375        I have {{friends.length}} friends. They are:
16376        <input type="search" ng-model="q" placeholder="filter friends..." />
16377        <ul class="example-animate-container">
16378          <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
16379            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
16380          </li>
16381        </ul>
16382      </div>
16383    </file>
16384    <file name="animations.css">
16385      .example-animate-container {
16386        background:white;
16387        border:1px solid black;
16388        list-style:none;
16389        margin:0;
16390        padding:0;
16391      }
16392
16393      .example-animate-container > li {
16394        padding:10px;
16395        list-style:none;
16396      }
16397
16398      .animate-repeat.ng-enter,
16399      .animate-repeat.ng-leave,
16400      .animate-repeat.ng-move {
16401        -webkit-transition:all linear 0.5s;
16402        -moz-transition:all linear 0.5s;
16403        -o-transition:all linear 0.5s;
16404        transition:all linear 0.5s;
16405      }
16406
16407      .animate-repeat.ng-enter {
16408        line-height:0;
16409        opacity:0;
16410        padding-top:0;
16411        padding-bottom:0;
16412      }
16413      .animate-repeat.ng-enter.ng-enter-active {
16414        line-height:20px;
16415        opacity:1;
16416        padding:10px;
16417      }
16418
16419      .animate-repeat.ng-leave {
16420        opacity:1;
16421        line-height:20px;
16422        padding:10px;
16423      }
16424      .animate-repeat.ng-leave.ng-leave-active {
16425        opacity:0;
16426        line-height:0;
16427        padding-top:0;
16428        padding-bottom:0;
16429      }
16430
16431      .animate-repeat.ng-move { }
16432      .animate-repeat.ng-move.ng-move-active { }
16433    </file>
16434    <file name="scenario.js">
16435       it('should render initial data set', function() {
16436         var r = using('.doc-example-live').repeater('ul li');
16437         expect(r.count()).toBe(10);
16438         expect(r.row(0)).toEqual(["1","John","25"]);
16439         expect(r.row(1)).toEqual(["2","Jessie","30"]);
16440         expect(r.row(9)).toEqual(["10","Samantha","60"]);
16441         expect(binding('friends.length')).toBe("10");
16442       });
16443
16444       it('should update repeater when filter predicate changes', function() {
16445         var r = using('.doc-example-live').repeater('ul li');
16446         expect(r.count()).toBe(10);
16447
16448         input('q').enter('ma');
16449
16450         expect(r.count()).toBe(2);
16451         expect(r.row(0)).toEqual(["1","Mary","28"]);
16452         expect(r.row(1)).toEqual(["2","Samantha","60"]);
16453       });
16454      </file>
16455    </example>
16456 */
16457var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
16458  var NG_REMOVED = '$$NG_REMOVED';
16459  var ngRepeatMinErr = minErr('ngRepeat');
16460  return {
16461    transclude: 'element',
16462    priority: 1000,
16463    terminal: true,
16464    compile: function(element, attr, linker) {
16465      return function($scope, $element, $attr){
16466        var expression = $attr.ngRepeat;
16467        var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
16468          trackByExp, trackByExpGetter, trackByIdFn, trackByIdArrayFn, trackByIdObjFn, lhs, rhs, valueIdentifier, keyIdentifier,
16469          hashFnLocals = {$id: hashKey};
16470
16471        if (!match) {
16472          throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
16473            expression);
16474        }
16475
16476        lhs = match[1];
16477        rhs = match[2];
16478        trackByExp = match[4];
16479
16480        if (trackByExp) {
16481          trackByExpGetter = $parse(trackByExp);
16482          trackByIdFn = function(key, value, index) {
16483            // assign key, value, and $index to the locals so that they can be used in hash functions
16484            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
16485            hashFnLocals[valueIdentifier] = value;
16486            hashFnLocals.$index = index;
16487            return trackByExpGetter($scope, hashFnLocals);
16488          };
16489        } else {
16490          trackByIdArrayFn = function(key, value) {
16491            return hashKey(value);
16492          }
16493          trackByIdObjFn = function(key) {
16494            return key;
16495          }
16496        }
16497
16498        match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
16499        if (!match) {
16500          throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
16501                                                                    lhs);
16502        }
16503        valueIdentifier = match[3] || match[1];
16504        keyIdentifier = match[2];
16505
16506        // Store a list of elements from previous run. This is a hash where key is the item from the
16507        // iterator, and the value is objects with following properties.
16508        //   - scope: bound scope
16509        //   - element: previous element.
16510        //   - index: position
16511        var lastBlockMap = {};
16512
16513        //watch props
16514        $scope.$watchCollection(rhs, function ngRepeatAction(collection){
16515          var index, length,
16516              previousNode = $element[0],     // current position of the node
16517              nextNode,
16518              // Same as lastBlockMap but it has the current state. It will become the
16519              // lastBlockMap on the next iteration.
16520              nextBlockMap = {},
16521              arrayLength,
16522              childScope,
16523              key, value, // key/value of iteration
16524              trackById,
16525              collectionKeys,
16526              block,       // last object information {scope, element, id}
16527              nextBlockOrder = [];
16528
16529
16530          if (isArrayLike(collection)) {
16531            collectionKeys = collection;
16532            trackByIdFn = trackByIdFn || trackByIdArrayFn;
16533          } else {
16534            trackByIdFn = trackByIdFn || trackByIdObjFn;
16535            // if object, extract keys, sort them and use to determine order of iteration over obj props
16536            collectionKeys = [];
16537            for (key in collection) {
16538              if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
16539                collectionKeys.push(key);
16540              }
16541            }
16542            collectionKeys.sort();
16543          }
16544
16545          arrayLength = collectionKeys.length;
16546
16547          // locate existing items
16548          length = nextBlockOrder.length = collectionKeys.length;
16549          for(index = 0; index < length; index++) {
16550           key = (collection === collectionKeys) ? index : collectionKeys[index];
16551           value = collection[key];
16552           trackById = trackByIdFn(key, value, index);
16553           if(lastBlockMap.hasOwnProperty(trackById)) {
16554             block = lastBlockMap[trackById]
16555             delete lastBlockMap[trackById];
16556             nextBlockMap[trackById] = block;
16557             nextBlockOrder[index] = block;
16558           } else if (nextBlockMap.hasOwnProperty(trackById)) {
16559             // restore lastBlockMap
16560             forEach(nextBlockOrder, function(block) {
16561               if (block && block.startNode) lastBlockMap[block.id] = block;
16562             });
16563             // This is a duplicate and we need to throw an error
16564             throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
16565                                                                                                                                                    expression,       trackById);
16566           } else {
16567             // new never before seen block
16568             nextBlockOrder[index] = { id: trackById };
16569             nextBlockMap[trackById] = false;
16570           }
16571         }
16572
16573          // remove existing items
16574          for (key in lastBlockMap) {
16575            if (lastBlockMap.hasOwnProperty(key)) {
16576              block = lastBlockMap[key];
16577              $animate.leave(block.elements);
16578              forEach(block.elements, function(element) { element[NG_REMOVED] = true});
16579              block.scope.$destroy();
16580            }
16581          }
16582
16583          // we are not using forEach for perf reasons (trying to avoid #call)
16584          for (index = 0, length = collectionKeys.length; index < length; index++) {
16585            key = (collection === collectionKeys) ? index : collectionKeys[index];
16586            value = collection[key];
16587            block = nextBlockOrder[index];
16588
16589            if (block.startNode) {
16590              // if we have already seen this object, then we need to reuse the
16591              // associated scope/element
16592              childScope = block.scope;
16593
16594              nextNode = previousNode;
16595              do {
16596                nextNode = nextNode.nextSibling;
16597              } while(nextNode && nextNode[NG_REMOVED]);
16598
16599              if (block.startNode == nextNode) {
16600                // do nothing
16601              } else {
16602                // existing item which got moved
16603                $animate.move(block.elements, null, jqLite(previousNode));
16604              }
16605              previousNode = block.endNode;
16606            } else {
16607              // new item which we don't know about
16608              childScope = $scope.$new();
16609            }
16610
16611            childScope[valueIdentifier] = value;
16612            if (keyIdentifier) childScope[keyIdentifier] = key;
16613            childScope.$index = index;
16614            childScope.$first = (index === 0);
16615            childScope.$last = (index === (arrayLength - 1));
16616            childScope.$middle = !(childScope.$first || childScope.$last);
16617            childScope.$odd = !(childScope.$even = index%2==0);
16618
16619            if (!block.startNode) {
16620              linker(childScope, function(clone) {
16621                $animate.enter(clone, null, jqLite(previousNode));
16622                previousNode = clone;
16623                block.scope = childScope;
16624                block.startNode = clone[0];
16625                block.elements = clone;
16626                block.endNode = clone[clone.length - 1];
16627                nextBlockMap[block.id] = block;
16628              });
16629            }
16630          }
16631          lastBlockMap = nextBlockMap;
16632        });
16633      };
16634    }
16635  };
16636}];
16637
16638/**
16639 * @ngdoc directive
16640 * @name ng.directive:ngShow
16641 *
16642 * @description
16643 * The `ngShow` directive shows and hides the given HTML element conditionally based on the expression
16644 * provided to the ngShow attribute. The show and hide mechanism is a achieved by removing and adding
16645 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is a predefined CSS class present
16646 * in AngularJS which sets the display style to none (using an !important flag).
16647 *
16648 * <pre>
16649 * <!-- when $scope.myValue is truthy (element is visible) -->
16650 * <div ng-show="myValue"></div>
16651 *
16652 * <!-- when $scope.myValue is falsy (element is hidden) -->
16653 * <div ng-show="myValue" class="ng-hide"></div>
16654 * </pre>
16655 *
16656 * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
16657 * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
16658 * from the element causing the element not to appear hidden.
16659 *
16660 * ## Why is !important used?
16661 *
16662 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
16663 * can be easily overridden by heavier selectors. For example, something as simple
16664 * as changing the display style on a HTML list item would make hidden elements appear visible.
16665 * This also becomes a bigger issue when dealing with CSS frameworks.
16666 *
16667 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
16668 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
16669 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
16670 *
16671 * ### Overriding .ng-hide
16672 *
16673 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
16674 * restating the styles for the .ng-hide class in CSS:
16675 * <pre>
16676 * .ng-hide {
16677 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
16678 *   display:block!important;
16679 *
16680 *   //this is just another form of hiding an element
16681 *   position:absolute;
16682 *   top:-9999px;
16683 *   left:-9999px;
16684 * }
16685 * </pre>
16686 *
16687 * Just remember to include the important flag so the CSS override will function.
16688 *
16689 * ## A note about animations with ngShow
16690 *
16691 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
16692 * is true and false. This system works similar to the animation system present with ngClass, however, the
16693 * only difference is that you must also include the !important flag to override the display property so
16694 * that you can perform an animation when the element is hidden during the time of the animation.
16695 *
16696 * <pre>
16697 * //
16698 * //a working example can be found at the bottom of this page
16699 * //
16700 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
16701 *   transition:0.5s linear all;
16702 *   display:block!important;
16703 * }
16704 *
16705 * .my-element.ng-hide-add { ... }
16706 * .my-element.ng-hide-add.ng-hide-add-active { ... }
16707 * .my-element.ng-hide-remove { ... }
16708 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
16709 * </pre>
16710 *
16711 * @animations
16712 * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
16713 * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
16714 *
16715 * @element ANY
16716 * @param {expression} ngShow If the {@link guide/expression expression} is truthy
16717 *     then the element is shown or hidden respectively.
16718 *
16719 * @example
16720  <example animations="true">
16721    <file name="index.html">
16722      Click me: <input type="checkbox" ng-model="checked"><br/>
16723      <div>
16724        Show:
16725        <div class="check-element animate-show" ng-show="checked">
16726          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
16727        </div>
16728      </div>
16729      <div>
16730        Hide:
16731        <div class="check-element animate-show" ng-hide="checked">
16732          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
16733        </div>
16734      </div>
16735    </file>
16736    <file name="animations.css">
16737      .animate-show.ng-hide-add, 
16738      .animate-show.ng-hide-remove {
16739        -webkit-transition:all linear 0.5s;
16740        -moz-transition:all linear 0.5s;
16741        -o-transition:all linear 0.5s;
16742        transition:all linear 0.5s;
16743        display:block!important;
16744      }
16745
16746      .animate-show.ng-hide-add.ng-hide-add-active,
16747      .animate-show.ng-hide-remove {
16748        line-height:0;
16749        opacity:0;
16750        padding:0 10px;
16751      }
16752
16753      .animate-show.ng-hide-add,
16754      .animate-show.ng-hide-remove.ng-hide-remove-active {
16755        line-height:20px;
16756        opacity:1;
16757        padding:10px;
16758        border:1px solid black;
16759        background:white;
16760      }
16761
16762      .check-element {
16763        padding:10px;
16764        border:1px solid black;
16765        background:white;
16766      }
16767    </file>
16768    <file name="scenario.js">
16769       it('should check ng-show / ng-hide', function() {
16770         expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
16771         expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
16772
16773         input('checked').check();
16774
16775         expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
16776         expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
16777       });
16778    </file>
16779  </example>
16780 */
16781var ngShowDirective = ['$animate', function($animate) {
16782  return function(scope, element, attr) {
16783    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
16784      $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
16785    });
16786  };
16787}];
16788
16789
16790/**
16791 * @ngdoc directive
16792 * @name ng.directive:ngHide
16793 *
16794 * @description
16795 * The `ngHide` directive shows and hides the given HTML element conditionally based on the expression
16796 * provided to the ngHide attribute. The show and hide mechanism is a achieved by removing and adding
16797 * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is a predefined CSS class present
16798 * in AngularJS which sets the display style to none (using an !important flag).
16799 *
16800 * <pre>
16801 * <!-- when $scope.myValue is truthy (element is hidden) -->
16802 * <div ng-hide="myValue"></div>
16803 *
16804 * <!-- when $scope.myValue is falsy (element is visible) -->
16805 * <div ng-hide="myValue" class="ng-hide"></div>
16806 * </pre>
16807 *
16808 * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
16809 * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
16810 * from the element causing the element not to appear hidden.
16811 *
16812 * ## Why is !important used?
16813 *
16814 * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
16815 * can be easily overridden by heavier selectors. For example, something as simple
16816 * as changing the display style on a HTML list item would make hidden elements appear visible.
16817 * This also becomes a bigger issue when dealing with CSS frameworks.
16818 *
16819 * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
16820 * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
16821 * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
16822 *
16823 * ### Overriding .ng-hide
16824 *
16825 * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
16826 * restating the styles for the .ng-hide class in CSS:
16827 * <pre>
16828 * .ng-hide {
16829 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
16830 *   display:block!important;
16831 *
16832 *   //this is just another form of hiding an element
16833 *   position:absolute;
16834 *   top:-9999px;
16835 *   left:-9999px;
16836 * }
16837 * </pre>
16838 *
16839 * Just remember to include the important flag so the CSS override will function.
16840 *
16841 * ## A note about animations with ngHide
16842 *
16843 * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
16844 * is true and false. This system works similar to the animation system present with ngClass, however, the
16845 * only difference is that you must also include the !important flag to override the display property so
16846 * that you can perform an animation when the element is hidden during the time of the animation.
16847 *
16848 * <pre>
16849 * //
16850 * //a working example can be found at the bottom of this page
16851 * //
16852 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
16853 *   transition:0.5s linear all;
16854 *   display:block!important;
16855 * }
16856 *
16857 * .my-element.ng-hide-add { ... }
16858 * .my-element.ng-hide-add.ng-hide-add-active { ... }
16859 * .my-element.ng-hide-remove { ... }
16860 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
16861 * </pre>
16862 *
16863 * @animations
16864 * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
16865 * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
16866 *
16867 * @element ANY
16868 * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
16869 *     the element is shown or hidden respectively.
16870 *
16871 * @example
16872  <example animations="true">
16873    <file name="index.html">
16874      Click me: <input type="checkbox" ng-model="checked"><br/>
16875      <div>
16876        Show:
16877        <div class="check-element animate-hide" ng-show="checked">
16878          <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
16879        </div>
16880      </div>
16881      <div>
16882        Hide:
16883        <div class="check-element animate-hide" ng-hide="checked">
16884          <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
16885        </div>
16886      </div>
16887    </file>
16888    <file name="animations.css">
16889      .animate-hide.ng-hide-add, 
16890      .animate-hide.ng-hide-remove {
16891        -webkit-transition:all linear 0.5s;
16892        -moz-transition:all linear 0.5s;
16893        -o-transition:all linear 0.5s;
16894        transition:all linear 0.5s;
16895        display:block!important;
16896      }
16897
16898      .animate-hide.ng-hide-add.ng-hide-add-active,
16899      .animate-hide.ng-hide-remove {
16900        line-height:0;
16901        opacity:0;
16902        padding:0 10px;
16903      }
16904
16905      .animate-hide.ng-hide-add,
16906      .animate-hide.ng-hide-remove.ng-hide-remove-active {
16907        line-height:20px;
16908        opacity:1;
16909        padding:10px;
16910        border:1px solid black;
16911        background:white;
16912      }
16913
16914      .check-element {
16915        padding:10px;
16916        border:1px solid black;
16917        background:white;
16918      }
16919    </file>
16920    <file name="scenario.js">
16921       it('should check ng-show / ng-hide', function() {
16922         expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
16923         expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
16924
16925         input('checked').check();
16926
16927         expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
16928         expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
16929       });
16930    </file>
16931  </example>
16932 */
16933var ngHideDirective = ['$animate', function($animate) {
16934  return function(scope, element, attr) {
16935    scope.$watch(attr.ngHide, function ngHideWatchAction(value){
16936      $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
16937    });
16938  };
16939}];
16940
16941/**
16942 * @ngdoc directive
16943 * @name ng.directive:ngStyle
16944 *
16945 * @description
16946 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
16947 *
16948 * @element ANY
16949 * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
16950 *      object whose keys are CSS style names and values are corresponding values for those CSS
16951 *      keys.
16952 *
16953 * @example
16954   <example>
16955     <file name="index.html">
16956        <input type="button" value="set" ng-click="myStyle={color:'red'}">
16957        <input type="button" value="clear" ng-click="myStyle={}">
16958        <br/>
16959        <span ng-style="myStyle">Sample Text</span>
16960        <pre>myStyle={{myStyle}}</pre>
16961     </file>
16962     <file name="style.css">
16963       span {
16964         color: black;
16965       }
16966     </file>
16967     <file name="scenario.js">
16968       it('should check ng-style', function() {
16969         expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
16970         element('.doc-example-live :button[value=set]').click();
16971         expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
16972         element('.doc-example-live :button[value=clear]').click();
16973         expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
16974       });
16975     </file>
16976   </example>
16977 */
16978var ngStyleDirective = ngDirective(function(scope, element, attr) {
16979  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
16980    if (oldStyles && (newStyles !== oldStyles)) {
16981      forEach(oldStyles, function(val, style) { element.css(style, '');});
16982    }
16983    if (newStyles) element.css(newStyles);
16984  }, true);
16985});
16986
16987/**
16988 * @ngdoc directive
16989 * @name ng.directive:ngSwitch
16990 * @restrict EA
16991 *
16992 * @description
16993 * The ngSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
16994 * Elements within ngSwitch but without ngSwitchWhen or ngSwitchDefault directives will be preserved at the location
16995 * as specified in the template.
16996 *
16997 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
16998 * from the template cache), ngSwitch simply choses one of the nested elements and makes it visible based on which element
16999 * matches the value obtained from the evaluated expression. In other words, you define a container element
17000 * (where you place the directive), place an expression on the **on="..." attribute**
17001 * (or the **ng-switch="..." attribute**), define any inner elements inside of the directive and place
17002 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
17003 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
17004 * attribute is displayed.
17005 *
17006 * @animations
17007 * enter - happens after the ngSwtich contents change and the matched child element is placed inside the container
17008 * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
17009 *
17010 * @usage
17011 * <ANY ng-switch="expression">
17012 *   <ANY ng-switch-when="matchValue1">...</ANY>
17013 *   <ANY ng-switch-when="matchValue2">...</ANY>
17014 *   <ANY ng-switch-default>...</ANY>
17015 * </ANY>
17016 *
17017 * @scope
17018 * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
17019 * @paramDescription
17020 * On child elements add:
17021 *
17022 * * `ngSwitchWhen`: the case statement to match against. If match then this
17023 *   case will be displayed. If the same match appears multiple times, all the
17024 *   elements will be displayed.
17025 * * `ngSwitchDefault`: the default case when no other case match. If there
17026 *   are multiple default cases, all of them will be displayed when no other
17027 *   case match.
17028 *
17029 *
17030 * @example
17031  <example animations="true">
17032    <file name="index.html">
17033      <div ng-controller="Ctrl">
17034        <select ng-model="selection" ng-options="item for item in items">
17035        </select>
17036        <tt>selection={{selection}}</tt>
17037        <hr/>
17038        <div class="animate-switch-container"
17039          ng-switch on="selection">
17040            <div ng-switch-when="settings">Settings Div</div>
17041            <div ng-switch-when="home">Home Span</div>
17042            <div ng-switch-default>default</div>
17043        </div>
17044      </div>
17045    </file>
17046    <file name="script.js">
17047      function Ctrl($scope) {
17048        $scope.items = ['settings', 'home', 'other'];
17049        $scope.selection = $scope.items[0];
17050      }
17051    </file>
17052    <file name="animations.css">
17053      .animate-switch-container {
17054        position:relative;
17055        background:white;
17056        border:1px solid black;
17057        height:40px;
17058        overflow:hidden;
17059      }
17060
17061      .animate-switch-container > div {
17062        padding:10px;
17063      }
17064
17065      .animate-switch-container > .ng-enter,
17066      .animate-switch-container > .ng-leave {
17067        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17068        -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17069        -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17070        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
17071
17072        position:absolute;
17073        top:0;
17074        left:0;
17075        right:0;
17076        bottom:0;
17077      }
17078
17079      .animate-switch-container > .ng-enter {
17080        top:-50px;
17081      }
17082      .animate-switch-container > .ng-enter.ng-enter-active {
17083        top:0;
17084      }
17085
17086      .animate-switch-container > .ng-leave {
17087        top:0;
17088      }
17089      .animate-switch-container > .ng-leave.ng-leave-active {
17090        top:50px;
17091      }
17092    </file>
17093    <file name="scenario.js">
17094      it('should start in settings', function() {
17095        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
17096      });
17097      it('should change to home', function() {
17098        select('selection').option('home');
17099        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
17100      });
17101      it('should select default', function() {
17102        select('selection').option('other');
17103        expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
17104      });
17105    </file>
17106  </example>
17107 */
17108var ngSwitchDirective = ['$animate', function($animate) {
17109  return {
17110    restrict: 'EA',
17111    require: 'ngSwitch',
17112
17113    // asks for $scope to fool the BC controller module
17114    controller: ['$scope', function ngSwitchController() {
17115     this.cases = {};
17116    }],
17117    link: function(scope, element, attr, ngSwitchController) {
17118      var watchExpr = attr.ngSwitch || attr.on,
17119          selectedTranscludes,
17120          selectedElements,
17121          selectedScopes = [];
17122
17123      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
17124        for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
17125          selectedScopes[i].$destroy();
17126          $animate.leave(selectedElements[i]);
17127        }
17128
17129        selectedElements = [];
17130        selectedScopes = [];
17131
17132        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
17133          scope.$eval(attr.change);
17134          forEach(selectedTranscludes, function(selectedTransclude) {
17135            var selectedScope = scope.$new();
17136            selectedScopes.push(selectedScope);
17137            selectedTransclude.transclude(selectedScope, function(caseElement) {
17138              var anchor = selectedTransclude.element;
17139
17140              selectedElements.push(caseElement);
17141              $animate.enter(caseElement, anchor.parent(), anchor);
17142            });
17143          });
17144        }
17145      });
17146    }
17147  }
17148}];
17149
17150var ngSwitchWhenDirective = ngDirective({
17151  transclude: 'element',
17152  priority: 500,
17153  require: '^ngSwitch',
17154  compile: function(element, attrs, transclude) {
17155    return function(scope, element, attr, ctrl) {
17156      ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
17157      ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
17158    };
17159  }
17160});
17161
17162var ngSwitchDefaultDirective = ngDirective({
17163  transclude: 'element',
17164  priority: 500,
17165  require: '^ngSwitch',
17166  compile: function(element, attrs, transclude) {
17167    return function(scope, element, attr, ctrl) {
17168      ctrl.cases['?'] = (ctrl.cases['?'] || []);
17169      ctrl.cases['?'].push({ transclude: transclude, element: element });
17170    };
17171  }
17172});
17173
17174/**
17175 * @ngdoc directive
17176 * @name ng.directive:ngTransclude
17177 *
17178 * @description
17179 * Insert the transcluded DOM here.
17180 *
17181 * @element ANY
17182 *
17183 * @example
17184   <doc:example module="transclude">
17185     <doc:source>
17186       <script>
17187         function Ctrl($scope) {
17188           $scope.title = 'Lorem Ipsum';
17189           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
17190         }
17191
17192         angular.module('transclude', [])
17193          .directive('pane', function(){
17194             return {
17195               restrict: 'E',
17196               transclude: true,
17197               scope: { title:'@' },
17198               template: '<div style="border: 1px solid black;">' +
17199                           '<div style="background-color: gray">{{title}}</div>' +
17200                           '<div ng-transclude></div>' +
17201                         '</div>'
17202             };
17203         });
17204       </script>
17205       <div ng-controller="Ctrl">
17206         <input ng-model="title"><br>
17207         <textarea ng-model="text"></textarea> <br/>
17208         <pane title="{{title}}">{{text}}</pane>
17209       </div>
17210     </doc:source>
17211     <doc:scenario>
17212        it('should have transcluded', function() {
17213          input('title').enter('TITLE');
17214          input('text').enter('TEXT');
17215          expect(binding('title')).toEqual('TITLE');
17216          expect(binding('text')).toEqual('TEXT');
17217        });
17218     </doc:scenario>
17219   </doc:example>
17220 *
17221 */
17222var ngTranscludeDirective = ngDirective({
17223  controller: ['$transclude', '$element', '$scope', function($transclude, $element, $scope) {
17224    // use evalAsync so that we don't process transclusion before directives on the parent element even when the
17225    // transclusion replaces the current element. (we can't use priority here because that applies only to compile fns
17226    // and not controllers
17227    $scope.$evalAsync(function() {
17228      $transclude(function(clone) {
17229        $element.append(clone);
17230      });
17231    });
17232  }]
17233});
17234
17235/**
17236 * @ngdoc directive
17237 * @name ng.directive:script
17238 *
17239 * @description
17240 * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
17241 * template can be used by `ngInclude`, `ngView` or directive templates.
17242 *
17243 * @restrict E
17244 * @param {'text/ng-template'} type must be set to `'text/ng-template'`
17245 *
17246 * @example
17247  <doc:example>
17248    <doc:source>
17249      <script type="text/ng-template" id="/tpl.html">
17250        Content of the template.
17251      </script>
17252
17253      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
17254      <div id="tpl-content" ng-include src="currentTpl"></div>
17255    </doc:source>
17256    <doc:scenario>
17257      it('should load template defined inside script tag', function() {
17258        element('#tpl-link').click();
17259        expect(element('#tpl-content').text()).toMatch(/Content of the template/);
17260      });
17261    </doc:scenario>
17262  </doc:example>
17263 */
17264var scriptDirective = ['$templateCache', function($templateCache) {
17265  return {
17266    restrict: 'E',
17267    terminal: true,
17268    compile: function(element, attr) {
17269      if (attr.type == 'text/ng-template') {
17270        var templateUrl = attr.id,
17271            // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
17272            text = element[0].text;
17273
17274        $templateCache.put(templateUrl, text);
17275      }
17276    }
17277  };
17278}];
17279
17280/**
17281 * @ngdoc directive
17282 * @name ng.directive:select
17283 * @restrict E
17284 *
17285 * @description
17286 * HTML `SELECT` element with angular data-binding.
17287 *
17288 * # `ngOptions`
17289 *
17290 * Optionally `ngOptions` attribute can be used to dynamically generate a list of `<option>`
17291 * elements for a `<select>` element using an array or an object obtained by evaluating the
17292 * `ngOptions` expression.
17293 *
17294 * When an item in the `<select>` menu is selected, the value of array element or object property
17295 * represented by the selected option will be bound to the model identified by the `ngModel`
17296 * directive of the parent select element.
17297 *
17298 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
17299 * be nested into the `<select>` element. This element will then represent `null` or "not selected"
17300 * option. See example below for demonstration.
17301 *
17302 * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
17303 * of {@link ng.directive:ngRepeat ngRepeat} when you want the
17304 * `select` model to be bound to a non-string value. This is because an option element can currently
17305 * be bound to string values only.
17306 *
17307 * @param {string} ngModel Assignable angular expression to data-bind to.
17308 * @param {string=} name Property name of the form under which the control is published.
17309 * @param {string=} required The control is considered valid only if value is entered.
17310 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17311 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17312 *    `required` when you want to data-bind to the `required` attribute.
17313 * @param {comprehension_expression=} ngOptions in one of the following forms:
17314 *
17315 *   * for array data sources:
17316 *     * `label` **`for`** `value` **`in`** `array`
17317 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
17318 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
17319 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
17320 *   * for object data sources:
17321 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
17322 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
17323 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
17324 *     * `select` **`as`** `label` **`group by`** `group`
17325 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
17326 *
17327 * Where:
17328 *
17329 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
17330 *   * `value`: local variable which will refer to each item in the `array` or each property value
17331 *      of `object` during iteration.
17332 *   * `key`: local variable which will refer to a property name in `object` during iteration.
17333 *   * `label`: The result of this expression will be the label for `<option>` element. The
17334 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
17335 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
17336 *      element. If not specified, `select` expression will default to `value`.
17337 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
17338 *      DOM element.
17339 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
17340 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
17341 *     `value` variable (e.g. `value.propertyName`).
17342 *
17343 * @example
17344    <doc:example>
17345      <doc:source>
17346        <script>
17347        function MyCntrl($scope) {
17348          $scope.colors = [
17349            {name:'black', shade:'dark'},
17350            {name:'white', shade:'light'},
17351            {name:'red', shade:'dark'},
17352            {name:'blue', shade:'dark'},
17353            {name:'yellow', shade:'light'}
17354          ];
17355          $scope.color = $scope.colors[2]; // red
17356        }
17357        </script>
17358        <div ng-controller="MyCntrl">
17359          <ul>
17360            <li ng-repeat="color in colors">
17361              Name: <input ng-model="color.name">
17362              [<a href ng-click="colors.splice($index, 1)">X</a>]
17363            </li>
17364            <li>
17365              [<a href ng-click="colors.push({})">add</a>]
17366            </li>
17367          </ul>
17368          <hr/>
17369          Color (null not allowed):
17370          <select ng-model="color" ng-options="c.name for c in colors"></select><br>
17371
17372          Color (null allowed):
17373          <span  class="nullable">
17374            <select ng-model="color" ng-options="c.name for c in colors">
17375              <option value="">-- chose color --</option>
17376            </select>
17377          </span><br/>
17378
17379          Color grouped by shade:
17380          <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
17381          </select><br/>
17382
17383
17384          Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
17385          <hr/>
17386          Currently selected: {{ {selected_color:color}  }}
17387          <div style="border:solid 1px black; height:20px"
17388               ng-style="{'background-color':color.name}">
17389          </div>
17390        </div>
17391      </doc:source>
17392      <doc:scenario>
17393         it('should check ng-options', function() {
17394           expect(binding('{selected_color:color}')).toMatch('red');
17395           select('color').option('0');
17396           expect(binding('{selected_color:color}')).toMatch('black');
17397           using('.nullable').select('color').option('');
17398           expect(binding('{selected_color:color}')).toMatch('null');
17399         });
17400      </doc:scenario>
17401    </doc:example>
17402 */
17403
17404var ngOptionsDirective = valueFn({ terminal: true });
17405var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
17406                         //0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000007777000000000000000000088888
17407  var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*
17407)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
17408      nullModelCtrl = {$setViewValue: noop};
17409
17410  return {
17411    restrict: 'E',
17412    require: ['select', '?ngModel'],
17413    controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
17414      var self = this,
17415          optionsMap = {},
17416          ngModelCtrl = nullModelCtrl,
17417          nullOption,
17418          unknownOption;
17419
17420
17421      self.databound = $attrs.ngModel;
17422
17423
17424      self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
17425        ngModelCtrl = ngModelCtrl_;
17426        nullOption = nullOption_;
17427        unknownOption = unknownOption_;
17428      }
17429
17430
17431      self.addOption = function(value) {
17432        optionsMap[value] = true;
17433
17434        if (ngModelCtrl.$viewValue == value) {
17435          $element.val(value);
17436          if (unknownOption.parent()) unknownOption.remove();
17437        }
17438      };
17439
17440
17441      self.removeOption = function(value) {
17442        if (this.hasOption(value)) {
17443          delete optionsMap[value];
17444          if (ngModelCtrl.$viewValue == value) {
17445            this.renderUnknownOption(value);
17446          }
17447        }
17448      };
17449
17450
17451      self.renderUnknownOption = function(val) {
17452        var unknownVal = '? ' + hashKey(val) + ' ?';
17453        unknownOption.val(unknownVal);
17454        $element.prepend(unknownOption);
17455        $element.val(unknownVal);
17456        unknownOption.prop('selected', true); // needed for IE
17457      }
17458
17459
17460      self.hasOption = function(value) {
17461        return optionsMap.hasOwnProperty(value);
17462      }
17463
17464      $scope.$on('$destroy', function() {
17465        // disable unknown option so that we don't do work when the whole select is being destroyed
17466        self.renderUnknownOption = noop;
17467      });
17468    }],
17469
17470    link: function(scope, element, attr, ctrls) {
17471      // if ngModel is not defined, we don't need to do anything
17472      if (!ctrls[1]) return;
17473
17474      var selectCtrl = ctrls[0],
17475          ngModelCtrl = ctrls[1],
17476          multiple = attr.multiple,
17477          optionsExp = attr.ngOptions,
17478          nullOption = false, // if false, user will not be able to select it (used by ngOptions)
17479          emptyOption,
17480          // we can't just jqLite('<option>') since jqLite is not smart enough
17481          // to create it in <select> and IE barfs otherwise.
17482          optionTemplate = jqLite(document.createElement('option')),
17483          optGroupTemplate =jqLite(document.createElement('optgroup')),
17484          unknownOption = optionTemplate.clone();
17485
17486      // find "null" option
17487      for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
17488        if (children[i].value == '') {
17489          emptyOption = nullOption = children.eq(i);
17490          break;
17491        }
17492      }
17493
17494      selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
17495
17496      // required validator
17497      if (multiple && (attr.required || attr.ngRequired)) {
17498        var requiredValidator = function(value) {
17499          ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
17500          return value;
17501        };
17502
17503        ngModelCtrl.$parsers.push(requiredValidator);
17504        ngModelCtrl.$formatters.unshift(requiredValidator);
17505
17506        attr.$observe('required', function() {
17507          requiredValidator(ngModelCtrl.$viewValue);
17508        });
17509      }
17510
17511      if (optionsExp) Options(scope, element, ngModelCtrl);
17512      else if (multiple) Multiple(scope, element, ngModelCtrl);
17513      else Single(scope, element, ngModelCtrl, selectCtrl);
17514
17515
17516      ////////////////////////////
17517
17518
17519
17520      function Single(scope, selectElement, ngModelCtrl, selectCtrl) {
17521        ngModelCtrl.$render = function() {
17522          var viewValue = ngModelCtrl.$viewValue;
17523
17524          if (selectCtrl.hasOption(viewValue)) {
17525            if (unknownOption.parent()) unknownOption.remove();
17526            selectElement.val(viewValue);
17527            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
17528          } else {
17529            if (isUndefined(viewValue) && emptyOption) {
17530              selectElement.val('');
17531            } else {
17532              selectCtrl.renderUnknownOption(viewValue);
17533            }
17534          }
17535        };
17536
17537        selectElement.on('change', function() {
17538          scope.$apply(function() {
17539            if (unknownOption.parent()) unknownOption.remove();
17540            ngModelCtrl.$setViewValue(selectElement.val());
17541          });
17542        });
17543      }
17544
17545      function Multiple(scope, selectElement, ctrl) {
17546        var lastView;
17547        ctrl.$render = function() {
17548          var items = new HashMap(ctrl.$viewValue);
17549          forEach(selectElement.find('option'), function(option) {
17550            option.selected = isDefined(items.get(option.value));
17551          });
17552        };
17553
17554        // we have to do it on each watch since ngModel watches reference, but
17555        // we need to work of an array, so we need to see if anything was inserted/removed
17556        scope.$watch(function selectMultipleWatch() {
17557          if (!equals(lastView, ctrl.$viewValue)) {
17558            lastView = copy(ctrl.$viewValue);
17559            ctrl.$render();
17560          }
17561        });
17562
17563        selectElement.on('change', function() {
17564          scope.$apply(function() {
17565            var array = [];
17566            forEach(selectElement.find('option'), function(option) {
17567              if (option.selected) {
17568                array.push(option.value);
17569              }
17570            });
17571            ctrl.$setViewValue(array);
17572          });
17573        });
17574      }
17575
17576      function Options(scope, selectElement, ctrl) {
17577        var match;
17578
17579        if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
17580          throw minErr('ngOptions')('iexp',
17581            "Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}",
17582            optionsExp, startingTag(selectElement));
17583        }
17584
17585        var displayFn = $parse(match[2] || match[1]),
17586            valueName = match[4] || match[6],
17587            keyName = match[5],
17588            groupByFn = $parse(match[3] || ''),
17589            valueFn = $parse(match[2] ? match[1] : valueName),
17590            valuesFn = $parse(match[7]),
17591            track = match[8],
17592            trackFn = track ? $parse(match[8]) : null,
17593            // This is an array of array of existing option groups in DOM. We try to reuse these if possible
17594            // optionGroupsCache[0] is the options with no option group
17595            // optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
17596            optionGroupsCache = [[{element: selectElement, label:''}]];
17597
17598        if (nullOption) {
17599          // compile the element since there might be bindings in it
17600          $compile(nullOption)(scope);
17601
17602          // remove the class, which is added automatically because we recompile the element and it
17603          // becomes the compilation root
17604          nullOption.removeClass('ng-scope');
17605
17606          // we need to remove it before calling selectElement.html('') because otherwise IE will
17607          // remove the label from the element. wtf?
17608          nullOption.remove();
17609        }
17610
17611        // clear contents, we'll add what's needed based on the model
17612        selectElement.html('');
17613
17614        selectElement.on('change', function() {
17615          scope.$apply(function() {
17616            var optionGroup,
17617                collection = valuesFn(scope) || [],
17618                locals = {},
17619                key, value, optionElement, index, groupIndex, length, groupLength;
17620
17621            if (multiple) {
17622              value = [];
17623              for (groupIndex = 0, groupLength = optionGroupsCache.length;
17624                   groupIndex < groupLength;
17625                   groupIndex++) {
17626                // list of options for that group. (first item has the parent)
17627                optionGroup = optionGroupsCache[groupIndex];
17628
17629                for(index = 1, length = optionGroup.length; index < length; index++) {
17630                  if ((optionElement = optionGroup[index].element)[0].selected) {
17631                    key = optionElement.val();
17632                    if (keyName) locals[keyName] = key;
17633                    if (trackFn) {
17634                      for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
17635                        locals[valueName] = collection[trackIndex];
17636                        if (trackFn(scope, locals) == key) break;
17637                      }
17638                    } else {
17639                      locals[valueName] = collection[key];
17640                    }
17641                    value.push(valueFn(scope, locals));
17642                  }
17643                }
17644              }
17645            } else {
17646              key = selectElement.val();
17647              if (key == '?') {
17648                value = undefined;
17649              } else if (key == ''){
17650                value = null;
17651              } else {
17652                if (trackFn) {
17653                  for (var trackIndex = 0; trackIndex < collection.length; trackIndex++) {
17654                    locals[valueName] = collection[trackIndex];
17655                    if (trackFn(scope, locals) == key) {
17656                      value = valueFn(scope, locals);
17657                      break;
17658                    }
17659                  }
17660                } else {
17661                  locals[valueName] = collection[key];
17662                  if (keyName) locals[keyName] = key;
17663                  value = valueFn(scope, locals);
17664                }
17665              }
17666            }
17667            ctrl.$setViewValue(value);
17668          });
17669        });
17670
17671        ctrl.$render = render;
17672
17673        // TODO(vojta): can't we optimize this ?
17674        scope.$watch(render);
17675
17676        function render() {
17677          var optionGroups = {'':[]}, // Temporary location for the option groups before we render them
17678              optionGroupNames = [''],
17679              optionGroupName,
17680              optionGroup,
17681              option,
17682              existingParent, existingOptions, existingOption,
17683              modelValue = ctrl.$modelValue,
17684              values = valuesFn(scope) || [],
17685              keys = keyName ? sortedKeys(values) : values,
17686              groupLength, length,
17687              groupIndex, index,
17688              locals = {},
17689              selected,
17690              selectedSet = false, // nothing is selected yet
17691              lastElement,
17692              element,
17693              label;
17694
17695          if (multiple) {
17696            if (trackFn && isArray(modelValue)) {
17697              selectedSet = new HashMap([]);
17698              for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
17699                locals[valueName] = modelValue[trackIndex];
17700                selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
17701              }
17702            } else {
17703              selectedSet = new HashMap(modelValue);
17704            }
17705          }
17706
17707          // We now build up the list of options we need (we merge later)
17708          for (index = 0; length = keys.length, index < length; index++) {
17709               locals[valueName] = values[keyName ? locals[keyName]=keys[index]:index];
17710               optionGroupName = groupByFn(scope, locals) || '';
17711            if (!(optionGroup = optionGroups[optionGroupName])) {
17712              optionGroup = optionGroups[optionGroupName] = [];
17713              optionGroupNames.push(optionGroupName);
17714            }
17715            if (multiple) {
17716              selected = selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) != undefined;
17717            } else {
17718              if (trackFn) {
17719                var modelCast = {};
17720                modelCast[valueName] = modelValue;
17721                selected = trackFn(scope, modelCast) === trackFn(scope, locals);
17722              } else {
17723                selected = modelValue === valueFn(scope, locals);
17724              }
17725              selectedSet = selectedSet || selected; // see if at least one item is selected
17726            }
17727            label = displayFn(scope, locals); // what will be seen by the user
17728            label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
17729            optionGroup.push({
17730              id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),   // either the index into array or key from object
17731              label: label,
17732              selected: selected                   // determine if we should be selected
17733            });
17734          }
17735          if (!multiple) {
17736            if (nullOption || modelValue === null) {
17737              // insert null option if we have a placeholder, or the model is null
17738              optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
17739            } else if (!selectedSet) {
17740              // option could not be found, we have to insert the undefined item
17741              optionGroups[''].unshift({id:'?', label:'', selected:true});
17742            }
17743          }
17744
17745          // Now we need to update the list of DOM nodes to match the optionGroups we computed above
17746          for (groupIndex = 0, groupLength = optionGroupNames.length;
17747               groupIndex < groupLength;
17748               groupIndex++) {
17749            // current option group name or '' if no group
17750            optionGroupName = optionGroupNames[groupIndex];
17751
17752            // list of options for that group. (first item has the parent)
17753            optionGroup = optionGroups[optionGroupName];
17754
17755            if (optionGroupsCache.length <= groupIndex) {
17756              // we need to grow the optionGroups
17757              existingParent = {
17758                element: optGroupTemplate.clone().attr('label', optionGroupName),
17759                label: optionGroup.label
17760              };
17761              existingOptions = [existingParent];
17762              optionGroupsCache.push(existingOptions);
17763              selectElement.append(existingParent.element);
17764            } else {
17765              existingOptions = optionGroupsCache[groupIndex];
17766              existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
17767
17768              // update the OPTGROUP label if not the same.
17769              if (existingParent.label != optionGroupName) {
17770                existingParent.element.attr('label', existingParent.label = optionGroupName);
17771              }
17772            }
17773
17774            lastElement = null;  // start at the beginning
17775            for(index = 0, length = optionGroup.length; index < length; index++) {
17776              option = optionGroup[index];
17777              if ((existingOption = existingOptions[index+1])) {
17778                // reuse elements
17779                lastElement = existingOption.element;
17780                if (existingOption.label !== option.label) {
17781                  lastElement.text(existingOption.label = option.label);
17782                }
17783                if (existingOption.id !== option.id) {
17784                  lastElement.val(existingOption.id = option.id);
17785                }
17786                // lastElement.prop('selected') provided by jQuery has side-effects
17787                if (lastElement[0].selected !== option.selected) {
17788                  lastElement.prop('selected', (existingOption.selected = option.selected));
17789                }
17790              } else {
17791                // grow elements
17792
17793                // if it's a null option
17794                if (option.id === '' && nullOption) {
17795                  // put back the pre-compiled element
17796                  element = nullOption;
17797                } else {
17798                  // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
17799                  // in this version of jQuery on some browser the .text() returns a string
17800                  // rather then the element.
17801                  (element = optionTemplate.clone())
17802                      .val(option.id)
17803                      .attr('selected', option.selected)
17804                      .text(option.label);
17805                }
17806
17807                existingOptions.push(existingOption = {
17808                    element: element,
17809                    label: option.label,
17810                    id: option.id,
17811                    selected: option.selected
17812                });
17813                if (lastElement) {
17814                  lastElement.after(element);
17815                } else {
17816                  existingParent.element.append(element);
17817                }
17818                lastElement = element;
17819              }
17820            }
17821            // remove any excessive OPTIONs in a group
17822            index++; // increment since the existingOptions[0] is parent element not OPTION
17823            while(existingOptions.length > index) {
17824              existingOptions.pop().element.remove();
17825            }
17826          }
17827          // remove any excessive OPTGROUPs from select
17828          while(optionGroupsCache.length > groupIndex) {
17829            optionGroupsCache.pop()[0].element.remove();
17830          }
17831        }
17832      }
17833    }
17834  }
17835}];
17836
17837var optionDirective = ['$interpolate', function($interpolate) {
17838  var nullSelectCtrl = {
17839    addOption: noop,
17840    removeOption: noop
17841  };
17842
17843  return {
17844    restrict: 'E',
17845    priority: 100,
17846    compile: function(element, attr) {
17847      if (isUndefined(attr.value)) {
17848        var interpolateFn = $interpolate(element.text(), true);
17849        if (!interpolateFn) {
17850          attr.$set('value', element.text());
17851        }
17852      }
17853
17854      return function (scope, element, attr) {
17855        var selectCtrlName = '$selectController',
17856            parent = element.parent(),
17857            selectCtrl = parent.data(selectCtrlName) ||
17858              parent.parent().data(selectCtrlName); // in case we are in optgroup
17859
17860        if (selectCtrl && selectCtrl.databound) {
17861          // For some reason Opera defaults to true and if not overridden this messes up the repeater.
17862          // We don't want the view to drive the initialization of the model anyway.
17863          element.prop('selected', false);
17864        } else {
17865          selectCtrl = nullSelectCtrl;
17866        }
17867
17868        if (interpolateFn) {
17869          scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
17870            attr.$set('value', newVal);
17871            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
17872            selectCtrl.addOption(newVal);
17873          });
17874        } else {
17875          selectCtrl.addOption(attr.value);
17876        }
17877
17878        element.on('$destroy', function() {
17879          selectCtrl.removeOption(attr.value);
17880        });
17881      };
17882    }
17883  }
17884}];
17885
17886var styleDirective = valueFn({
17887  restrict: 'E',
17888  terminal: true
17889});
17890
17891  //try to bind to jquery now so that one can write angular.element().read()
17892  //but we will rebind on bootstrap again.
17893  bindJQuery();
17894
17895  publishExternalAPI(angular);
17896
17897  jqLite(document).ready(function() {
17898    angularInit(document, bootstrap);
17899  });
17900
17901})(window, document);
17902angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}</style>');

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