PageSourceSearch

https://naec.ge/resources/jscript/angular/angular.js

js naec.ge collected 2026-10-02 04:31:52 UTC 904,081 bytes, 21,607 lines download raw bytes

1/**
2 * @license AngularJS v1.2.16
3 * (c) 2010-2014 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function (window, document, undefined) {
7    'use strict';
8
9    /**
10     * @description
11     *
12     * This object provides a utility for producing rich Error messages within
13     * Angular. It can be called as follows:
14     *
15     * var exampleMinErr = minErr('example');
16     * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
17     *
18     * The above creates an instance of minErr in the example namespace. The
19     * resulting error will have a namespaced error code of example.one.  The
20     * resulting error will replace {0} with the value of foo, and {1} with the
21     * value of bar. The object is not restricted in the number of arguments it can
22     * take.
23     *
24     * If fewer arguments are specified than necessary for interpolation, the extra
25     * interpolation markers will be preserved in the final string.
26     *
27     * Since data will be parsed statically during a build step, some restrictions
28     * are applied with respect to how minErr instances are created and called.
29     * Instances should have names of the form namespaceMinErr for a minErr created
30     * using minErr('namespace') . Error codes, namespaces and template strings
31     * should all be static strings, not variables or general expressions.
32     *
33     * @param {string} module The namespace to use for the new minErr instance.
34     * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
35     */
36
37    function minErr(module) {
38        return function () {
39            var code = arguments[0],
40                prefix = '[' + (module ? module + ':' : '') + code + '] ',
41                template = arguments[1],
42                templateArgs = arguments,
43                stringify = function (obj) {
44                    if (typeof obj === 'function') {
45                        return obj.toString().replace(/ \{[\s\S]*$/, '');
46                    } else if (typeof obj === 'undefined') {
47                        return 'undefined';
48                    } else if (typeof obj !== 'string') {
49                        return JSON.stringify(obj);
50                    }
51                    return obj;
52                },
53                message, i;
54
55            message = prefix + template.replace(/\{\d+\}/g, function (match) {
56                var index = +match.slice(1, -1), arg;
57
58                if (index + 2 < templateArgs.length) {
59                    arg = templateArgs[index + 2];
60                    if (typeof arg === 'function') {
61                        return arg.toString().replace(/ ?\{[\s\S]*$/, '');
62                    } else if (typeof arg === 'undefined') {
63                        return 'undefined';
64                    } else if (typeof arg !== 'string') {
65                        return toJson(arg);
66                    }
67                    return arg;
68                }
69                return match;
70            });
71
72            message = message + '\nhttp://errors.angularjs.org/1.2.16/' +
73                (module ? module + '/' : '') + code;
74            for (i = 2; i < arguments.length; i++) {
75                message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
76                    encodeURIComponent(stringify(arguments[i]));
77            }
78
79            return new Error(message);
80        };
81    }
82
83    /* We need to tell jshint what variables are being exported */
84    /* global
85     -angular,
86     -msie,
87     -jqLite,
88     -jQuery,
89     -slice,
90     -push,
91     -toString,
92     -ngMinErr,
93     -_angular,
94     -angularModule,
95     -nodeName_,
96     -uid,
97
98     -lowercase,
99     -uppercase,
100     -manualLowercase,
101     -manualUppercase,
102     -nodeName_,
103     -isArrayLike,
104     -forEach,
105     -sortedKeys,
106     -forEachSorted,
107     -reverseParams,
108     -nextUid,
109     -setHashKey,
110     -extend,
111     -int,
112     -inherit,
113     -noop,
114     -identity,
115     -valueFn,
116     -isUndefined,
117     -isDefined,
118     -isObject,
119     -isString,
120     -isNumber,
121     -isDate,
122     -isArray,
123     -isFunction,
124     -isRegExp,
125     -isWindow,
126     -isScope,
127     -isFile,
128     -isBlob,
129     -isBoolean,
130     -trim,
131     -isElement,
132     -makeMap,
133     -map,
134     -size,
135     -includes,
136     -indexOf,
137     -arrayRemove,
138     -isLeafNode,
139     -copy,
140     -shallowCopy,
141     -equals,
142     -csp,
143     -concat,
144     -sliceArgs,
145     -bind,
146     -toJsonReplacer,
147     -toJson,
148     -fromJson,
149     -toBoolean,
150     -startingTag,
151     -tryDecodeURIComponent,
152     -parseKeyValue,
153     -toKeyValue,
154     -encodeUriSegment,
155     -encodeUriQuery,
156     -angularInit,
157     -bootstrap,
158     -snake_case,
159     -bindJQuery,
160     -assertArg,
161     -assertArgFn,
162     -assertNotHasOwnProperty,
163     -getter,
164     -getBlockElements,
165     -hasOwnProperty,
166
167     */
168
169////////////////////////////////////
170
171    /**
172     * @ngdoc module
173     * @name ng
174     * @module ng
175     * @description
176     *
177     * # ng (core module)
178     * The ng module is loaded by default when an AngularJS application is started. The module itself
179     * contains the essential components for an AngularJS application to function. The table below
180     * lists a high level breakdown of each of the services/factories, filters, directives and testing
181     * components available within this core module.
182     *
183     * <div doc-module-components="ng"></div>
184     */
185
186    /**
187     * @ngdoc function
188     * @name angular.lowercase
189     * @module ng
190     * @function
191     *
192     * @description Converts the specified string to lowercase.
193     * @param {string} string String to be converted to lowercase.
194     * @returns {string} Lowercased string.
195     */
196    var lowercase = function (string) {
197        return isString(string) ? string.toLowerCase() : string;
198    };
199    var hasOwnProperty = Object.prototype.hasOwnProperty;
200
201    /**
202     * @ngdoc function
203     * @name angular.uppercase
204     * @module ng
205     * @function
206     *
207     * @description Converts the specified string to uppercase.
208     * @param {string} string String to be converted to uppercase.
209     * @returns {string} Uppercased string.
210     */
211    var uppercase = function (string) {
212        return isString(string) ? string.toUpperCase() : string;
213    };
214
215
216    var manualLowercase = function (s) {
217        /* jshint bitwise: false */
218        return isString(s)
219            ? s.replace(/[A-Z]/g, function (ch) {
220            return String.fromCharCode(ch.charCodeAt(0) | 32);
221        })
222            : s;
223    };
224    var manualUppercase = function (s) {
225        /* jshint bitwise: false */
226        return isString(s)
227            ? s.replace(/[a-z]/g, function (ch) {
228            return String.fromCharCode(ch.charCodeAt(0) & ~32);
229        })
230            : s;
231    };
232
233
234// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
235// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
236// with correct but slower alternatives.
237    if ('i' !== 'I'.toLowerCase()) {
238        lowercase = manualLowercase;
239        uppercase = manualUppercase;
240    }
241
242
243    var /** holds major version number for IE or NaN for real browsers */
244            msie,
245        jqLite,           // delay binding since jQuery could be loaded after us.
246        jQuery,           // delay binding
247        slice = [].slice,
248        push = [].push,
249        toString = Object.prototype.toString,
250        ngMinErr = minErr('ng'),
251
252
253        _angular = window.angular,
254        /** @name angular */
255            angular = window.angular || (window.angular = {}),
256        angularModule,
257        nodeName_,
258        uid = ['0', '0', '0'];
259
260    /**
261     * IE 11 changed the format of the UserAgent string.
262     * See http://msdn.microsoft.com/en-us/library/ms537503.aspx
263     */
264    msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
265    if (isNaN(msie)) {
266        msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
267    }
268
269
270    /**
271     * @private
272     * @param {*} obj
273     * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
274     *                   String ...)
275     */
276    function isArrayLike(obj) {
277        if (obj == null || isWindow(obj)) {
278            return false;
279        }
280
281        var length = obj.length;
282
283        if (obj.nodeType === 1 && length) {
284            return true;
285        }
286
287        return isString(obj) || isArray(obj) || length === 0 ||
288            typeof length === 'number' && length > 0 && (length - 1) in obj;
289    }
290
291    /**
292     * @ngdoc function
293     * @name angular.forEach
294     * @module ng
295     * @function
296     *
297     * @description
298     * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
299     * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
300     * is the value of an object property or an array element and `key` is the object property key or
301     * array element index. Specifying a `context` for the function is optional.
302     *
303     * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
304     * using the `hasOwnProperty` method.
305     *
306     ```js
307     var values = {name: 'misko', gender: 'male'};
308     var log = [];
309     angular.forEach(values, function(value, key){
310       this.push(key + ': ' + value);
311     }, log);
312     expect(log).toEqual(['name: misko', 'gender: male']);
313     ```
314     *
315     * @param {Object|Array} obj Object to iterate over.
316     * @param {Function} iterator Iterator function.
317     * @param {Object=} context Object to become context (`this`) for the iterator function.
318     * @returns {Object|Array} Reference to `obj`.
319     */
320    function forEach(obj, iterator, context) {
321        var key;
322        if (obj) {
323            if (isFunction(obj)) {
324                for (key in obj) {
325                    // Need to check if hasOwnProperty exists,
326                    // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
327                    if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
328                        iterator.call(context, obj[key], key);
329                    }
330                }
331            } else if (obj.forEach && obj.forEach !== forEach) {
332                obj.forEach(iterator, context);
333            } else if (isArrayLike(obj)) {
334                for (key = 0; key < obj.length; key++)
335                    iterator.call(context, obj[key], key);
336            } else {
337                for (key in obj) {
338                    if (obj.hasOwnProperty(key)) {
339                        iterator.call(context, obj[key], key);
340                    }
341                }
342            }
343        }
344        return obj;
345    }
346
347    function sortedKeys(obj) {
348        var keys = [];
349        for (var key in obj) {
350            if (obj.hasOwnProperty(key)) {
351                keys.push(key);
352            }
353        }
354        return keys.sort();
355    }
356
357    function forEachSorted(obj, iterator, context) {
358        var keys = sortedKeys(obj);
359        for (var i = 0; i < keys.length; i++) {
360            iterator.call(context, obj[keys[i]], keys[i]);
361        }
362        return keys;
363    }
364
365
366    /**
367     * when using forEach the params are value, key, but it is often useful to have key, value.
368     * @param {function(string, *)} iteratorFn
369     * @returns {function(*, string)}
370     */
371    function reverseParams(iteratorFn) {
372        return function (value, key) {
373            iteratorFn(key, value);
374        };
375    }
376
377    /**
378     * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
379     * characters such as '012ABC'. The reason why we are not using simply a number counter is that
380     * the number string gets longer over time, and it can also overflow, where as the nextId
381     * will grow much slower, it is a string, and it will never overflow.
382     *
383     * @returns {string} an unique alpha-numeric string
384     */
385    function nextUid() {
386        var index = uid.length;
387        var digit;
388
389        while (index) {
390            index--;
391            digit = uid[index].charCodeAt(0);
392            if (digit == 57 /*'9'*/) {
393                uid[index] = 'A';
394                return uid.join('');
395            }
396            if (digit == 90  /*'Z'*/) {
397                uid[index] = '0';
398            } else {
399                uid[index] = String.fromCharCode(digit + 1);
400                return uid.join('');
401            }
402        }
403        uid.unshift('0');
404        return uid.join('');
405    }
406
407
408    /**
409     * Set or clear the hashkey for an object.
410     * @param obj object
411     * @param h the hashkey (!truthy to delete the hashkey)
412     */
413    function setHashKey(obj, h) {
414        if (h) {
415            obj.$$hashKey = h;
416        }
417        else {
418            delete obj.$$hashKey;
419        }
420    }
421
422    /**
423     * @ngdoc function
424     * @name angular.extend
425     * @module ng
426     * @function
427     *
428     * @description
429     * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
430     * to `dst`. You can specify multiple `src` objects.
431     *
432     * @param {Object} dst Destination object.
433     * @param {...Object} src Source object(s).
434     * @returns {Object} Reference to `dst`.
435     */
436    function extend(dst) {
437        var h = dst.$$hashKey;
438        forEach(arguments, function (obj) {
439            if (obj !== dst) {
440                forEach(obj, function (value, key) {
441                    dst[key] = value;
442                });
443            }
444        });
445
446        setHashKey(dst, h);
447        return dst;
448    }
449
450    function int(str) {
451        return parseInt(str, 10);
452    }
453
454
455    function inherit(parent, extra) {
456        return extend(new (extend(function () {
457        }, {prototype: parent}))(), extra);
458    }
459
460    /**
461     * @ngdoc function
462     * @name angular.noop
463     * @module ng
464     * @function
465     *
466     * @description
467     * A function that performs no operations. This function can be useful when writing code in the
468     * functional style.
469     ```js
470     function foo(callback) {
471       var result = calculateResult();
472       (callback || angular.noop)(result);
473     }
474     ```
475     */
476    function noop() {
477    }
478
479    noop.$inject = [];
480
481
482    /**
483     * @ngdoc function
484     * @name angular.identity
485     * @module ng
486     * @function
487     *
488     * @description
489     * A function that returns its first argument. This function is useful when writing code in the
490     * functional style.
491     *
492     ```js
493     function transformer(transformationFn, value) {
494       return (transformationFn || angular.identity)(value);
495     };
496     ```
497     */
498    function identity($) {
499        return $;
500    }
501
502    identity.$inject = [];
503
504
505    function valueFn(value) {
506        return function () {
507            return value;
508        };
509    }
510
511    /**
512     * @ngdoc function
513     * @name angular.isUndefined
514     * @module ng
515     * @function
516     *
517     * @description
518     * Determines if a reference is undefined.
519     *
520     * @param {*} value Reference to check.
521     * @returns {boolean} True if `value` is undefined.
522     */
523    function isUndefined(value) {
524        return typeof value === 'undefined';
525    }
526
527
528    /**
529     * @ngdoc function
530     * @name angular.isDefined
531     * @module ng
532     * @function
533     *
534     * @description
535     * Determines if a reference is defined.
536     *
537     * @param {*} value Reference to check.
538     * @returns {boolean} True if `value` is defined.
539     */
540    function isDefined(value) {
541        return typeof value !== 'undefined';
542    }
543
544
545    /**
546     * @ngdoc function
547     * @name angular.isObject
548     * @module ng
549     * @function
550     *
551     * @description
552     * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
553     * considered to be objects. Note that JavaScript arrays are objects.
554     *
555     * @param {*} value Reference to check.
556     * @returns {boolean} True if `value` is an `Object` but not `null`.
557     */
558    function isObject(value) {
559        return value != null && typeof value === 'object';
560    }
561
562
563    /**
564     * @ngdoc function
565     * @name angular.isString
566     * @module ng
567     * @function
568     *
569     * @description
570     * Determines if a reference is a `String`.
571     *
572     * @param {*} value Reference to check.
573     * @returns {boolean} True if `value` is a `String`.
574     */
575    function isString(value) {
576        return typeof value === 'string';
577    }
578
579
580    /**
581     * @ngdoc function
582     * @name angular.isNumber
583     * @module ng
584     * @function
585     *
586     * @description
587     * Determines if a reference is a `Number`.
588     *
589     * @param {*} value Reference to check.
590     * @returns {boolean} True if `value` is a `Number`.
591     */
592    function isNumber(value) {
593        return typeof value === 'number';
594    }
595
596
597    /**
598     * @ngdoc function
599     * @name angular.isDate
600     * @module ng
601     * @function
602     *
603     * @description
604     * Determines if a value is a date.
605     *
606     * @param {*} value Reference to check.
607     * @returns {boolean} True if `value` is a `Date`.
608     */
609    function isDate(value) {
610        return toString.call(value) === '[object Date]';
611    }
612
613
614    /**
615     * @ngdoc function
616     * @name angular.isArray
617     * @module ng
618     * @function
619     *
620     * @description
621     * Determines if a reference is an `Array`.
622     *
623     * @param {*} value Reference to check.
624     * @returns {boolean} True if `value` is an `Array`.
625     */
626    function isArray(value) {
627        return toString.call(value) === '[object Array]';
628    }
629
630
631    /**
632     * @ngdoc function
633     * @name angular.isFunction
634     * @module ng
635     * @function
636     *
637     * @description
638     * Determines if a reference is a `Function`.
639     *
640     * @param {*} value Reference to check.
641     * @returns {boolean} True if `value` is a `Function`.
642     */
643    function isFunction(value) {
644        return typeof value === 'function';
645    }
646
647
648    /**
649     * Determines if a value is a regular expression object.
650     *
651     * @private
652     * @param {*} value Reference to check.
653     * @returns {boolean} True if `value` is a `RegExp`.
654     */
655    function isRegExp(value) {
656        return toString.call(value) === '[object RegExp]';
657    }
658
659
660    /**
661     * Checks if `obj` is a window object.
662     *
663     * @private
664     * @param {*} obj Object to check
665     * @returns {boolean} True if `obj` is a window obj.
666     */
667    function isWindow(obj) {
668        return obj && obj.document && obj.location && obj.alert && obj.setInterval;
669    }
670
671
672    function isScope(obj) {
673        return obj && obj.$evalAsync && obj.$watch;
674    }
675
676
677    function isFile(obj) {
678        return toString.call(obj) === '[object File]';
679    }
680
681
682    function isBlob(obj) {
683        return toString.call(obj) === '[object Blob]';
684    }
685
686
687    function isBoolean(value) {
688        return typeof value === 'boolean';
689    }
690
691
692    var trim = (function () {
693        // native trim is way faster: http://jsperf.com/angular-trim-test
694        // but IE doesn't have it... :-(
695        // TODO: we should move this into IE/ES5 polyfill
696        if (!String.prototype.trim) {
697            return function (value) {
698                return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
699            };
700        }
701        return function (value) {
702            return isString(value) ? value.trim() : value;
703        };
704    })();
705
706
707    /**
708     * @ngdoc function
709     * @name angular.isElement
710     * @module ng
711     * @function
712     *
713     * @description
714     * Determines if a reference is a DOM element (or wrapped jQuery element).
715     *
716     * @param {*} value Reference to check.
717     * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
718     */
719    function isElement(node) {
720        return !!(node &&
721            (node.nodeName  // we are a direct element
722                || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
723    }
724
725    /**
726     * @param str 'key1,key2,...'
727     * @returns {object} in the form of {key1:true, key2:true, ...}
728     */
729    function makeMap(str) {
730        var obj = {}, items = str.split(","), i;
731        for (i = 0; i < items.length; i++)
732            obj[ items[i] ] = true;
733        return obj;
734    }
735
736
737    if (msie < 9) {
738        nodeName_ = function (element) {
739            element = element.nodeName ? element : element[0];
740            return (element.scopeName && element.scopeName != 'HTML')
741                ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
742        };
743    } else {
744        nodeName_ = function (element) {
745            return element.nodeName ? element.nodeName : element[0].nodeName;
746        };
747    }
748
749
750    function map(obj, iterator, context) {
751        var results = [];
752        forEach(obj, function (value, index, list) {
753            results.push(iterator.call(context, value, index, list));
754        });
755        return results;
756    }
757
758
759    /**
760     * @description
761     * Determines the number of elements in an array, the number of properties an object has, or
762     * the length of a string.
763     *
764     * Note: This function is used to augment the Object type in Angular expressions. See
765     * {@link angular.Object} for more information about Angular arrays.
766     *
767     * @param {Object|Array|string} obj Object, array, or string to inspect.
768     * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
769     * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
770     */
771    function size(obj, ownPropsOnly) {
772        var count = 0, key;
773
774        if (isArray(obj) || isString(obj)) {
775            return obj.length;
776        } else if (isObject(obj)) {
777            for (key in obj)
778                if (!ownPropsOnly || obj.hasOwnProperty(key))
779                    count++;
780        }
781
782        return count;
783    }
784
785
786    function includes(array, obj) {
787        return indexOf(array, obj) != -1;
788    }
789
790    function indexOf(array, obj) {
791        if (array.indexOf) return array.indexOf(obj);
792
793        for (var i = 0; i < array.length; i++) {
794            if (obj === array[i]) return i;
795        }
796        return -1;
797    }
798
799    function arrayRemove(array, value) {
800        var index = indexOf(array, value);
801        if (index >= 0)
802            array.splice(index, 1);
803        return value;
804    }
805
806    function isLeafNode(node) {
807        if (node) {
808            switch (node.nodeName) {
809                case "OPTION":
810                case "PRE":
811                case "TITLE":
812                    return true;
813            }
814        }
815        return false;
816    }
817
818    /**
819     * @ngdoc function
820     * @name angular.copy
821     * @module ng
822     * @function
823     *
824     * @description
825     * Creates a deep copy of `source`, which should be an object or an array.
826     *
827     * * If no destination is supplied, a copy of the object or array is created.
828     * * If a destination is provided, all of its elements (for array) or properties (for objects)
829     *   are deleted and then all elements/properties from the source are copied to it.
830     * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
831     * * If `source` is identical to 'destination' an exception will be thrown.
832     *
833     * @param {*} source The source that will be used to make a copy.
834     *                   Can be any type, including primitives, `null`, and `undefined`.
835     * @param {(Object|Array)=} destination Destination into which the source is copied. If
836     *     provided, must be of the same type as `source`.
837     * @returns {*} The copy or updated `destination`, if `destination` was specified.
838     *
839     * @example
840     <example>
841     <file name="index.jsp">
842     <div ng-controller="Controller">
843     <form novalidate class="simple-form">
844     Name: <input type="text" ng-model="user.name" /><br />
845     E-mail: <input type="email" ng-model="user.email" /><br />
846     Gender: <input type="radio" ng-model="user.gender" value="male" />male
847     <input type="radio" ng-model="user.gender" value="female" />female<br />
848     <button ng-click="reset()">RESET</button>
849     <button ng-click="update(user)">SAVE</button>
850     </form>
851     <pre>form = {{user | json}}</pre>
852     <pre>master = {{master | json}}</pre>
853     </div>
854
855     <script>
856     function Controller($scope) {
857    $scope.master= {};
858
859    $scope.update = function(user) {
860      // Example with 1 argument
861      $scope.master= angular.copy(user);
862    };
863
864    $scope.reset = function() {
865      // Example with 2 arguments
866      angular.copy($scope.master, $scope.user);
867    };
868
869    $scope.reset();
870  }
871     </script>
872     </file>
873     </example>
874     */
875    function copy(source, destination) {
876        if (isWindow(source) || isScope(source)) {
877            throw ngMinErr('cpws',
878                "Can't copy! Making copies of Window or Scope instances is not supported.");
879        }
880
881        if (!destination) {
882            destination = source;
883            if (source) {
884                if (isArray(source)) {
885                    destination = copy(source, []);
886                } else if (isDate(source)) {
887                    destination = new Date(source.getTime());
888                } else if (isRegExp(source)) {
889                    destination = new RegExp(source.source);
890                } else if (isObject(source)) {
891                    destination = copy(source, {});
892                }
893            }
894        } else {
895            if (source === destination) throw ngMinErr('cpi',
896                "Can't copy! Source and destination are identical.");
897            if (isArray(source)) {
898                destination.length = 0;
899                for (var i = 0; i < source.length; i++) {
900                    destination.push(copy(source[i]));
901                }
902            } else {
903                var h = destination.$$hashKey;
904                forEach(destination, function (value, key) {
905                    delete destination[key];
906                });
907                for (var key in source) {
908                    destination[key] = copy(source[key]);
909                }
910                setHashKey(destination, h);
911            }
912        }
913        return destination;
914    }
915
916    /**
917     * Create a shallow copy of an object
918     */
919    function shallowCopy(src, dst) {
920        dst = dst || {};
921
922        for (var key in src) {
923            // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
924            // so we don't need to worry about using our custom hasOwnProperty here
925            if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
926                dst[key] = src[key];
927            }
928        }
929
930        return dst;
931    }
932
933
934    /**
935     * @ngdoc function
936     * @name angular.equals
937     * @module ng
938     * @function
939     *
940     * @description
941     * Determines if two objects or two values are equivalent. Supports value types, regular
942     * expressions, arrays and objects.
943     *
944     * Two objects or values are considered equivalent if at least one of the following is true:
945     *
946     * * Both objects or values pass `===` comparison.
947     * * Both objects or values are of the same type and all of their properties are equal by
948     *   comparing them with `angular.equals`.
949     * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
950     * * Both values represent the same regular expression (In JavasScript,
951     *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
952     *   representation matches).
953     *
954     * During a property comparison, properties of `function` type and properties with names
955     * that begin with `$` are ignored.
956     *
957     * Scope and DOMWindow objects are being compared only by identify (`===`).
958     *
959     * @param {*} o1 Object or value to compare.
960     * @param {*} o2 Object or value to compare.
961     * @returns {boolean} True if arguments are equal.
962     */
963    function equals(o1, o2) {
964        if (o1 === o2) return true;
965        if (o1 === null || o2 === null) return false;
966        if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
967        var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
968        if (t1 == t2) {
969            if (t1 == 'object') {
970                if (isArray(o1)) {
971                    if (!isArray(o2)) return false;
972                    if ((length = o1.length) == o2.length) {
973                        for (key = 0; key < length; key++) {
974                            if (!equals(o1[key], o2[key])) return false;
975                        }
976                        return true;
977                    }
978                } else if (isDate(o1)) {
979                    return isDate(o2) && o1.getTime() == o2.getTime();
980                } else if (isRegExp(o1) && isRegExp(o2)) {
981                    return o1.toString() == o2.toString();
982                } else {
983                    if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
984                    keySet = {};
985                    for (key in o1) {
986                        if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
987                        if (!equals(o1[key], o2[key])) return false;
988                        keySet[key] = true;
989                    }
990                    for (key in o2) {
991                        if (!keySet.hasOwnProperty(key) &&
992                            key.charAt(0) !== '$' &&
993                            o2[key] !== undefined && !isFunction(o2[key])) return false;
994                    }
995                    return true;
996                }
997            }
998        }
999        return false;
1000    }
1001
1002
1003    function csp() {
1004        return (document.securityPolicy && document.securityPolicy.isActive) ||
1005            (document.querySelector && !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
1006    }
1007
1008
1009    function concat(array1, array2, index) {
1010        return array1.concat(slice.call(array2, index));
1011    }
1012
1013    function sliceArgs(args, startIndex) {
1014        return slice.call(args, startIndex || 0);
1015    }
1016
1017
1018    /* jshint -W101 */
1019    /**
1020     * @ngdoc function
1021     * @name angular.bind
1022     * @module ng
1023     * @function
1024     *
1025     * @description
1026     * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1027     * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1028     * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1029     * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1030     *
1031     * @param {Object} self Context which `fn` should be evaluated in.
1032     * @param {function()} fn Function to be bound.
1033     * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1034     * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1035     */
1036    /* jshint +W101 */
1037    function bind(self, fn) {
1038        var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1039        if (isFunction(fn) && !(fn instanceof RegExp)) {
1040            return curryArgs.length
1041                ? function () {
1042                return arguments.length
1043                    ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
1044                    : fn.apply(self, curryArgs);
1045            }
1046                : function () {
1047                return arguments.length
1048                    ? fn.apply(self, arguments)
1049                    : fn.call(self);
1050            };
1051        } else {
1052            // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
1053            return fn;
1054        }
1055    }
1056
1057
1058    function toJsonReplacer(key, value) {
1059        var val = value;
1060
1061        if (typeof key === 'string' && key.charAt(0) === '$') {
1062            val = undefined;
1063        } else if (isWindow(value)) {
1064            val = '$WINDOW';
1065        } else if (value && document === value) {
1066            val = '$DOCUMENT';
1067        } else if (isScope(value)) {
1068            val = '$SCOPE';
1069        }
1070
1071        return val;
1072    }
1073
1074
1075    /**
1076     * @ngdoc function
1077     * @name angular.toJson
1078     * @module ng
1079     * @function
1080     *
1081     * @description
1082     * Serializes input into a JSON-formatted string. Properties with leading $ characters will be
1083     * stripped since angular uses this notation internally.
1084     *
1085     * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1086     * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
1087     * @returns {string|undefined} JSON-ified string representing `obj`.
1088     */
1089    function toJson(obj, pretty) {
1090        if (typeof obj === 'undefined') return undefined;
1091        return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
1092    }
1093
1094
1095    /**
1096     * @ngdoc function
1097     * @name angular.fromJson
1098     * @module ng
1099     * @function
1100     *
1101     * @description
1102     * Deserializes a JSON string.
1103     *
1104     * @param {string} json JSON string to deserialize.
1105     * @returns {Object|Array|string|number} Deserialized thingy.
1106     */
1107    function fromJson(json) {
1108        return isString(json)
1109            ? JSON.parse(json)
1110            : json;
1111    }
1112
1113
1114    function toBoolean(value) {
1115        if (typeof value === 'function') {
1116            value = true;
1117        } else if (value && value.length !== 0) {
1118            var v = lowercase("" + value);
1119            value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1120        } else {
1121            value = false;
1122        }
1123        return value;
1124    }
1125
1126    /**
1127     * @returns {string} Returns the string representation of the element.
1128     */
1129    function startingTag(element) {
1130        element = jqLite(element).clone();
1131        try {
1132            // turns out IE does not let you set .html() on elements which
1133            // are not allowed to have children. So we just ignore it.
1134            element.empty();
1135        } catch (e) {
1136        }
1137        // As Per DOM Standards
1138        var TEXT_NODE = 3;
1139        var elemHtml = jqLite('<div>').append(element).html();
1140        try {
1141            return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
1142                elemHtml.
1143                    match(/^(<[^>]+>)/)[1].
1144                    replace(/^<([\w\-]+)/, function (match, nodeName) {
1145                        return '<' + lowercase(nodeName);
1146                    });
1147        } catch (e) {
1148            return lowercase(elemHtml);
1149        }
1150
1151    }
1152
1153
1154/////////////////////////////////////////////////
1155
1156    /**
1157     * Tries to decode the URI component without throwing an exception.
1158     *
1159     * @private
1160     * @param str value potential URI component to check.
1161     * @returns {boolean} True if `value` can be decoded
1162     * with the decodeURIComponent function.
1163     */
1164    function tryDecodeURIComponent(value) {
1165        try {
1166            return decodeURIComponent(value);
1167        } catch (e) {
vendor: 5,051 bytes, lines 1168-1289
1168            // Ignore any invalid uri component
1169        }
1170    }
1171
1172
1173    /**
1174     * Parses an escaped url query string into key-value pairs.
1175     * @returns {Object.<string,boolean|Array>}
1176     */
1177    function parseKeyValue(/**string*/keyValue) {
1178        var obj = {}, key_value, key;
1179        forEach((keyValue || "").split('&'), function (keyValue) {
1180            if (keyValue) {
1181                key_value = keyValue.split('=');
1182                key = tryDecodeURIComponent(key_value[0]);
1183                if (isDefined(key)) {
1184                    var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
1185                    if (!obj[key]) {
1186                        obj[key] = val;
1187                    } else if (isArray(obj[key])) {
1188                        obj[key].push(val);
1189                    } else {
1190                        obj[key] = [obj[key], val];
1191                    }
1192                }
1193            }
1194        });
1195        return obj;
1196    }
1197
1198    function toKeyValue(obj) {
1199        var parts = [];
1200        forEach(obj, function (value, key) {
1201            if (isArray(value)) {
1202                forEach(value, function (arrayValue) {
1203                    parts.push(encodeUriQuery(key, true) +
1204                        (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1205                });
1206            } else {
1207                parts.push(encodeUriQuery(key, true) +
1208                    (value === true ? '' : '=' + encodeUriQuery(value, true)));
1209            }
1210        });
1211        return parts.length ? parts.join('&') : '';
1212    }
1213
1214
1215    /**
1216     * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1217     * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1218     * segments:
1219     *    segment       = *pchar
1220     *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1221     *    pct-encoded   = "%" HEXDIG HEXDIG
1222     *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1223     *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1224     *                     / "*" / "+" / "," / ";" / "="
1225     */
1226    function encodeUriSegment(val) {
1227        return encodeUriQuery(val, true).
1228            replace(/%26/gi, '&').
1229            replace(/%3D/gi, '=').
1230            replace(/%2B/gi, '+');
1231    }
1232
1233
1234    /**
1235     * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1236     * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1237     * encoded per http://tools.ietf.org/html/rfc3986:
1238     *    query       = *( pchar / "/" / "?" )
1239     *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
1240     *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
1241     *    pct-encoded   = "%" HEXDIG HEXDIG
1242     *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
1243     *                     / "*" / "+" / "," / ";" / "="
1244     */
1245    function encodeUriQuery(val, pctEncodeSpaces) {
1246        return encodeURIComponent(val).
1247            replace(/%40/gi, '@').
1248            replace(/%3A/gi, ':').
1249            replace(/%24/g, '$').
1250            replace(/%2C/gi, ',').
1251            replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1252    }
1253
1254
1255    /**
1256     * @ngdoc directive
1257     * @name ngApp
1258     * @module ng
1259     *
1260     * @element ANY
1261     * @param {angular.Module} ngApp an optional application
1262     *   {@link angular.module module} name to load.
1263     *
1264     * @description
1265     *
1266     * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1267     * designates the **root element** of the application and is typically placed near the root element
1268     * of the page - e.g. on the `<body>` or `<html>` tags.
1269     *
1270     * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1271     * found in the document will be used to define the root element to auto-bootstrap as an
1272     * application. To run multiple applications in an HTML document you must manually bootstrap them using
1273     * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
1274     *
1275     * You can specify an **AngularJS module** to be used as the root module for the application.  This
1276     * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
1277     * should contain the application code needed or have dependencies on other modules that will
1278     * contain the code. See {@link angular.module} for more information.
1279     *
1280     * In the example below if the `ngApp` directive were not placed on the `html` element then the
1281     * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1282     * would not be resolved to `3`.
1283     *
1284     * `ngApp` is the easiest, and most common, way to bootstrap an application.
1285     *
1286     <example module="ngAppDemo">
1287     <file name="index.jsp">
1288     <div ng-controller="ngAppDemoController">
1289     I can add: {{a}} + {{b}} =  {{ a+b }}
1290     </div>
1291     </file>
1292     <file name="script.js">
1293     angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1294     $scope.a = 1;
1295     $scope.b = 2;
1296   });
1297     </file>
1298     </example>
1299     *
1300     */
1301    function angularInit(element, bootstrap) {
1302        var elements = [element],
1303            appElement,
1304            module,
1305            names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
1306            NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
1307
1308        function append(element) {
1309            element && elements.push(element);
1310        }
1311
1312        forEach(names, function (name) {
1313            names[name] = true;
1314            append(document.getElementById(name));
1315            name = name.replace(':', '\\:');
1316            if (element.querySelectorAll) {
1317                forEach(element.querySelectorAll('.' + name), append);
1318                forEach(element.querySelectorAll('.' + name + '\\:'), append);
1319                forEach(element.querySelectorAll('[' + name + ']'), append);
1320            }
1321        });
1322
1323        forEach(elements, function (element) {
1324            if (!appElement) {
1325                var className = ' ' + element.className + ' ';
1326                var match = NG_APP_CLASS_REGEXP.exec(className);
1327                if (match) {
1328                    appElement = element;
1329                    module = (match[2] || '').replace(/\s+/g, ',');
1330                } else {
1331                    forEach(element.attributes, function (attr) {
1332                        if (!appElement && names[attr.name]) {
1333                            appElement = element;
1334                            module = attr.value;
1335                        }
1336                    });
1337                }
1338            }
1339        });
1340        if (appElement) {
1341            bootstrap(appElement, module ? [module] : []);
1342        }
1343    }
1344
1345    /**
1346     * @ngdoc function
1347     * @name angular.bootstrap
1348     * @module ng
1349     * @description
1350     * Use this function to manually start up angular application.
1351     *
1352     * See: {@link guide/bootstrap Bootstrap}
1353     *
1354     * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
1355     * They must use {@link ng.directive:ngApp ngApp}.
1356     *
1357     * Angular will detect if it has been loaded into the browser more than once and only allow the
1358     * first loaded script to be bootstrapped and will report a warning to the browser console for
1359     * each of the subsequent scripts.   This prevents strange results in applications, where otherwise
1360     * multiple instances of Angular try to work on the DOM.
1361     *
1362     * <example name="multi-bootstrap" module="multi-bootstrap">
1363     * <file name="index.jsp">
1364     * <script src="../../../angular.js"></script>
1365     * <div ng-controller="BrokenTable">
1366     *   <table>
1367     *   <tr>
1368     *     <th ng-repeat="heading in headings">{{heading}}</th>
1369     *   </tr>
1370     *   <tr ng-repeat="filling in fillings">
1371     *     <td ng-repeat="fill in filling">{{fill}}</td>
1372     *   </tr>
1373     * </table>
1374     * </div>
1375     * </file>
1376     * <file name="controller.js">
1377     * var app = angular.module('multi-bootstrap', [])
1378     *
1379     * .controller('BrokenTable', function($scope) {
1380 *     $scope.headings = ['One', 'Two', 'Three'];
1381 *     $scope.fillings = [[1, 2, 3], ['A', 'B', 'C'], [7, 8, 9]];
1382 * });
1383     * </file>
1384     * <file name="protractor.js" type="protractor">
1385     * it('should only insert one table cell for each item in $scope.fillings', function() {
1386 *  expect(element.all(by.css('td')).count())
1387 *      .toBe(9);
1388 * });
1389     * </file>
1390     * </example>
1391     *
1392     * @param {DOMElement} element DOM element which is the root of angular application.
1393     * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1394     *     Each item in the array should be the name of a predefined module or a (DI annotated)
1395     *     function that will be invoked by the injector as a run block.
1396     *     See: {@link angular.module modules}
1397     * @returns {auto.$injector} Returns the newly created injector for this app.
1398     */
1399    function bootstrap(element, modules) {
1400        var doBootstrap = function () {
1401            element = jqLite(element);
1402
1403            if (element.injector()) {
1404                var tag = (element[0] === document) ? 'document' : startingTag(element);
1405                throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1406            }
1407
1408            modules = modules || [];
1409            modules.unshift(['$provide', function ($provide) {
1410                $provide.value('$rootElement', element);
1411            }]);
1412            modules.unshift('ng');
1413            var injector = createInjector(modules);
1414            injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
1415                function (scope, element, compile, injector, animate) {
1416                    scope.$apply(function () {
1417                        element.data('$injector', injector);
1418                        compile(element)(scope);
1419                    });
1420                }]
1421            );
1422            return injector;
1423        };
1424
1425        var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1426
1427        if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1428            return doBootstrap();
1429        }
1430
1431        window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1432        angular.resumeBootstrap = function (extraModules) {
1433            forEach(extraModules, function (module) {
1434                modules.push(module);
1435            });
1436            doBootstrap();
1437        };
1438    }
1439
1440    var SNAKE_CASE_REGEXP = /[A-Z]/g;
1441
1442    function snake_case(name, separator) {
1443        separator = separator || '_';
1444        return name.replace(SNAKE_CASE_REGEXP, function (letter, pos) {
1445            return (pos ? separator : '') + letter.toLowerCase();
1446        });
1447    }
1448
1449    function bindJQuery() {
1450        // bind to jQuery if present;
1451        jQuery = window.jQuery;
1452        // reset to jQuery or default to us.
1453        if (jQuery) {
1454            jqLite = jQuery;
1455            extend(jQuery.fn, {
1456                scope: JQLitePrototype.scope,
1457                isolateScope: JQLitePrototype.isolateScope,
1458                controller: JQLitePrototype.controller,
1459                injector: JQLitePrototype.injector,
1460                inheritedData: JQLitePrototype.inheritedData
1461            });
1462            // Method signature:
1463            //     jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
1464            jqLitePatchJQueryRemove('remove', true, true, false);
1465            jqLitePatchJQueryRemove('empty', false, false, false);
1466            jqLitePatchJQueryRemove('html', false, false, true);
1467        } else {
1468            jqLite = JQLite;
1469        }
1470        angular.element = jqLite;
1471    }
1472
1473    /**
1474     * throw error if the argument is falsy.
1475     */
1476    function assertArg(arg, name, reason) {
1477        if (!arg) {
1478            throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1479        }
1480        return arg;
1481    }
1482
1483    function assertArgFn(arg, name, acceptArrayAnnotation) {
1484        if (acceptArrayAnnotation && isArray(arg)) {
1485            arg = arg[arg.length - 1];
1486        }
1487
1488        assertArg(isFunction(arg), name, 'not a function, got ' +
1489            (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
1490        return arg;
1491    }
1492
1493    /**
1494     * throw error if the name given is hasOwnProperty
1495     * @param  {String} name    the name to test
1496     * @param  {String} context the context in which the name is used, such as module or directive
1497     */
1498    function assertNotHasOwnProperty(name, context) {
1499        if (name === 'hasOwnProperty') {
1500            throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1501        }
1502    }
1503
1504    /**
1505     * Return the value accessible from the object by path. Any undefined traversals are ignored
1506     * @param {Object} obj starting object
1507     * @param {String} path path to traverse
1508     * @param {boolean} [bindFnToScope=true]
1509     * @returns {Object} value as accessible by path
1510     */
1511//TODO(misko): this function needs to be removed
1512    function getter(obj, path, bindFnToScope) {
1513        if (!path) return obj;
1514        var keys = path.split('.');
1515        var key;
1516        var lastInstance = obj;
1517        var len = keys.length;
1518
1519        for (var i = 0; i < len; i++) {
1520            key = keys[i];
1521            if (obj) {
1522                obj = (lastInstance = obj)[key];
1523            }
1524        }
1525        if (!bindFnToScope && isFunction(obj)) {
1526            return bind(lastInstance, obj);
1527        }
1528        return obj;
1529    }
1530
1531    /**
1532     * Return the DOM siblings between the first and last node in the given array.
1533     * @param {Array} array like object
1534     * @returns {DOMElement}
1534 object containing the elements
1535     */
1536    function getBlockElements(nodes) {
1537        var startNode = nodes[0],
1538            endNode = nodes[nodes.length - 1];
1539        if (startNode === endNode) {
1540            return jqLite(startNode);
1541        }
1542
1543        var element = startNode;
1544        var elements = [element];
1545
1546        do {
1547            element = element.nextSibling;
1548            if (!element) break;
1549            elements.push(element);
1550        } while (element !== endNode);
1551
1552        return jqLite(elements);
1553    }
1554
1555    /**
1556     * @ngdoc type
1557     * @name angular.Module
1558     * @module ng
1559     * @description
1560     *
1561     * Interface for configuring angular {@link angular.module modules}.
1562     */
1563
1564    function setupModuleLoader(window) {
1565
1566        var $injectorMinErr = minErr('$injector');
1567        var ngMinErr = minErr('ng');
1568
1569        function ensure(obj, name, factory) {
1570            return obj[name] || (obj[name] = factory());
1571        }
1572
1573        var angular = ensure(window, 'angular', Object);
1574
1575        // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
1576        angular.$$minErr = angular.$$minErr || minErr;
1577
1578        return ensure(angular, 'module', function () {
1579            /** @type {Object.<string, angular.Module>} */
1580            var modules = {};
1581
1582            /**
1583             * @ngdoc function
1584             * @name angular.module
1585             * @module ng
1586             * @description
1587             *
1588             * The `angular.module` is a global place for creating, registering and retrieving Angular
1589             * modules.
1590             * All modules (angular core or 3rd party) that should be available to an application must be
1591             * registered using this mechanism.
1592             *
1593             * When passed two or more arguments, a new module is created.  If passed only one argument, an
1594             * existing module (the name passed as the first argument to `module`) is retrieved.
1595             *
1596             *
1597             * # Module
1598             *
1599             * A module is a collection of services, directives, filters, and configuration information.
1600             * `angular.module` is used to configure the {@link auto.$injector $injector}.
1601             *
1602             * ```js
1603             * // Create a new module
1604             * var myModule = angular.module('myModule', []);
1605             *
1606             * // register a new service
1607             * myModule.value('appName', 'MyCoolApp');
1608             *
1609             * // configure existing services inside initialization blocks.
1610             * myModule.config(['$locationProvider', function($locationProvider) {
1611     *   // Configure existing providers
1612     *   $locationProvider.hashPrefix('!');
1613     * }]);
1614             * ```
1615             *
1616             * Then you can create an injector and load your modules like this:
1617             *
1618             * ```js
1619             * var injector = angular.injector(['ng', 'myModule'])
1620             * ```
1621             *
1622             * However it's more likely that you'll just use
1623             * {@link ng.directive:ngApp ngApp} or
1624             * {@link angular.bootstrap} to simplify this process for you.
1625             *
1626             * @param {!string} name The name of the module to create or retrieve.
1627             <<<<<* @param {!Array.<string>=} requires If specified then new module is being created. If
1628             >>>>>*        unspecified then the module is being retrieved for further configuration.
1629             * @param {Function} configFn Optional configuration function for the module. Same as
1630             *        {@link angular.Module#config Module#config()}.
1631             * @returns {module} new module with the {@link angular.Module} api.
1632             */
1633            return function module(name, requires, configFn) {
1634                var assertNotHasOwnProperty = function (name, context) {
1635                    if (name === 'hasOwnProperty') {
1636                        throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1637                    }
1638                };
1639
1640                assertNotHasOwnProperty(name, 'module');
1641                if (requires && modules.hasOwnProperty(name)) {
1642                    modules[name] = null;
1643                }
1644                return ensure(modules, name, function () {
1645                    if (!requires) {
1646                        throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
1647                            "the module name or forgot to load it. If registering a module ensure that you " +
1648                            "specify the dependencies as the second argument.", name);
1649                    }
1650
1651                    /** @type {!Array.<Array.<*>>} */
1652                    var invokeQueue = [];
1653
1654                    /** @type {!Array.<Function>} */
1655                    var runBlocks = [];
1656
1657                    var config = invokeLater('$injector', 'invoke');
1658
1659                    /** @type {angular.Module} */
1660                    var moduleInstance = {
1661                        // Private state
1662                        _invokeQueue: invokeQueue,
1663                        _runBlocks: runBlocks,
1664
1665                        /**
1666                         * @ngdoc property
1667                         * @name angular.Module#requires
1668                         * @module ng
1669                         * @returns {Array.<string>} List of module names which must be loaded before this module.
1670                         * @description
1671                         * Holds the list of modules which the injector will load before the current module is
1672                         * loaded.
1673                         */
1674                        requires: requires,
1675
1676                        /**
1677                         * @ngdoc property
1678                         * @name angular.Module#name
1679                         * @module ng
1680                         * @returns {string} Name of the module.
1681                         * @description
1682                         */
1683                        name: name,
1684
1685
1686                        /**
1687                         * @ngdoc method
1688                         * @name angular.Module#provider
1689                         * @module ng
1690                         * @param {string} name service name
1691                         * @param {Function} providerType Construction function for creating new instance of the
1692                         *                                service.
1693                         * @description
1694                         * See {@link auto.$provide#provider $provide.provider()}.
1695                         */
1696                        provider: invokeLater('$provide', 'provider'),
1697
1698                        /**
1699                         * @ngdoc method
1700                         * @name angular.Module#factory
1701                         * @module ng
1702                         * @param {string} name service name
1703                         * @param {Function} providerFunction Function for creating new instance of the service.
1704                         * @description
1705                         * See {@link auto.$provide#factory $provide.factory()}.
1706                         */
1707                        factory: invokeLater('$provide', 'factory'),
1708
1709                        /**
1710                         * @ngdoc method
1711                         * @name angular.Module#service
1712                         * @module ng
1713                         * @param {string} name service name
1714                         * @param {Function} constructor A constructor function that will be instantiated.
1715                         * @description
1716                         * See {@link auto.$provide#service $provide.service()}.
1717                         */
1718                        service: invokeLater('$provide', 'service'),
1719
1720                        /**
1721                         * @ngdoc method
1722                         * @name angular.Module#value
1723                         * @module ng
1724                         * @param {string} name service name
1725                         * @param {*} object Service instance object.
1726                         * @description
1727                         * See {@link auto.$provide#value $provide.value()}.
1728                         */
1729                        value: invokeLater('$provide', 'value'),
1730
1731                        /**
1732                         * @ngdoc method
1733                         * @name angular.Module#constant
1734                         * @module ng
1735                         * @param {string} name constant name
1736                         * @param {*} object Constant value.
1737                         * @description
1738                         * Because the constant are fixed, they get applied before other provide methods.
1739                         * See {@link auto.$provide#constant $provide.constant()}.
1740                         */
1741                        constant: invokeLater('$provide', 'constant', 'unshift'),
1742
1743                        /**
1744                         * @ngdoc method
1745                         * @name angular.Module#animation
1746                         * @module ng
1747                         * @param {string} name animation name
1748                         * @param {Function} animationFactory Factory function for creating new instance of an
1749                         *                                    animation.
1750                         * @description
1751                         *
1752                         * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
1753                         *
1754                         *
1755                         * Defines an animation hook that can be later used with
1756                         * {@link ngAnimate.$animate $animate} service and directives that use this service.
1757                         *
1758                         * ```js
1759                         * module.animation('.animation-name', function($inject1, $inject2) {
1760           *   return {
1761           *     eventName : function(element, done) {
1762           *       //code to run the animation
1763           *       //once complete, then run done()
1764           *       return function cancellationFunction(element) {
1765           *         //code to cancel the animation
1766           *       }
1767           *     }
1768           *   }
1769           * })
1770                         * ```
1771                         *
1772                         * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
1773                         * {@link ngAnimate ngAnimate module} for more information.
1774                         */
1775                        animation: invokeLater('$animateProvider', 'register'),
1776
1777                        /**
1778                         * @ngdoc method
1779                         * @name angular.Module#filter
1780                         * @module ng
1781                         * @param {string} name Filter name.
1782                         * @param {Function} filterFactory Factory function for creating new instance of filter.
1783                         * @description
1784                         * See {@link ng.$filterProvider#register $filterProvider.register()}.
1785                         */
1786                        filter: invokeLater('$filterProvider', 'register'),
1787
1788                        /**
1789                         * @ngdoc method
1790                         * @name angular.Module#controller
1791                         * @module ng
1792                         * @param {string|Object} name Controller name, or an object map of controllers where the
1793                         *    keys are the names and the values are the constructors.
1794                         * @param {Function} constructor Controller constructor function.
1795                         * @description
1796                         * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
1797                         */
1798                        controller: invokeLater('$controllerProvider', 'register'),
1799
1800                        /**
1801                         * @ngdoc method
1802                         * @name angular.Module#directive
1803                         * @module ng
1804                         * @param {string|Object} name Directive name, or an object map of directives where the
1805                         *    keys are the names and the values are the factories.
1806                         * @param {Function} directiveFactory Factory function for creating new instance of
1807                         * directives.
1808                         * @description
1809                         * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
1810                         */
1811                        directive: invokeLater('$compileProvider', 'directive'),
1812
1813                        /**
1814                         * @ngdoc method
1815                         * @name angular.Module#config
1816                         * @module ng
1817                         * @param {Function} configFn Execute this function on module load. Useful for service
1818                         *    configuration.
1819                         * @description
1820                         * Use this method to register work which needs to be performed on module loading.
1821                         */
1822                        config: config,
1823
1824                        /**
1825                         * @ngdoc method
1826                         * @name angular.Module#run
1827                         * @module ng
1828                         * @param {Function} initializationFn Execute this function after injector creation.
1829                         *    Useful for application initialization.
1830                         * @description
1831                         * Use this method to register work which should be performed when the injector is done
1832                         * loading all modules.
1833                         */
1834                        run: function (block) {
1835                            runBlocks.push(block);
1836                            return this;
1837                        }
1838                    };
1839
1840                    if (configFn) {
1841                        config(configFn);
1842                    }
1843
1844                    return  moduleInstance;
1845
1846                    /**
1847                     * @param {string} provider
1848                     * @param {string} method
1849                     * @param {String=} insertMethod
1850                     * @returns {angular.Module}
1851                     */
1852                    function invokeLater(provider, method, insertMethod) {
1853                        return function () {
1854                            invokeQueue[insertMethod || 'push']([provider, method, arguments]);
1855                            return moduleInstance;
1856                        };
1857                    }
1858                });
1859            };
1860        });
1861
1862    }
1863
1864    /* global
1865     angularModule: true,
1866     version: true,
1867
1868     $LocaleProvider,
1869     $CompileProvider,
1870
1871     htmlAnchorDirective,
1872     inputDirective,
1873     inputDirective,
1874     formDirective,
1875     scriptDirective,
1876     selectDirective,
1877     styleDirective,
1878     optionDirective,
1879     ngBindDirective,
1880     ngBindHtmlDirective,
1881     ngBindTemplateDirective,
1882     ngClassDirective,
1883     ngClassEvenDirective,
1884     ngClassOddDirective,
1885     ngCspDirective,
1886     ngCloakDirective,
1887     ngControllerDirective,
1888     ngFormDirective,
1889     ngHideDirective,
1890     ngIfDirective,
1891     ngIncludeDirective,
1892     ngIncludeFillContentDirective,
1893     ngInitDirective,
1894     ngNonBindableDirective,
1895     ngPluralizeDirective,
1896     ngRepeatDirective,
1897     ngShowDirective,
1898     ngStyleDirective,
1899     ngSwitchDirective,
1900     ngSwitchWhenDirective,
1901     ngSwitchDefaultDirective,
1902     ngOptionsDirective,
1903     ngTranscludeDirective,
1904     ngModelDirective,
1905     ngListDirective,
1906     ngChangeDirective,
1907     requiredDirective,
1908     requiredDirective,
1909     ngValueDirective,
1910     ngAttributeAliasDirectives,
1911     ngEventDirectives,
1912
1913     $AnchorScrollProvider,
1914     $AnimateProvider,
1915     $BrowserProvider,
1916     $CacheFactoryProvider,
1917     $ControllerProvider,
1918     $DocumentProvider,
1919     $ExceptionHandlerProvider,
1920     $FilterProvider,
1921     $InterpolateProvider,
1922     $IntervalProvider,
1923     $HttpProvider,
1924     $HttpBackendProvider,
1925     $LocationProvider,
1926     $LogProvider,
1927     $ParseProvider,
1928     $RootScopeProvider,
1929     $QProvider,
1930     $$SanitizeUriProvider,
1931     $SceProvider,
1932     $SceDelegateProvider,
1933     $SnifferProvider,
1934     $TemplateCacheProvider,
1935     $TimeoutProvider,
1936     $$RAFProvider,
1937     $$AsyncCallbackProvider,
1938     $WindowProvider
1939     */
1940
1941
1942    /**
1943     * @ngdoc object
1944     * @name angular.version
1945     * @module ng
1946     * @description
1947     * An object that contains information about the current AngularJS version. This object has the
1948     * following properties:
1949     *
1950     * - `full` – `{string}` – Full version string, such as "0.9.18".
1951     * - `major` – `{number}` – Major version number, such as "0".
1952     * - `minor` – `{number}` – Minor version number, such as "9".
1953     * - `dot` – `{number}` – Dot version number, such as "18".
1954     * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1955     */
1956    var version = {
1957        full: '1.2.16',    // all of these placeholder strings will be replaced by grunt's
1958        major: 1,    // package task
1959        minor: 2,
1960        dot: 16,
1961        codeName: 'badger-enumeration'
1962    };
1963
1964
1965    function publishExternalAPI(angular) {
1966        extend(angular, {
1967            'bootstrap': bootstrap,
1968            'copy': copy,
1969            'extend': extend,
1970            'equals': equals,
1971            'element': jqLite,
1972            'forEach': forEach,
1973            'injector': createInjector,
1974            'noop': noop,
1975            'bind': bind,
1976            'toJson': toJson,
1977            'fromJson': fromJson,
1978            'identity': identity,
1979            'isUndefined': isUndefined,
1980            'isDefined': isDefined,
1981            'isString': isString,
1982            'isFunction': isFunction,
1983            'isObject': isObject,
1984            'isNumber': isNumber,
1985            'isElement': isElement,
1986            'isArray': isArray,
1987            'version': version,
1988            'isDate': isDate,
1989            'lowercase': lowercase,
1990            'uppercase': uppercase,
1991            'callbacks': {counter: 0},
1992            '$$minErr': minErr,
1993            '$$csp': csp
1994        });
1995
1996        angularModule = setupModuleLoader(window);
1997        try {
1998            angularModule('ngLocale');
1999        } catch (e) {
2000            angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
2001        }
2002
2003        angularModule('ng', ['ngLocale'], ['$provide',
2004            function ngModule($provide) {
2005                // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2006                $provide.provider({
2007                    $$sanitizeUri: $$SanitizeUriProvider
2008                });
2009                $provide.provider('$compile', $CompileProvider).
2010                    directive({
2011                        a: htmlAnchorDirective,
2012                        input: inputDirective,
2013                        textarea: inputDirective,
2014                        form: formDirective,
2015                        script: scriptDirective,
2016                        select: selectDirective,
2017                        style: styleDirective,
2018                        option: optionDirective,
2019                        ngBind: ngBindDirective,
2020                        ngBindHtml: ngBindHtmlDirective,
2021                        ngBindTemplate: ngBindTemplateDirective,
2022                        ngClass: ngClassDirective,
2023                        ngClassEven: ngClassEvenDirective,
2024                        ngClassOdd: ngClassOddDirective,
2025                        ngCloak: ngCloakDirective,
2026                        ngController: ngControllerDirective,
2027                        ngForm: ngFormDirective,
2028                        ngHide: ngHideDirective,
2029                        ngIf: ngIfDirective,
2030                        ngInclude: ngIncludeDirective,
2031                        ngInit: ngInitDirective,
2032                        ngNonBindable: ngNonBindableDirective,
2033                        ngPluralize: ngPluralizeDirective,
2034                        ngRepeat: ngRepeatDirective,
2035                        ngShow: ngShowDirective,
2036                        ngStyle: ngStyleDirective,
2037                        ngSwitch: ngSwitchDirective,
2038                        ngSwitchWhen: ngSwitchWhenDirective,
2039                        ngSwitchDefault: ngSwitchDefaultDirective,
2040                        ngOptions: ngOptionsDirective,
2041                        ngTransclude: ngTranscludeDirective,
2042                        ngModel: ngModelDirective,
2043                        ngList: ngListDirective,
2044                        ngChange: ngChangeDirective,
2045                        required: requiredDirective,
2046                        ngRequired: requiredDirective,
2047                        ngValue: ngValueDirective
2048                    }).
2049                    directive({
2050                        ngInclude: ngIncludeFillContentDirective
2051                    }).
2052                    directive(ngAttributeAliasDirectives).
2053                    directive(ngEventDirectives);
2054                $provide.provider({
2055                    $anchorScroll: $AnchorScrollProvider,
2056                    $animate: $AnimateProvider,
2057                    $browser: $BrowserProvider,
2058                    $cacheFactory: $CacheFactoryProvider,
2059                    $controller: $ControllerProvider,
2060                    $document: $DocumentProvider,
2061                    $exceptionHandler: $ExceptionHandlerProvider,
2062                    $filter: $FilterProvider,
2063                    $interpolate: $InterpolateProvider,
2064                    $interval: $IntervalProvider,
2065                    $http: $HttpProvider,
2066                    $httpBackend: $HttpBackendProvider,
2067                    $location: $LocationProvider,
2068                    $log: $LogProvider,
2069                    $parse: $ParseProvider,
2070                    $rootScope: $RootScopeProvider,
2071                    $q: $QProvider,
2072                    $sce: $SceProvider,
2073                    $sceDelegate: $SceDelegateProvider,
2074                    $sniffer: $SnifferProvider,
2075                    $templateCache: $TemplateCacheProvider,
2076                    $timeout: $TimeoutProvider,
2077                    $window: $WindowProvider,
2078                    $$rAF: $$RAFProvider,
2079                    $$asyncCallback: $$AsyncCallbackProvider
2080                });
2081            }
2082        ]);
2083    }
2084
2085    /* global
2086
2087     -JQLitePrototype,
2088     -addEventListenerFn,
2089     -removeEventListenerFn,
2090     -BOOLEAN_ATTR
2091     */
2092
2093//////////////////////////////////
2094//JQLite
2095//////////////////////////////////
2096
2097    /**
2098     * @ngdoc function
2099     * @name angular.element
2100     * @module ng
2101     * @function
2102     *
2103     * @description
2104     * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2105     *
2106     * If jQuery is available, `angular.element` is an alias for the
2107     * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2108     * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
2109     *
2110     * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
2111     * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
2112     * commonly needed functionality with the goal of having a very small footprint.</div>
2113     *
2114     * To use jQuery, simply load it before `DOMContentLoaded` event fired.
2115     *
2116     * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
2117     * jqLite; they are never raw DOM references.</div>
2118     *
2119     * ## Angular's jqLite
2120     * jqLite provides only the following jQuery methods:
2121     *
2122     * - [`addClass()`](http://api.jquery.com/addClass/)
2123     * - [`after()`](http://api.jquery.com/after/)
2124     * - [`append()`](http://api.jquery.com/append/)
2125     * - [`attr()`](http://api.jquery.com/attr/)
2126     * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2127     * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2128     * - [`clone()`](http://api.jquery.com/clone/)
2129     * - [`contents()`](http://api.jquery.com/contents/)
2130     * - [`css()`](http://api.jquery.com/css/)
2131     * - [`data()`](http://api.jquery.com/data/)
2132     * - [`empty()`](http://api.jquery.com/empty/)
2133     * - [`eq()`](http://api.jquery.com/eq/)
2134     * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2135     * - [`hasClass()`](http://api.jquery.com/hasClass/)
2136     * - [`html()`](http://api.jquery.com/html/)
2137     * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2138     * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2139     * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
2140     * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2141     * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2142     * - [`prepend()`](http://api.jquery.com/prepend/)
2143     * - [`prop()`](http://api.jquery.com/prop/)
2144     * - [`ready()`](http://api.jquery.com/ready/)
2145     * - [`remove()`](http://api.jquery.com/remove/)
2146     * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2147     * - [`removeClass()`](http://api.jquery.com/removeClass/)
2148     * - [`removeData()`](http://api.jquery.com/removeData/)
2149     * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2150     * - [`text()`](http://api.jquery.com/text/)
2151     * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
2152     * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
2153     * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
2154     * - [`val()`](http://api.jquery.com/val/)
2155     * - [`wrap()`](http://api.jquery.com/wrap/)
2156     *
2157     * ## jQuery/jqLite Extras
2158     * Angular also provides the following additional methods and events to both jQuery and jqLite:
2159     *
2160     * ### Events
2161     * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2162     *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
2163     *    element before it is removed.
2164     *
2165     * ### Methods
2166     * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2167     *   retrieves controller associated with the `ngController` directive. If `name` is provided as
2168     *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
2169     *   `'ngModel'`).
2170     * - `injector()` - retrieves the injector of the current element or its parent.
2171     * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2172     *   element or its parent.
2173     * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2174     *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
2175     *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
2176     * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2177     *   parent element is reached.
2178     *
2179     * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2180     * @returns {Object} jQuery object.
2181     */
2182
2183    var jqCache = JQLite.cache = {},
2184        jqName = JQLite.expando = 'ng-' + new Date().getTime(),
2185        jqId = 1,
2186        addEventListenerFn = (window.document.addEventListener
2187            ? function (element, type, fn) {
2188            element.addEventListener(type, fn, false);
2189        }
2190            : function (element, type, fn) {
2191            element.attachEvent('on' + type, fn);
2192        }),
2193        removeEventListenerFn = (window.document.removeEventListener
2194            ? function (element, type, fn) {
2195            element.removeEventListener(type, fn, false);
2196        }
2197            : function (element, type, fn) {
2198            element.detachEvent('on' + type, fn);
2199        });
2200
2201    /*
2202     * !!! This is an undocumented "private" function !!!
2203     */
2204    var jqData = JQLite._data = function (node) {
2205        //jQuery always returns an object on cache miss
2206        return this.cache[node[this.expando]] || {};
2207    };
2208
2209    function jqNextId() {
2210        return ++jqId;
2211    }
2212
2213
2214    var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2215    var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2216    var jqLiteMinErr = minErr('jqLite');
2217
2218    /**
2219     * Converts snake_case to camelCase.
2220     * Also there is special case for Moz prefix starting with upper case letter.
2221     * @param name Name to normalize
2222     */
2223    function camelCase(name) {
2224        return name.
2225            replace(SPECIAL_CHARS_REGEXP,function (_, separator, letter, offset) {
2226                return offset ? letter.toUpperCase() : letter;
2227            }).
2228            replace(MOZ_HACK_REGEXP, 'Moz$1');
2229    }
2230
2231/////////////////////////////////////////////
2232// jQuery mutation patch
2233//
2234// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
2235// $destroy event on all DOM nodes being removed.
2236//
2237/////////////////////////////////////////////
2238
2239    function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
2240        var originalJqFn = jQuery.fn[name];
2241        originalJqFn = originalJqFn.$original || originalJqFn;
2242        removePatch.$original = originalJqFn;
2243        jQuery.fn[name] = removePatch;
2244
2245        function removePatch(param) {
2246            // jshint -W040
2247            var list = filterElems && param ? [this.filter(param)] : [this],
2248                fireEvent = dispatchThis,
2249                set, setIndex, setLength,
2250                element, childIndex, childLength, children;
2251
2252            if (!getterIfNoArguments || param != null) {
2253                while (list.length) {
2254                    set = list.shift();
2255                    for (setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
2256                        element = jqLite(set[setIndex]);
2257                        if (fireEvent) {
2258                            element.triggerHandler('$destroy');
2259                        } else {
2260                            fireEvent = !fireEvent;
2261                        }
2262                        for (childIndex = 0, childLength = (children = element.children()).length;
2263                             childIndex < childLength;
2264                             childIndex++) {
2265                            list.push(jQuery(children[childIndex]));
2266                        }
2267                    }
2268                }
2269            }
2270            return originalJqFn.apply(this, arguments);
2271        }
2272    }
2273
2274    var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
2275    var HTML_REGEXP = /<|&#?\w+;/;
2276    var TAG_NAME_REGEXP = /<([\w:]+)/;
2277    var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
2278
2279    var wrapMap = {
2280        'option': [1, '<select multiple="multiple">', '</select>'],
2281
2282        'thead': [1, '<table>', '</table>'],
2283        'col': [2, '<table><colgroup>', '</colgroup></table>'],
2284        'tr': [2, '<table><tbody>', '</tbody></table>'],
2285        'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2286        '_default': [0, "", ""]
2287    };
2288
2289    wrapMap.optgroup = wrapMap.option;
2290    wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2291    wrapMap.th = wrapMap.td;
2292
2293    function jqLiteIsTextNode(html) {
2294        return !HTML_REGEXP.test(html);
2295    }
2296
2297    function jqLiteBuildFragment(html, context) {
2298        var elem, tmp, tag, wrap,
2299            fragment = context.createDocumentFragment(),
2300            nodes = [], i, j, jj;
2301
2302        if (jqLiteIsTextNode(html)) {
2303            // Convert non-html into a text node
2304            nodes.push(context.createTextNode(html));
2305        } else {
2306            tmp = fragment.appendChild(context.createElement('div'));
2307            // Convert html into DOM nodes
2308            tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2309            wrap = wrapMap[tag] || wrapMap._default;
2310            tmp.innerHTML = '<div>&#160;</div>' +
2311                wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2312            tmp.removeChild(tmp.firstChild);
2313
2314            // Descend through wrappers to the right content
2315            i = wrap[0];
2316            while (i--) {
2317                tmp = tmp.lastChild;
2318            }
2319
2320            for (j = 0, jj = tmp.childNodes.length; j < jj; ++j) nodes.push(tmp.childNodes[j]);
2321
2322            tmp = fragment.firstChild;
2323            tmp.textContent = "";
2324        }
2325
2326        // Remove wrapper from fragment
2327        fragment.textContent = "";
2328        fragment.innerHTML = ""; // Clear inner HTML
2329        return nodes;
2330    }
2331
2332    function jqLiteParseHTML(html, context) {
2333        context = context || document;
2334        var parsed;
2335
2336        if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2337            return [context.createElement(parsed[1])];
2338        }
2339
2340        return jqLiteBuildFragment(html, context);
2341    }
2342
2343/////////////////////////////////////////////
2344    function JQLite(element) {
2345        if (element instanceof JQLite) {
2346            return element;
2347        }
2348        if (isString(element)) {
2349            element = trim(element);
2350        }
2351        if (!(this instanceof JQLite)) {
2352            if (isString(element) && element.charAt(0) != '<') {
2353                throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2354            }
2355            return new JQLite(element);
2356        }
2357
2358        if (isString(element)) {
2359            jqLiteAddNodes(this, jqLiteParseHTML(element));
2360            var fragment = jqLite(document.createDocumentFragment());
2361            fragment.append(this);
2362        } else {
2363            jqLiteAddNodes(this, element);
2364        }
2365    }
2366
2367    function jqLiteClone(element) {
2368        return element.cloneNode(true);
2369    }
2370
2371    function jqLiteDealoc(element) {
2372        jqLiteRemoveData(element);
2373        for (var i = 0, children = element.childNodes || []; i < children.length; i++) {
2374            jqLiteDealoc(children[i]);
2375        }
2376    }
2377
2378    function jqLiteOff(element, type, fn, unsupported) {
2379        if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2380
2381        var events = jqLiteExpandoStore(element, 'events'),
2382            handle = jqLiteExpandoStore(element, 'handle');
2383
2384        if (!handle) return; //no listeners registered
2385
2386        if (isUndefined(type)) {
2387            forEach(events, function (eventHandler, type) {
2388                removeEventListenerFn(element, type, eventHandler);
2389                delete events[type];
2390            });
2391        } else {
2392            forEach(type.split(' '), function (type) {
2393                if (isUndefined(fn)) {
2394                    removeEventListenerFn(element, type, events[type]);
2395                    delete events[type];
2396                } else {
2397                    arrayRemove(events[type] || [], fn);
2398                }
2399            });
2400        }
2401    }
2402
2403    function jqLiteRemoveData(element, name) {
2404        var expandoId = element[jqName],
2405            expandoStore = jqCache[expandoId];
2406
2407        if (expandoStore) {
2408            if (name) {
2409                delete jqCache[expandoId].data[name];
2410                return;
2411            }
2412
2413            if (expandoStore.handle) {
2414                expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
2415                jqLiteOff(element);
2416            }
2417            delete jqCache[expandoId];
2418            element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
2419        }
2420    }
2421
2422    function jqLiteExpandoStore(element, key, value) {
2423        var expandoId = element[jqName],
2424            expandoStore = jqCache[expandoId || -1];
2425
2426        if (isDefined(value)) {
2427            if (!expandoStore) {
2428                element[jqName] = expandoId = jqNextId();
2429                expandoStore = jqCache[expandoId] = {};
2430            }
2431            expandoStore[key] = value;
2432        } else {
2433            return expandoStore && expandoStore[key];
2434        }
2435    }
2436
2437    function jqLiteData(element, key, value) {
2438        var data = jqLiteExpandoStore(element, 'data'),
2439            isSetter = isDefined(value),
2440            keyDefined = !isSetter && isDefined(key),
2441            isSimpleGetter = keyDefined && !isObject(key);
2442
2443        if (!data && !isSimpleGetter) {
2444            jqLiteExpandoStore(element, 'data', data = {});
2445        }
2446
2447        if (isSetter) {
2448            data[key] = value;
2449        } else {
2450            if (keyDefined) {
2451                if (isSimpleGetter) {
2452                    // don't create data in this case.
2453                    return data && data[key];
2454                } else {
2455                    extend(data, key);
2456                }
2457            } else {
2458                return data;
2459            }
2460        }
2461    }
2462
2463    function jqLiteHasClass(element, selector) {
2464        if (!element.getAttribute) return false;
2465        return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
2466            indexOf(" " + selector + " ") > -1);
2467    }
2468
2469    function jqLiteRemoveClass(element, cssClasses) {
2470        if (cssClasses && element.setAttribute) {
2471            forEach(cssClasses.split(' '), function (cssClass) {
2472                element.setAttribute('class', trim(
2473                    (" " + (element.getAttribute('class') || '') + " ")
2474                        .replace(/[\n\t]/g, " ")
2475                        .replace(" " + trim(cssClass) + " ", " "))
2476                );
2477            });
2478        }
2479    }
2480
2481    function jqLiteAddClass(element, cssClasses) {
2482        if (cssClasses && element.setAttribute) {
2483            var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
2484                .replace(/[\n\t]/g, " ");
2485
2486            forEach(cssClasses.split(' '), function (cssClass) {
2487                cssClass = trim(cssClass);
2488                if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
2489                    existingClasses += cssClass + ' ';
2490                }
2491            });
2492
2493            element.setAttribute('class', trim(existingClasses));
2494        }
2495    }
2496
2497    function jqLiteAddNodes(root, elements) {
2498        if (elements) {
2499            elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
2500                ? elements
2501                : [ elements ];
2502            for (var i = 0; i < elements.length; i++) {
2503                root.push(elements[i]);
2504            }
2505        }
2506    }
2507
2508    function jqLiteController(element, name) {
2509        return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
2510    }
2511
2512    function jqLiteInheritedData(element, name, value) {
2513        element = jqLite(element);
2514
2515        // if element is the document object work with the html element instead
2516        // this makes $(document).scope() possible
2517        if (element[0].nodeType == 9) {
2518            element = element.find('html');
2519        }
2520        var names = isArray(name) ? name : [name];
2521
2522        while (element.length) {
2523            var node = element[0];
2524            for (var i = 0, ii = names.length; i < ii; i++) {
2525                if ((value = element.data(names[i])) !== undefined) return value;
2526            }
2527
2528            // If dealing with a document fragment node with a host element, and no parent, use the host
2529            // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
2530            // to lookup parent controllers.
2531            element = jqLite(node.parentNode || (node.nodeType === 11 && node.host));
2532        }
2533    }
2534
2535    function jqLiteEmpty(element) {
2536        for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2537            jqLiteDealoc(childNodes[i]);
2538        }
2539        while (element.firstChild) {
2540            element.removeChild(element.firstChild);
2541        }
2542    }
2543
2544//////////////////////////////////////////
2545// Functions which are declared directly.
2546//////////////////////////////////////////
2547    var JQLitePrototype = JQLite.prototype = {
2548        ready: function (fn) {
2549            var fired = false;
2550
2551            function trigger() {
2552                if (fired) return;
2553                fired = true;
2554                fn();
2555            }
2556
2557            // check if document already is loaded
2558            if (document.readyState === 'complete') {
2559                setTimeout(trigger);
2560            } else {
2561                this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
2562                // we can not use jqLite since we are not done loading and jQuery could be loaded later.
2563                // jshint -W064
2564                JQLite(window).on('load', trigger); // fallback to window.onload for others
2565                // jshint +W064
2566            }
2567        },
2568        toString: function () {
2569            var value = [];
2570            forEach(this, function (e) {
2571                value.push('' + e);
2572            });
2573            return '[' + value.join(', ') + ']';
2574        },
2575
2576        eq: function (index) {
2577            return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
2578        },
2579
2580        length: 0,
2581        push: push,
2582        sort: [].sort,
2583        splice: [].splice
2584    };
2585
2586//////////////////////////////////////////
2587// Functions iterating getter/setters.
2588// these functions return self on setter and
2589// value on get.
2590//////////////////////////////////////////
2591    var BOOLEAN_ATTR = {};
2592    forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function (value) {
2593        BOOLEAN_ATTR[lowercase(value)] = value;
2594    });
2595    var BOOLEAN_ELEMENTS = {};
2596    forEach('input,select,option,textarea,button,form,details'.split(','), function (value) {
2597        BOOLEAN_ELEMENTS[uppercase(value)] = true;
2598    });
2599
2600    function getBooleanAttrName(element, name) {
2601        // check dom last since we will most likely fail on name
2602        var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2603
2604        // booleanAttr is here twice to minimize DOM access
2605        return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2606    }
2607
2608    forEach({
2609        data: jqLiteData,
2610        inheritedData: jqLiteInheritedData,
2611
2612        scope: function (element) {
2613            // Can't use jqLiteData here directly so we stay compatible with jQuery!
2614            return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
2615        },
2616
2617        isolateScope: function (element) {
2618            // Can't use jqLiteData here directly so we stay compatible with jQuery!
2619            return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
2620        },
2621
2622        controller: jqLiteController,
2623
2624        injector: function (element) {
2625            return jqLiteInheritedData(element, '$injector');
2626        },
2627
2628        removeAttr: function (element, name) {
2629            element.removeAttribute(name);
2630        },
2631
2632        hasClass: jqLiteHasClass,
2633
2634        css: function (element, name, value) {
2635            name = camelCase(name);
2636
2637            if (isDefined(value)) {
2638                element.style[name] = value;
2639            } else {
2640                var val;
2641
2642                if (msie <= 8) {
2643                    // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
2644                    val = element.currentStyle && element.currentStyle[name];
2645                    if (val === '') val = 'auto';
2646                }
2647
2648                val = val || element.style[name];
2649
2650                if (msie <= 8) {
2651                    // jquery weirdness :-/
2652                    val = (val === '') ? undefined : val;
2653                }
2654
2655                return  val;
2656            }
2657        },
2658
2659        attr: function (element, name, value) {
2660            var lowercasedName = lowercase(name);
2661            if (BOOLEAN_ATTR[lowercasedName]) {
2662                if (isDefined(value)) {
2663                    if (!!value) {
2664                        element[name] = true;
2665                        element.setAttribute(name, lowercasedName);
2666                    } else {
2667                        element[name] = false;
2668                        element.removeAttribute(lowercasedName);
2669                    }
2670                } else {
2671                    return (element[name] ||
2672                        (element.attributes.getNamedItem(name) || noop).specified)
2673                        ? lowercasedName
2674                        : undefined;
2675                }
2676            } else if (isDefined(value)) {
2677                element.setAttribute(name, value);
2678            } else if (element.getAttribute) {
2679                // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
2680                // some elements (e.g. Document) don't have get attribute, so return undefined
2681                var ret = element.getAttribute(name, 2);
2682                // normalize non-existing attributes to undefined (as jQuery)
2683                return ret === null ? undefined : ret;
2684            }
2685        },
2686
2687        prop: function (element, name, value) {
2688            if (isDefined(value)) {
2689                element[name] = value;
2690            } else {
2691                return element[name];
2692            }
2693        },
2694
2695        text: (function () {
2696            var NODE_TYPE_TEXT_PROPERTY = [];
2697            if (msie < 9) {
2698                NODE_TYPE_TEXT_PROPERTY[1] = 'innerText';
2699                /** Element **/
2700                NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue';
2701                /** Text **/
2702            } else {
2703                NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
2704                    NODE_TYPE_TEXT_PROPERTY[3] = 'textContent';
2705                /** Text **/
2706            }
2707            getText.$dv = '';
2708            return getText;
2709
2710            function getText(element, value) {
2711                var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
2712                if (isUndefined(value)) {
2713                    return textProp ? element[textProp] : '';
2714                }
2715                element[textProp] = value;
2716            }
2717        })(),
2718
2719        val: function (element, value) {
2720            if (isUndefined(value)) {
2721                if (nodeName_(element) === 'SELECT' && element.multiple) {
2722                    var result = [];
2723                    forEach(element.options, function (option) {
2724                        if (option.selected) {
2725                            result.push(option.value || option.text);
2726                        }
2727                    });
2728                    return result.length === 0 ? null : result;
2729                }
2730                return element.value;
2731            }
2732            element.value = value;
2733        },
2734
2735        html: function (element, value) {
2736            if (isUndefined(value)) {
2737                return element.innerHTML;
2738            }
2739            for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
2740                jqLiteDealoc(childNodes[i]);
2741            }
2742            element.innerHTML = value;
2743        },
2744
2745        empty: jqLiteEmpty
2746    }, function (fn, name) {
2747        /**
2748         * Properties: writes return selection, reads return first value
2749         */
2750        JQLite.prototype[name] = function (arg1, arg2) {
2751            var i, key;
2752
2753            // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
2754            // in a way that survives minification.
2755            // jqLiteEmpty takes no arguments but is a setter.
2756            if (fn !== jqLiteEmpty &&
2757                (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
2758                if (isObject(arg1)) {
2759
2760                    // we are a write, but the object properties are the key/values
2761                    for (i = 0; i < this.length; i++) {
2762                        if (fn === jqLiteData) {
2763                            // data() takes the whole object in jQuery
2764                            fn(this[i], arg1);
2765                        } else {
2766                            for (key in arg1) {
2767                                fn(this[i], key, arg1[key]);
2768                            }
2769                        }
2770                    }
2771                    // return self for chaining
2772                    return this;
2773                } else {
2774                    // we are a read, so read the first child.
2775                    var value = fn.$dv;
2776                    // Only if we have $dv do we iterate over all, otherwise it is just the first element.
2777                    var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
2778                    for (var j = 0; j < jj; j++) {
2779                        var nodeValue = fn(this[j], arg1, arg2);
2780                        value = value ? value + nodeValue : nodeValue;
2781                    }
2782                    return value;
2783                }
2784            } else {
2785                // we are a write, so apply to all children
2786                for (i = 0; i < this.length; i++) {
2787                    fn(this[i], arg1, arg2);
2788                }
2789                // return self for chaining
2790                return this;
2791            }
2792        };
2793    });
2794
2795    function createEventHandler(element, events) {
2796        var eventHandler = function (event, type) {
2797            if (!event.preventDefault) {
2798                event.preventDefault = function () {
2799                    event.returnValue = false; //ie
2800                };
2801            }
2802
2803            if (!event.stopPropagation) {
2804                event.stopPropagation = function () {
2805                    event.cancelBubble = true; //ie
2806                };
2807            }
2808
2809            if (!event.target) {
2810                event.target = event.srcElement || document;
2811            }
2812
2813            if (isUndefined(event.defaultPrevented)) {
2814                var prevent = event.preventDefault;
2815                event.preventDefault = function () {
2816                    event.defaultPrevented = true;
2817                    prevent.call(event);
2818                };
2819                event.defaultPrevented = false;
2820            }
2821
2822            event.isDefaultPrevented = function () {
2823                return event.defaultPrevented || event.returnValue === false;
2824            };
2825
2826            // Copy event handlers in case event handlers array is modified during execution.
2827            var eventHandlersCopy = shallowCopy(events[type || event.type] || []);
2828
2829            forEach(eventHandlersCopy, function (fn) {
2830                fn.call(element, event);
2831            });
2832
2833            // Remove monkey-patched methods (IE),
2834            // as they would cause memory leaks in IE8.
2835            if (msie <= 8) {
2836                // IE7/8 does not allow to delete property on native object
2837                event.preventDefault = null;
2838                event.stopPropagation = null;
2839                event.isDefaultPrevented = null;
2840            } else {
2841                // It shouldn't affect normal browsers (native methods are defined on prototype).
2842                delete event.preventDefault;
2843                delete event.stopPropagation;
2844                delete event.isDefaultPrevented;
2845            }
2846        };
2847        eventHandler.elem = element;
2848        return eventHandler;
2849    }
2850
2851//////////////////////////////////////////
2852// Functions iterating traversal.
2853// These functions chain results into a single
2854// selector.
2855//////////////////////////////////////////
2856    forEach({
2857        removeData: jqLiteRemoveData,
2858
2859        dealoc: jqLiteDealoc,
2860
2861        on: function onFn(element, type, fn, unsupported) {
2862            if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2863
2864            var events = jqLiteExpandoStore(element, 'events'),
2865                handle = jqLiteExpandoStore(element, 'handle');
2866
2867            if (!events) jqLiteExpandoStore(element, 'events', events = {});
2868            if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
2869
2870            forEach(type.split(' '), function (type) {
2871                var eventFns = events[type];
2872
2873                if (!eventFns) {
2874                    if (type == 'mouseenter' || type == 'mouseleave') {
2875                        var contains = document.body.contains || document.body.compareDocumentPosition ?
2876                            function (a, b) {
2877                                // jshint bitwise: false
2878                                var adown = a.nodeType === 9 ? a.documentElement : a,
2879                                    bup = b && b.parentNode;
2880                                return a === bup || !!( bup && bup.nodeType === 1 && (
2881                                    adown.contains ?
2882                                        adown.contains(bup) :
2883                                        a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
2884                                    ));
2885                            } :
2886                            function (a, b) {
2887                                if (b) {
2888                                    while ((b = b.parentNode)) {
2889                                        if (b === a) {
2890                                            return true;
2891                                        }
2892                                    }
2893                                }
2894                                return false;
2895                            };
2896
2897                        events[type] = [];
2898
2899                        // Refer to jQuery's implementation of mouseenter & mouseleave
2900                        // Read about mouseenter and mouseleave:
2901                        // http://www.quirksmode.org/js/events_mouse.html#link8
2902                        var eventmap = { mouseleave: "mouseout", mouseenter: "mouseover"};
2903
2904                        onFn(element, eventmap[type], function (event) {
2905                            var target = this, related = event.relatedTarget;
2906                            // For mousenter/leave call the handler if related is outside the target.
2907                            // NB: No relatedTarget if the mouse left/entered the browser window
2908                            if (!related || (related !== target && !contains(target, related))) {
2909                                handle(event, type);
2910                            }
2911                        });
2912
2913                    } else {
2914                        addEventListenerFn(element, type, handle);
2915                        events[type] = [];
2916                    }
2917                    eventFns = events[type];
2918                }
2919                eventFns.push(fn);
2920            });
2921        },
2922
2923        off: jqLiteOff,
2924
2925        one: function (element, type, fn) {
2926            element = jqLite(element);
2927
2928            //add the listener twice so that when it is called
2929            //you can remove the original function and still be
2930            //able to call element.off(ev, fn) normally
2931            element.on(type, function onFn() {
2932                element.off(type, fn);
2933                element.off(type, onFn);
2934            });
2935            element.on(type, fn);
2936        },
2937
2938        replaceWith: function (element, replaceNode) {
2939            var index, parent = element.parentNode;
2940            jqLiteDealoc(element);
2941            forEach(new JQLite(replaceNode), function (node) {
2942                if (index) {
2943                    parent.insertBefore(node, index.nextSibling);
2944                } else {
2945                    parent.replaceChild(node, element);
2946                }
2947                index = node;
2948            });
2949        },
2950
2951        children: function (element) {
2952            var children = [];
2953            forEach(element.childNodes, function (element) {
2954                if (element.nodeType === 1)
2955                    children.push(element);
2956            });
2957            return children;
2958        },
2959
2960        contents: function (element) {
2961            return element.contentDocument || element.childNodes || [];
2962        },
2963
2964        append: function (element, node) {
2965            forEach(new JQLite(node), function (child) {
2966                if (element.nodeType === 1 || element.nodeType === 11) {
2967                    element.appendChild(child);
2968                }
2969            });
2970        },
2971
2972        prepend: function (element, node) {
2973            if (element.nodeType === 1) {
2974                var index = element.firstChild;
2975                forEach(new JQLite(node), function (child) {
2976                    element.insertBefore(child, index);
2977                });
2978            }
2979        },
2980
2981        wrap: function (element, wrapNode) {
2982            wrapNode = jqLite(wrapNode)[0];
2983            var parent = element.parentNode;
2984            if (parent) {
2985                parent.replaceChild(wrapNode, element);
2986            }
2987            wrapNode.appendChild(element);
2988        },
2989
2990        remove: function (element) {
2991            jqLiteDealoc(element);
2992            var parent = element.parentNode;
2993            if (parent) parent.removeChild(element);
2994        },
2995
2996        after: function (element, newElement) {
2997            var index = element, parent = element.parentNode;
2998            forEach(new JQLite(newElement), function (node) {
2999                parent.insertBefore(node, index.nextSibling);
3000                index = node;
3001            });
3002        },
3003
3004        addClass: jqLiteAddClass,
3005        removeClass: jqLiteRemoveClass,
3006
3007        toggleClass: function (element, selector, condition) {
3008            if (selector) {
3009                forEach(selector.split(' '), function (className) {
3010                    var classCondition = condition;
3011                    if (isUndefined(classCondition)) {
3012                        classCondition = !jqLiteHasClass(element, className);
3013                    }
3014                    (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3015                });
3016            }
3017        },
3018
3019        parent: function (element) {
3020            var parent = element.parentNode;
3021            return parent && parent.nodeType !== 11 ? parent : null;
3022        },
3023
3024        next: function (element) {
3025            if (element.nextElementSibling) {
3026                return element.nextElementSibling;
3027            }
3028
3029            // IE8 doesn't have nextElementSibling
3030            var elm = element.nextSibling;
3031            while (elm != null && elm.nodeType !== 1) {
3032                elm = elm.nextSibling;
3033            }
3034            return elm;
3035        },
3036
3037        find: function (element, selector) {
3038            if (element.getElementsByTagName) {
3039                return element.getElementsByTagName(selector);
3040            } else {
3041                return [];
3042            }
3043        },
3044
3045        clone: jqLiteClone,
3046
3047        triggerHandler: function (element, eventName, eventData) {
3048            var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
3049
3050            eventData = eventData || [];
3051
3052            var event = [
3053                {
3054                    preventDefault: noop,
3055                    stopPropagation: noop
3056                }
3057            ];
3058
3059            forEach(eventFns, function (fn) {
3060                fn.apply(element, event.concat(eventData));
3061            });
3062        }
3063    }, function (fn, name) {
3064        /**
3065         * chaining functions
3066         */
3067        JQLite.prototype[name] = function (arg1, arg2, arg3) {
3068            var value;
3069            for (var i = 0; i < this.length; i++) {
3070                if (isUndefined(value)) {
3071                    value = fn(this[i], arg1, arg2, arg3);
3072                    if (isDefined(value)) {
3073                        // any function which returns a value needs to be wrapped
3074                        value = jqLite(value);
3075                    }
3076                } else {
3077                    jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3078                }
3079            }
3080            return isDefined(value) ? value : this;
3081        };
3082
3083        // bind legacy bind/unbind to on/off
3084        JQLite.prototype.bind = JQLite.prototype.on;
3085        JQLite.prototype.unbind = JQLite.prototype.off;
3086    });
3087
3088    /**
3089     * Computes a hash of an 'obj'.
3090     * Hash of a:
3091     *  string is string
3092     *  number is number as string
3093     *  object is either result of calling $$hashKey function on the object or uniquely generated id,
3094     *         that is also assigned to the $$hashKey property of the object.
3095     *
3096     * @param obj
3097     * @returns {string} hash string such that the same input will have the same hash string.
3098     *         The resulting string key is in 'type:hashKey' format.
3099     */
3100    function hashKey(obj) {
3101        var objType = typeof obj,
3102            key;
3103
3104        if (objType == 'object' && obj !== null) {
3105            if (typeof (key = obj.$$hashKey) == 'function') {
3106                // must invoke on object to keep the right this
3107                key = obj.$$hashKey();
3108            } else if (key === undefined) {
3109                key = obj.$$hashKey = nextUid();
3110            }
3111        } else {
3112            key = obj;
3113        }
3114
3115        return objType + ':' + key;
3116    }
3117
3118    /**
3119     * HashMap which can use objects as keys
3120     */
3121    function HashMap(array) {
3122        forEach(array, this.put, this);
3123    }
3124
3125    HashMap.prototype = {
3126        /**
3127         * Store key value pair
3128         * @param key key to store can be any type
3129         * @param value value to store can be any type
3130         */
3131        put: function (key, value) {
3132            this[hashKey(key)] = value;
3133        },
3134
3135        /**
3136         * @param key
3137         * @returns {Object} the value for the key
3138         */
3139        get: function (key) {
3140            return this[hashKey(key)];
3141        },
3142
3143        /**
3144         * Remove the key/value pair
3145         * @param key
3146         */
3147        remove: function (key) {
3148            var value = this[key = hashKey(key)];
3149            delete this[key];
3150            return value;
3151        }
3152    };
3153
3154    /**
3155     * @ngdoc function
3156     * @module ng
3157     * @name angular.injector
3158     * @function
3159     *
3160     * @description
3161     * Creates an injector function that can be used for retrieving services as well as for
3162     * dependency injection (see {@link guide/di dependency injection}).
3163     *
3164
3165     * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3166     *        {@link angular.module}. The `ng` module must be explicitly added.
3167     * @returns {function()} Injector function. See {@link auto.$injector $injector}.
3168     *
3169     * @example
3170     * Typical usage
3171     * ```js
3172     *   // create an injector
3173     *   var $injector = angular.injector(['ng']);
3174     *
3175     *   // use the injector to kick off your application
3176     *   // use the type inference to auto inject arguments, or use impl
3176icit injection
3177     *   $injector.invoke(function($rootScope, $compile, $document){
3178 *     $compile($document)($rootScope);
3179 *     $rootScope.$digest();
3180 *   });
3181     * ```
3182     *
3183     * Sometimes you want to get access to the injector of a currently running Angular app
3184     * from outside Angular. Perhaps, you want to inject and compile some markup after the
3185     * application has been bootstrapped. You can do this using extra `injector()` added
3186     * to JQuery/jqLite elements. See {@link angular.element}.
3187     *
3188     * *This is fairly rare but could be the case if a third party library is injecting the
3189     * markup.*
3190     *
3191     * In the following example a new block of HTML containing a `ng-controller`
3192     * directive is added to the end of the document body by JQuery. We then compile and link
3193     * it into the current AngularJS scope.
3194     *
3195     * ```js
3196     * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3197     * $(document.body).append($div);
3198     *
3199     * angular.element(document).injector().invoke(function($compile) {
3200 *   var scope = angular.element($div).scope();
3201 *   $compile($div)(scope);
3202 * });
3203     * ```
3204     */
3205
3206
3207    /**
3208     * @ngdoc module
3209     * @name auto
3210     * @description
3211     *
3212     * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3213     */
3214
3215    var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
3216    var FN_ARG_SPLIT = /,/;
3217    var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3218    var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3219    var $injectorMinErr = minErr('$injector');
3220
3221    function annotate(fn) {
3222        var $inject,
3223            fnText,
3224            argDecl,
3225            last;
3226
3227        if (typeof fn == 'function') {
3228            if (!($inject = fn.$inject)) {
3229                $inject = [];
3230                if (fn.length) {
3231                    fnText = fn.toString().replace(STRIP_COMMENTS, '');
3232                    argDecl = fnText.match(FN_ARGS);
3233                    forEach(argDecl[1].split(FN_ARG_SPLIT), function (arg) {
3234                        arg.replace(FN_ARG, function (all, underscore, name) {
3235                            $inject.push(name);
3236                        });
3237                    });
3238                }
3239                fn.$inject = $inject;
3240            }
3241        } else if (isArray(fn)) {
3242            last = fn.length - 1;
3243            assertArgFn(fn[last], 'fn');
3244            $inject = fn.slice(0, last);
3245        } else {
3246            assertArgFn(fn, 'fn', true);
3247        }
3248        return $inject;
3249    }
3250
3251///////////////////////////////////////
3252
3253    /**
3254     * @ngdoc service
3255     * @name $injector
3256     * @function
3257     *
3258     * @description
3259     *
3260     * `$injector` is used to retrieve object instances as defined by
3261     * {@link auto.$provide provider}, instantiate types, invoke methods,
3262     * and load modules.
3263     *
3264     * The following always holds true:
3265     *
3266     * ```js
3267     *   var $injector = angular.injector();
3268     *   expect($injector.get('$injector')).toBe($injector);
3269     *   expect($injector.invoke(function($injector){
3270 *     return $injector;
3271 *   }).toBe($injector);
3272     * ```
3273     *
3274     * # Injection Function Annotation
3275     *
3276     * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3277     * following are all valid ways of annotating function with injection arguments and are equivalent.
3278     *
3279     * ```js
3280     *   // inferred (only works if code not minified/obfuscated)
3281     *   $injector.invoke(function(serviceA){});
3282     *
3283     *   // annotated
3284     *   function explicit(serviceA) {};
3285     *   explicit.$inject = ['serviceA'];
3286     *   $injector.invoke(explicit);
3287     *
3288     *   // inline
3289     *   $injector.invoke(['serviceA', function(serviceA){}]);
3290     * ```
3291     *
3292     * ## Inference
3293     *
3294     * In JavaScript calling `toString()` on a function returns the function definition. The definition
3295     * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3296     * minification, and obfuscation tools since these tools change the argument names.
3297     *
3298     * ## `$inject` Annotation
3299     * By adding a `$inject` property onto a function the injection parameters can be specified.
3300     *
3301     * ## Inline
3302     * As an array of injection names, where the last item in the array is the function to call.
3303     */
3304
3305    /**
3306     * @ngdoc method
3307     * @name $injector#get
3308     *
3309     * @description
3310     * Return an instance of the service.
3311     *
3312     * @param {string} name The name of the instance to retrieve.
3313     * @return {*} The instance.
3314     */
3315
3316    /**
3317     * @ngdoc method
3318     * @name $injector#invoke
3319     *
3320     * @description
3321     * Invoke the method and supply the method arguments from the `$injector`.
3322     *
3323     * @param {!Function} fn The function to invoke. Function parameters are injected according to the
3324     *   {@link guide/di $inject Annotation} rules.
3325     * @param {Object=} self The `this` for the invoked method.
3326     * @param {Object=} locals Optional object. If preset then any argument names are read from this
3327     *                         object first, before the `$injector` is consulted.
3328     * @returns {*} the value returned by the invoked `fn` function.
3329     */
3330
3331    /**
3332     * @ngdoc method
3333     * @name $injector#has
3334     *
3335     * @description
3336     * Allows the user to query if the particular service exist.
3337     *
3338     * @param {string} Name of the service to query.
3339     * @returns {boolean} returns true if injector has given service.
3340     */
3341
3342    /**
3343     * @ngdoc method
3344     * @name $injector#instantiate
3345     * @description
3346     * Create a new instance of JS type. The method takes a constructor function invokes the new
3347     * operator and supplies all of the arguments to the constructor function as specified by the
3348     * constructor annotation.
3349     *
3350     * @param {Function} Type Annotated constructor function.
3351     * @param {Object=} locals Optional object. If preset then any argument names are read from this
3352     * object first, before the `$injector` is consulted.
3353     * @returns {Object} new instance of `Type`.
3354     */
3355
3356    /**
3357     * @ngdoc method
3358     * @name $injector#annotate
3359     *
3360     * @description
3361     * Returns an array of service names which the function is requesting for injection. This API is
3362     * used by the injector to determine which services need to be injected into the function when the
3363     * function is invoked. There are three ways in which the function can be annotated with the needed
3364     * dependencies.
3365     *
3366     * # Argument names
3367     *
3368     * The simplest form is to extract the dependencies from the arguments of the function. This is done
3369     * by converting the function into a string using `toString()` method and extracting the argument
3370     * names.
3371     * ```js
3372     *   // Given
3373     *   function MyController($scope, $route) {
3374 *     // ...
3375 *   }
3376     *
3377     *   // Then
3378     *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3379     * ```
3380     *
3381     * This method does not work with code minification / obfuscation. For this reason the following
3382     * annotation strategies are supported.
3383     *
3384     * # The `$inject` property
3385     *
3386     * If a function has an `$inject` property and its value is an array of strings, then the strings
3387     * represent names of services to be injected into the function.
3388     * ```js
3389     *   // Given
3390     *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
3391 *     // ...
3392 *   }
3393     *   // Define function dependencies
3394     *   MyController['$inject'] = ['$scope', '$route'];
3395     *
3396     *   // Then
3397     *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3398     * ```
3399     *
3400     * # The array notation
3401     *
3402     * It is often desirable to inline Injected functions and that's when setting the `$inject` property
3403     * is very inconvenient. In these situations using the array notation to specify the dependencies in
3404     * a way that survives minification is a better choice:
3405     *
3406     * ```js
3407     *   // We wish to write this (not minification / obfuscation safe)
3408     *   injector.invoke(function($compile, $rootScope) {
3409 *     // ...
3410 *   });
3411     *
3412     *   // We are forced to write break inlining
3413     *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
3414 *     // ...
3415 *   };
3416     *   tmpFn.$inject = ['$compile', '$rootScope'];
3417     *   injector.invoke(tmpFn);
3418     *
3419     *   // To better support inline function the inline annotation is supported
3420     *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
3421 *     // ...
3422 *   }]);
3423     *
3424     *   // Therefore
3425     *   expect(injector.annotate(
3426     *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
3427     *    ).toEqual(['$compile', '$rootScope']);
3428     * ```
3429     *
3430     * @param {Function|Array.<string|Function>}
3430 fn Function for which dependent service names need to
3431     * be retrieved as described above.
3432     *
3433     * @returns {Array.<string>} The names of the services which the function requires.
3434     */
3435
3436
3437    /**
3438     * @ngdoc object
3439     * @name $provide
3440     *
3441     * @description
3442     *
3443     * The {@link auto.$provide $provide} service has a number of methods for registering components
3444     * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
3445     * {@link angular.Module}.
3446     *
3447     * An Angular **service** is a singleton object created by a **service factory**.  These **service
3448     * factories** are functions which, in turn, are created by a **service provider**.
3449     * The **service providers** are constructor functions. When instantiated they must contain a
3450     * property called `$get`, which holds the **service factory** function.
3451     *
3452     * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
3453     * correct **service provider**, instantiating it and then calling its `$get` **service factory**
3454     * function to get the instance of the **service**.
3455     *
3456     * Often services have no configuration options and there is no need to add methods to the service
3457     * provider.  The provider will be no more than a constructor function with a `$get` property. For
3458     * these cases the {@link auto.$provide $provide} service has additional helper methods to register
3459     * services without specifying a provider.
3460     *
3461     * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
3462     *     {@link auto.$injector $injector}
3463     * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
3464     *     providers and services.
3465     * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
3466     *     services, not providers.
3467     * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
3468     *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
3469     *     given factory function.
3470     * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
3471     *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
3472     *      a new object using the given constructor function.
3473     *
3474     * See the individual methods for more information and examples.
3475     */
3476
3477    /**
3478     * @ngdoc method
3479     * @name $provide#provider
3480     * @description
3481     *
3482     * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
3483     * are constructor functions, whose instances are responsible for "providing" a factory for a
3484     * service.
3485     *
3486     * Service provider names start with the name of the service they provide followed by `Provider`.
3487     * For example, the {@link ng.$log $log} service has a provider called
3488     * {@link ng.$logProvider $logProvider}.
3489     *
3490     * Service provider objects can have additional methods which allow configuration of the provider
3491     * and its service. Importantly, you can configure what kind of service is created by the `$get`
3492     * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
3493     * method {@link ng.$logProvider#debugEnabled debugEnabled}
3494     * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
3495     * console or not.
3496     *
3497     * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
3498     'Provider'` key.
3499     * @param {(Object|function())} provider If the provider is:
3500     *
3501     *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
3502     *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
3503     *   - `Constructor`: a new instance of the provider will be created using
3504     *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
3505     *
3506     * @returns {Object} registered provider instance
3507
3508     * @example
3509     *
3510     * The following example shows how to create a simple event tracking service and register it using
3511     * {@link auto.$provide#provider $provide.provider()}.
3512     *
3513     * ```js
3514     *  // Define the eventTracker provider
3515     *  function EventTrackerProvider() {
3516 *    var trackingUrl = '/track';
3517 *
3518 *    // A provider method for configuring where the tracked events should been saved
3519 *    this.setTrackingUrl = function(url) {
3520 *      trackingUrl = url;
3521 *    };
3522 *
3523 *    // The service factory function
3524 *    this.$get = ['$http', function($http) {
3525 *      var trackedEvents = {};
3526 *      return {
3527 *        // Call this to track an event
3528 *        event: function(event) {
3529 *          var count = trackedEvents[event] || 0;
3530 *          count += 1;
3531 *          trackedEvents[event] = count;
3532 *          return count;
3533 *        },
3534 *        // Call this to save the tracked events to the trackingUrl
3535 *        save: function() {
3536 *          $http.post(trackingUrl, trackedEvents);
3537 *        }
3538 *      };
3539 *    }];
3540 *  }
3541     *
3542     *  describe('eventTracker', function() {
3543 *    var postSpy;
3544 *
3545 *    beforeEach(module(function($provide) {
3546 *      // Register the eventTracker provider
3547 *      $provide.provider('eventTracker', EventTrackerProvider);
3548 *    }));
3549 *
3550 *    beforeEach(module(function(eventTrackerProvider) {
3551 *      // Configure eventTracker provider
3552 *      eventTrackerProvider.setTrackingUrl('/custom-track');
3553 *    }));
3554 *
3555 *    it('tracks events', inject(function(eventTracker) {
3556 *      expect(eventTracker.event('login')).toEqual(1);
3557 *      expect(eventTracker.event('login')).toEqual(2);
3558 *    }));
3559 *
3560 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
3561 *      postSpy = spyOn($http, 'post');
3562 *      eventTracker.event('login');
3563 *      eventTracker.save();
3564 *      expect(postSpy).toHaveBeenCalled();
3565 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
3566 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
3567 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
3568 *    }));
3569 *  });
3570     * ```
3571     */
3572
3573    /**
3574     * @ngdoc method
3575     * @name $provide#factory
3576     * @description
3577     *
3578     * Register a **service factory**, which will be called to return the service instance.
3579     * This is short for registering a service where its provider consists of only a `$get` property,
3580     * which is the given service factory function.
3581     * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
3582     * configure your service in a provider.
3583     *
3584     * @param {string} name The name of the instance.
3585     * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
3586     *                            for `$provide.provider(name, {$get: $getFn})`.
3587     * @returns {Object} registered provider instance
3588     *
3589     * @example
3590     * Here is an example of registering a service
3591     * ```js
3592     *   $provide.factory('ping', ['$http', function($http) {
3593 *     return function ping() {
3594 *       return $http.send('/ping');
3595 *     };
3596 *   }]);
3597     * ```
3598     * You would then inject and use this service like this:
3599     * ```js
3600     *   someModule.controller('Ctrl', ['ping', function(ping) {
3601 *     ping();
3602 *   }]);
3603     * ```
3604     */
3605
3606
3607    /**
3608     * @ngdoc method
3609     * @name $provide#service
3610     * @description
3611     *
3612     * Register a **service constructor**, which will be invoked with `new` to create the service
3613     * instance.
3614     * This is short for registering a service where its provider's `$get` property is the service
3615     * constructor function that will be used to instantiate the service instance.
3616     *
3617     * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
3618     * as a type/class.
3619     *
3620     * @param {string} name The name of the instance.
3621     * @param {Function} constructor A class (constructor function) that will be instantiated.
3622     * @returns {Object} registered provider instance
3623     *
3624     * @example
3625     * Here is an example of registering a service using
3626     * {@link auto.$provide#service $provide.service(class)}.
3627     * ```js
3628     *   var Ping = function($http) {
3629 *     this.$http = $http;
3630 *   };
3631     *
3632     *   Ping.$inject = ['$http'];
3633     *
3634     *   Ping.prototype.send = function() {
3635 *     return this.$http.get('/ping');
3636 *   };
3637     *   $provide.service('ping', Ping);
3638     * ```
3639     * You would then inject and use this service like this:
3640     * ```js
3641     *   someModule.controller('Ctrl', ['ping', function(ping) {
3642 *     ping.send();
3643 *   }]);
3644     * ```
3645     */
3646
3647
3648    /**
3649     * @ngdoc method
3650     * @name $provide#value
3651     * @description
3652     *
3653     * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
3654     * number, an array, an object or a function.  This is short for registering a service where its
3655     * provider's `$get` property is a factory function that takes no arguments and returns the **value
3656     * service**.
3657     *
3658     * Value services are similar to constant services, except that they cannot be injected into a
3659     * module configuration function (see {@link angular.Module#config}) but they can be overridden by
3660     * an Angular
3661     * {@link auto.$provide#decorator decorator}.
3662     *
3663     * @param {string} name The name of the instance.
3664     * @param {*} value The value.
3665     * @returns {Object} registered provider instance
3666     *
3667     * @example
3668     * Here are some examples of creating value services.
3669     * ```js
3670     *   $provide.value('ADMIN_USER', 'admin');
3671     *
3672     *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
3673     *
3674     *   $provide.value('halfOf', function(value) {
3675 *     return value / 2;
3676 *   });
3677     * ```
3678     */
3679
3680
3681    /**
3682     * @ngdoc method
3683     * @name $provide#constant
3684     * @description
3685     *
3686     * Register a **constant service**, such as a string, a number, an array, an object or a function,
3687     * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
3688     * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
3689     * be overridden by an Angular {@link auto.$provide#decorator decorator}.
3690     *
3691     * @param {string} name The name of the constant.
3692     * @param {*} value The constant value.
3693     * @returns {Object} registered instance
3694     *
3695     * @example
3696     * Here a some examples of creating constants:
3697     * ```js
3698     *   $provide.constant('SHARD_HEIGHT', 306);
3699     *
3700     *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
3701     *
3702     *   $provide.constant('double', function(value) {
3703 *     return value * 2;
3704 *   });
3705     * ```
3706     */
3707
3708
3709    /**
3710     * @ngdoc method
3711     * @name $provide#decorator
3712     * @description
3713     *
3714     * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
3715     * intercepts the creation of a service, allowing it to override or modify the behaviour of the
3716     * service. The object returned by the decorator may be the original service, or a new service
3717     * object which replaces or wraps and delegates to the original service.
3718     *
3719     * @param {string} name The name of the service to decorate.
3720     * @param {function()} decorator This function will be invoked when the service needs to be
3721     *    instantiated and should return the decorated service instance. The function is called using
3722     *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
3723     *    Local injection arguments:
3724     *
3725     *    * `$delegate` - The original service instance, which can be monkey patched, configured,
3726     *      decorated or delegated to.
3727     *
3728     * @example
3729     * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
3730     * calls to {@link ng.$log#error $log.warn()}.
3731     * ```js
3732     *   $provide.decorator('$log', ['$delegate', function($delegate) {
3733 *     $delegate.warn = $delegate.error;
3734 *     return $delegate;
3735 *   }]);
3736     * ```
3737     */
3738
3739
3740    function createInjector(modulesToLoad) {
3741        var INSTANTIATING = {},
3742            providerSuffix = 'Provider',
3743            path = [],
3744            loadedModules = new HashMap(),
3745            providerCache = {
3746                $provide: {
3747                    provider: supportObject(provider),
3748                    factory: supportObject(factory),
3749                    service: supportObject(service),
3750                    value: supportObject(value),
3751                    constant: supportObject(constant),
3752                    decorator: decorator
3753                }
3754            },
3755            providerInjector = (providerCache.$injector =
3756                createInternalInjector(providerCache, function () {
3757                    throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
3758                })),
3759            instanceCache = {},
3760            instanceInjector = (instanceCache.$injector =
3761                createInternalInjector(instanceCache, function (servicename) {
3762                    var provider = providerInjector.get(servicename + providerSuffix);
3763                    return instanceInjector.invoke(provider.$get, provider);
3764                }));
3765
3766
3767        forEach(loadModules(modulesToLoad), function (fn) {
3768            instanceInjector.invoke(fn || noop);
3769        });
3770
3771        return instanceInjector;
3772
vendor: 1,915 bytes, lines 3773-3827
3773        ////////////////////////////////////
3774        // $provider
3775        ////////////////////////////////////
3776
3777        function supportObject(delegate) {
3778            return function (key, value) {
3779                if (isObject(key)) {
3780                    forEach(key, reverseParams(delegate));
3781                } else {
3782                    return delegate(key, value);
3783                }
3784            };
3785        }
3786
3787        function provider(name, provider_) {
3788            assertNotHasOwnProperty(name, 'service');
3789            if (isFunction(provider_) || isArray(provider_)) {
3790                provider_ = providerInjector.instantiate(provider_);
3791            }
3792            if (!provider_.$get) {
3793                throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
3794            }
3795            return providerCache[name + providerSuffix] = provider_;
3796        }
3797
3798        function factory(name, factoryFn) {
3799            return provider(name, { $get: factoryFn });
3800        }
3801
3802        function service(name, constructor) {
3803            return factory(name, ['$injector', function ($injector) {
3804                return $injector.instantiate(constructor);
3805            }]);
3806        }
3807
3808        function value(name, val) {
3809            return factory(name, valueFn(val));
3810        }
3811
3812        function constant(name, value) {
3813            assertNotHasOwnProperty(name, 'constant');
3814            providerCache[name] = value;
3815            instanceCache[name] = value;
3816        }
3817
3818        function decorator(serviceName, decorFn) {
3819            var origProvider = providerInjector.get(serviceName + providerSuffix),
3820                orig$get = origProvider.$get;
3821
3822            origProvider.$get = function () {
3823                var origInstance = instanceInjector.invoke(orig$get, origProvider);
3824                return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
3825            };
3826        }
3827
3828        ////////////////////////////////////
3829        // Module Loading
3830        ////////////////////////////////////
3831        function loadModules(modulesToLoad) {
3832            var runBlocks = [], moduleFn, invokeQueue, i, ii;
3833            forEach(modulesToLoad, function (module) {
3834                if (loadedModules.get(module)) return;
3835                loadedModules.put(module, true);
3836
3837                try {
3838                    if (isString(module)) {
3839                        moduleFn = angularModule(module);
3840                        runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
3841
3842                        for (invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
3843                            var invokeArgs = invokeQueue[i],
3844                                provider = providerInjector.get(invokeArgs[0]);
3845
3846                            provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
3847                        }
3848                    } else if (isFunction(module)) {
3849                        runBlocks.push(providerInjector.invoke(module));
3850                    } else if (isArray(module)) {
3851                        runBlocks.push(providerInjector.invoke(module));
3852                    } else {
3853                        assertArgFn(module, 'module');
3854                    }
3855                } catch (e) {
3856                    if (isArray(module)) {
3857                        module = module[module.length - 1];
3858                    }
3859                    if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
3860                        // Safari & FF's stack traces don't contain error.message content
3861                        // unlike those of Chrome and IE
3862                        // So if stack doesn't contain message, we create a new string that contains both.
3863                        // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
3864                        /* jshint -W022 */
3865                        e = e.message + '\n' + e.stack;
3866                    }
3867                    throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
3868                        module, e.stack || e.message || e);
3869                }
3870            });
3871            return runBlocks;
3872        }
3873
3874        ////////////////////////////////////
3875        // internal Injector
3876        ////////////////////////////////////
3877
3878        function createInternalInjector(cache, factory) {
3879
3880            function getService(serviceName) {
3881                if (cache.hasOwnProperty(serviceName)) {
3882                    if (cache[serviceName] === INSTANTIATING) {
3883                        throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
3884                    }
3885                    return cache[serviceName];
3886                } else {
3887                    try {
3888                        path.unshift(serviceName);
3889                        cache[serviceName] = INSTANTIATING;
3890                        return cache[serviceName] = factory(serviceName);
3891                    } catch (err) {
3892                        if (cache[serviceName] === INSTANTIATING) {
3893                            delete cache[serviceName];
3894                        }
3895                        throw err;
3896                    } finally {
3897                        path.shift();
3898                    }
3899                }
3900            }
3901
3902            function invoke(fn, self, locals) {
3903                var args = [],
3904                    $inject = annotate(fn),
3905                    length, i,
3906                    key;
3907
3908                for (i = 0, length = $inject.length; i < length; i++) {
3909                    key = $inject[i];
3910                    if (typeof key !== 'string') {
3911                        throw $injectorMinErr('itkn',
3912                            'Incorrect injection token! Expected service name as string, got {0}', key);
3913                    }
3914                    args.push(
3915                        locals && locals.hasOwnProperty(key)
3916                            ? locals[key]
3917                            : getService(key)
3918                    );
3919                }
3920                if (!fn.$inject) {
3921                    // this means that we must be an array.
3922                    fn = fn[length];
3923                }
3924
3925                // http://jsperf.com/angularjs-invoke-apply-vs-switch
3926                // #5388
3927                return fn.apply(self, args);
3928            }
3929
3930            function instantiate(Type, locals) {
3931                var Constructor = function () {
3932                    },
3933                    instance, returnedValue;
3934
3935                // Check if Type is annotated and use just the given function at n-1 as parameter
3936                // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
3937                Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
3938                instance = new Constructor();
3939                returnedValue = invoke(Type, instance, locals);
3940
3941                return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
3942            }
3943
3944            return {
3945                invoke: invoke,
3946                instantiate: instantiate,
3947                get: getService,
3948                annotate: annotate,
3949                has: function (name) {
3950                    return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
3951                }
3952            };
3953        }
3954    }
3955
3956    /**
3957     * @ngdoc service
3958     * @name $anchorScroll
3959     * @kind function
3960     * @requires $window
3961     * @requires $location
3962     * @requires $rootScope
3963     *
3964     * @description
3965     * When called, it checks current value of `$location.hash()` and scroll to related element,
3966     * according to rules specified in
3967     * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
3968     *
3969     * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
3970     * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
3971     *
3972     * @example
3973     <example>
3974     <file name="index.jsp">
3975     <div id="scrollArea" ng-controller="ScrollCtrl">
3976     <a ng-click="gotoBottom()">Go to bottom</a>
3977     <a id="bottom"></a> You're at the bottom!
3978     </div>
3979     </file>
3980     <file name="script.js">
3981     function ScrollCtrl($scope, $location, $anchorScroll) {
3982         $scope.gotoBottom = function (){
3983           // set the location.hash to the id of
3984           // the element you wish to scroll to.
3985           $location.hash('bottom');
3986
3987           // call $anchorScroll()
3988           $anchorScroll();
3989         };
3990       }
3991     </file>
3992     <file name="style.css">
3993     #scrollArea {
3994         height: 350px;
3995         overflow: auto;
3996       }
3997
3998     #bottom {
3999         display: block;
4000         margin-top: 2000px;
4001       }
4002     </file>
4003     </example>
4004     */
4005    function $AnchorScrollProvider() {
4006
4007        var autoScrollingEnabled = true;
4008
4009        this.disableAutoScrolling = function () {
4010            autoScrollingEnabled = false;
4011        };
4012
4013        this.$get = ['$window', '$location', '$rootScope', function ($window, $location, $rootScope) {
4014            var document = $window.document;
4015
4016            // helper function to get first anchor from a NodeList
4017            // can't use filter.filter, as it accepts only instances of Array
4018            // and IE can't convert NodeList to an array using [].slice
4019            // TODO(vojta): use filter if we change it to accept lists as well
4020            function getFirstAnchor(list) {
4021                var result = null;
4022                forEach(list, function (element) {
4023                    if (!result && lowercase(element.nodeName) === 'a') result = element;
4024                });
4025                return result;
4026            }
4027
4028            function scroll() {
4029                var hash = $location.hash(), elm;
4030
4031                // empty hash, scroll to the top of the page
4032                if (!hash) $window.scrollTo(0, 0);
4033
4034                // element with given id
4035                else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
4036
4037                // first anchor with given name :-D
4038                else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
4039
4040                // no element and hash == 'top', scroll to the top of the page
4041                else if (hash === 'top') $window.scrollTo(0, 0);
4042            }
4043
4044            // does not scroll when user clicks on anchor link that is currently on
4045            // (no url change, no $location.hash() change), browser native does scroll
4046            if (autoScrollingEnabled) {
4047                $rootScope.$watch(function autoScrollWatch() {
4048                        return $location.hash();
4049                    },
4050                    function autoScrollWatchAction() {
4051                        $rootScope.$evalAsync(scroll);
4052                    });
4053            }
4054
4055            return scroll;
4056        }];
4057    }
4058
4059    var $animateMinErr = minErr('$animate');
4060
4061    /**
4062     * @ngdoc provider
4063     * @name $animateProvider
4064     *
4065     * @description
4066     * Default implementation of $animate that doesn't perform any animations, instead just
4067     * synchronously performs DOM
4068     * updates and calls done() callbacks.
4069     *
4070     * In order to enable animations the ngAnimate module has to be loaded.
4071     *
4072     * To see the functional implementation check out src/ngAnimate/animate.js
4073     */
4074    var $AnimateProvider = ['$provide', function ($provide) {
4075
4076
4077        this.$$selectors = {};
4078
4079
4080        /**
4081         * @ngdoc method
4082         * @name $animateProvider#register
4083         *
4084         * @description
4085         * Registers a new injectable animation factory function. The factory function produces the
4086         * animation object which contains callback functions for each event that is expected to be
4087         * animated.
4088         *
4089         *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
4090         *   must be called once the element animation is complete. If a function is returned then the
4091         *   animation service will use this function to cancel the animation whenever a cancel event is
4092         *   triggered.
4093         *
4094         *
4095         * ```js
4096         *   return {
4097     *     eventFn : function(element, done) {
4098     *       //code to run the animation
4099     *       //once complete, then run done()
4100     *       return function cancellationFunction() {
4101     *         //code to cancel the animation
4102     *       }
4103     *     }
4104     *   }
4105         * ```
4106         *
4107         * @param {string} name The name of the animation.
4108         * @param {Function} factory The factory function that will be executed to return the animation
4109         *                           object.
4110         */
4111        this.register = function (name, factory) {
4112            var key = name + '-animation';
4113            if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
4114                "Expecting class selector starting with '.' got '{0}'.", name);
4115            this.$$selectors[name.substr(1)] = key;
4116            $provide.factory(key, factory);
4117        };
4118
4119        /**
4120         * @ngdoc method
4121         * @name $animateProvider#classNameFilter
4122         *
4123         * @description
4124         * Sets and/or returns the CSS class regular expression that is checked when performing
4125         * an animation. Upon bootstrap the classNameFilter value is not set at all and will
4126         * therefore enable $animate to attempt to perform an animation on any element.
4127         * When setting the classNameFilter value, animations will only be performed on elements
4128         * that successfully match the filter expression. This in turn can boost performance
4129         * for low-powered devices as well as applications containing a lot of structural operations.
4130         * @param {RegExp=} expression The className expression which will be checked against all animations
4131         * @return {RegExp} The current CSS className expression value. If null then there is no expression value
4132         */
4133        this.classNameFilter = function (expression) {
4134            if (arguments.length === 1) {
4135                this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
4136            }
4137            return this.$$classNameFilter;
4138        };
4139
4140        this.$get = ['$timeout', '$$asyncCallback', function ($timeout, $$asyncCallback) {
4141
4142            function async(fn) {
4143                fn && $$asyncCallback(fn);
4144            }
4145
4146            /**
4147             *
4148             * @ngdoc service
4149             * @name $animate
4150             * @description The $animate service provides rudimentary DOM manipulation functions to
4151             * insert, remove and move elements within the DOM, as well as adding and removing classes.
4152             * This service is the core service used by the ngAnimate $animator service which provides
4153             * high-level animation hooks for CSS and JavaScript.
4154             *
4155             * $animate is available in the AngularJS core, however, the ngAnimate module must be included
4156             * to enable full out animation support. Otherwise, $animate will only perform simple DOM
4157             * manipulation operations.
4158             *
4159             * To learn more about enabling animation support, click here to visit the {@link ngAnimate
4160     * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
4161     * page}.
4162             */
4163            return {
4164
4165                /**
4166                 *
4167                 * @ngdoc method
4168                 * @name $animate#enter
4169                 * @function
4170                 * @description Inserts the element into the DOM either after the `after` element or within
4171                 *   the `parent` element. Once complete, the done() callback will be fired (if provided).
4172                 * @param {DOMElement} element the element which will be inserted into the DOM
4173                 * @param {DOMElement} parent the parent element which will append the element as
4174                 *   a child (if the after element is not present)
4175                 * @param {DOMElement} after the sibling element which will append the element
4176                 *   after itself
4177                 * @param {Function=} done callback function that will be called after the element has been
4178                 *   inserted into the DOM
4179                 */
4180                enter: function (element, parent, after, done) {
4181                    if (after) {
4182                        after.after(element);
4183                    } else {
4184                        if (!parent || !parent[0]) {
4185                            parent = after.parent();
4186                        }
4187                        parent.append(element);
4188                    }
4189                    async(done);
4190                },
4191
4192                /**
4193                 *
4194                 * @ngdoc method
4195                 * @name $animate#leave
4196                 * @function
4197                 * @description Removes the element from the DOM. Once complete, the done() callback will be
4198                 *   fired (if provided).
4199                 * @param {DOMElement} element the element which will be removed from the DOM
4200                 * @param {Function=} done callback function that will be called after the element has been
4201                 *   removed from the DOM
4202                 */
4203                leave: function (element, done) {
4204                    element.remove();
4205                    async(done);
4206                },
4207
4208                /**
4209                 *
4210                 * @ngdoc method
4211                 * @name $animate#move
4212                 * @function
4213                 * @description Moves the position of the provided element within the DOM to be placed
4214                 * either after the `after` element or inside of the `parent` element. Once complete, the
4215                 * done() callback will be fired (if provided).
4216                 *
4217                 * @param {DOMElement} element the element which will be moved around within the
4218                 *   DOM
4219                 * @param {DOMElement} parent the parent element where the element will be
4220                 *   inserted into (if the after element is not present)
4221                 * @param {DOMElement} after the sibling element where the element will be
4222                 *   positioned next to
4223                 * @param {Function=} done the callback function (if provided) that will be fired after the
4224                 *   element has been moved to its new position
4225                 */
4226                move: function (element, parent, after, done) {
4227                    // Do not remove element before insert. Removing will cause data associated with the
4228                    // element to be dropped. Insert will implicitly do the remove.
4229                    this.enter(element, parent, after, done);
4230                },
4231
4232                /**
4233                 *
4234                 * @ngdoc method
4235                 * @name $animate#addClass
4236                 * @function
4237                 * @description Adds the provided className CSS class value to the provided element. Once
4238                 * complete, the done() callback will be fired (if provided).
4239                 * @param {DOMElement} element the element which will have the className value
4240                 *   added to it
4241                 * @param {string} className the CSS class which will be added to the element
4242                 * @param {Function=} done the callback function (if provided) that will be fired after the
4243                 *   className value has been added to the element
4244                 */
4245                addClass: function (element, className, done) {
4246                    className = isString(className) ?
4247                        className :
4248                        isArray(className) ? className.join(' ') : '';
4249                    forEach(element, function (element) {
4250                        jqLiteAddClass(element, className);
4251                    });
4252                    async(done);
4253                },
4254
4255                /**
4256                 *
4257                 * @ngdoc method
4258                 * @name $animate#removeClass
4259                 * @function
4260                 * @description Removes the provided className CSS class value from the provided element.
4261                 * Once complete, the done() callback will be fired (if provided).
4262                 * @param {DOMElement} element the element which will have the className value
4263                 *   removed from it
4264                 * @param {string} className the CSS class which will be removed from the element
4265                 * @param {Function=} done the callback function (if provided) that will be fired after the
4266                 *   className value has been removed from the element
4267                 */
4268                removeClass: function (element, className, done) {
4269                    className = isString(className) ?
4270                        className :
4271                        isArray(className) ? className.join(' ') : '';
4272                    forEach(element, function (element) {
4273                        jqLiteRemoveClass(element, className);
4274                    });
4275                    async(done);
4276                },
4277
4278                /**
4279                 *
4280                 * @ngdoc method
4281                 * @name $animate#setClass
4282                 * @function
4283                 * @description Adds and/or removes the given CSS classes to and from the element.
4284                 * Once complete, the done() callback will be fired (if provided).
4285                 * @param {DOMElement} element the element which will it's CSS classes changed
4286                 *   removed from it
4287                 * @param {string} add the CSS classes which will be added to the element
4288                 * @param {string} remove the CSS class which will be removed from the element
4289                 * @param {Function=} done the callback function (if provided) that will be fired after the
4290                 *   CSS classes have been set on the element
4291                 */
4292                setClass: function (element, add, remove, done) {
4293                    forEach(element, function (element) {
4294                        jqLiteAddClass(element, add);
4295                        jqLiteRemoveClass(element, remove);
4296                    });
4297                    async(done);
4298                },
4299
4300                enabled: noop
4301            };
4302        }];
4303    }];
4304
4305    function $$AsyncCallbackProvider() {
4306        this.$get = ['$$rAF', '$timeout', function ($$rAF, $timeout) {
4307            return $$rAF.supported
4308                ? function (fn) {
4309                return $$rAF(fn);
4310            }
4311                : function (fn) {
4312                return $timeout(fn, 0, false);
4313            };
4314        }];
4315    }
4316
4317    /**
4318     * ! This is a private undocumented service !
4319     *
4320     * @name $browser
4321     * @requires $log
4322     * @description
4323     * This object has two goals:
4324     *
4325     * - hide all the global state in the browser caused by the window object
4326     * - abstract away all the browser specific features and inconsistencies
4327     *
4328     * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
4329     * service, which can be used for convenient testing of the application without the interaction with
4330     * the real browser apis.
4331     */
4332    /**
4333     * @param {object} window The global window object.
4334     * @param {object} document jQuery wrapped document.
4335     * @param {function()} XHR XMLHttpRequest constructor.
4336     * @param {object} $log console.log or an object with the same interface.
4337     * @param {object} $sniffer $sniffer service
4338     */
4339    function Browser(window, document, $log, $sniffer) {
4340        var self = this,
4341            rawDocument = document[0],
4342            location = window.location,
4343            history = window.history,
4344            setTimeout = window.setTimeout,
4345            clearTimeout = window.clearTimeout,
4346            pendingDeferIds = {};
4347
4348        self.isMock = false;
4349
4350        var outstandingRequestCount = 0;
4351        var outstandingRequestCallbacks = [];
4352
4353        // TODO(vojta): remove this temporary api
4354        self.$$completeOutstandingRequest = completeOutstandingRequest;
4355        self.$$incOutstandingRequestCount = function () {
4356            outstandingRequestCount++;
4357        };
4358
4359        /**
4360         * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
4361         * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
4362         */
4363        function completeOutstandingRequest(fn) {
4364            try {
4365                fn.apply(null, sliceArgs(arguments, 1));
4366            } finally {
4367                outstandingRequestCount--;
4368                if (outstandingRequestCount === 0) {
4369                    while (outstandingRequestCallbacks.length) {
4370                        try {
4371                            outstandingRequestCallbacks.pop()();
4372                        } catch (e) {
4373                            $log.error(e);
4374                        }
4375                    }
4376                }
4377            }
4378        }
4379
4380        /**
4381         * @private
4382         * Note: this method is used only by scenario runner
4383         * TODO(vojta): prefix this method with $$ ?
4384         * @param {function()} callback Function that will be called when no outstanding request
4385         */
4386        self.notifyWhenNoOutstandingRequests = function (callback) {
4387            // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
4388            // at some deterministic time in respect to the test runner's actions. Leaving things up to the
4389            // regular poller would result in flaky tests.
4390            forEach(pollFns, function (pollFn) {
4391                pollFn();
4392            });
4393
4394            if (outstandingRequestCount === 0) {
4395                callback();
4396            } else {
4397                outstandingRequestCallbacks.push(callback);
4398            }
4399        };
4400
4401        //////////////////////////////////////////////////////////////
4402        // Poll Watcher API
4403        //////////////////////////////////////////////////////////////
4404        var pollFns = [],
4405            pollTimeout;
4406
4407        /**
4408         * @name $browser#addPollFn
4409         *
4410         * @param {function()} fn Poll function to add
4411         *
4412         * @description
4413         * Adds a function to the list of functions that poller periodically executes,
4414         * and starts polling if not started yet.
4415         *
4416         * @returns {function()} the added function
4417         */
4418        self.addPollFn = function (fn) {
4419            if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
4420            pollFns.push(fn);
4421            return fn;
4422        };
4423
4424        /**
4425         * @param {number} interval How often should browser call poll functions (ms)
4426         * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
4427         *
4428         * @description
4429         * Configures the poller to run in the specified intervals, using the specified
4430         * setTimeout fn and kicks it off.
4431         */
4432        function startPoller(interval, setTimeout) {
4433            (function check() {
4434                forEach(pollFns, function (pollFn) {
4435                    pollFn();
4436                });
4437                pollTimeout = setTimeout(check, interval);
4438            })();
4439        }
4440
4441        //////////////////////////////////////////////////////////////
4442        // URL API
4443        //////////////////////////////////////////////////////////////
4444
4445        var lastBrowserUrl = location.href,
4446            baseElement = document.find('base'),
4447            newLocation = null;
4448
4449        /**
4450         * @name $browser#url
4451         *
4452         * @description
4453         * GETTER:
4454         * Without any argument, this method just returns current value of location.href.
4455         *
4456         * SETTER:
4457         * With at least one argument, this method sets url to new value.
4458         * If html5 history api supported, pushState/replaceState is used, otherwise
4459         * location.href/location.replace is used.
4460         * Returns its own instance to allow chaining
4461         *
4462         * NOTE: this api is intended for use only by the $location service. Please use the
4463         * {@link ng.$location $location service} to change url.
4464         *
4465         * @param {string} url New url (when used as setter)
4466         * @param {boolean=} replace Should new url replace current history record ?
4467         */
4468        self.url = function (url, replace) {
4469            // Android Browser BFCache causes location, history reference to become stale.
4470            if (location !== window.location) location = window.location;
4471            if (history !== window.history) history = window.history;
4472
4473            // setter
4474            if (url) {
4475                if (lastBrowserUrl == url) return;
4476                lastBrowserUrl = url;
4477                if ($sniffer.history) {
4478                    if (replace) history.replaceState(null, '', url);
4479                    else {
4480                        history.pushState(null, '', url);
4481                        // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
4482                        baseElement.attr('href', baseElement.attr('href'));
4483                    }
4484                } else {
4485                    newLocation = url;
4486                    if (replace) {
4487                        location.replace(url);
4488                    } else {
4489                        location.href = url;
4490                    }
4491                }
4492                return self;
4493                // getter
4494            } else {
4495                // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
4496                //   methods not updating location.href synchronously.
4497                // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
4498                return newLocation || location.href.replace(/%27/g, "'");
4499            }
4500        };
4501
4502        var urlChangeListeners = [],
4503            urlChangeInit = false;
4504
4505        function fireUrlChange() {
4506            newLocation = null;
4507            if (lastBrowserUrl == self.url()) return;
4508
4509            lastBrowserUrl = self.url();
4510            forEach(urlChangeListeners, function (listener) {
4511                listener(self.url());
4512            });
4513        }
4514
4515        /**
4516         * @name $browser#onUrlChange
4517         *
4518         * @description
4519         * Register callback function that will be called, when url changes.
4520         *
4521         * It's only called when the url is changed from outside of angular:
4522         * - user types different url into address bar
4523         * - user clicks on history (forward/back) button
4524         * - user clicks on a link
4525         *
4526         * It's not called when url is changed by $browser.url() method
4527         *
4528         * The listener gets called with new url as parameter.
4529         *
4530         * NOTE: this api is intended for use only by the $location service. Please use the
4531         * {@link ng.$location $location service} to monitor url changes in angular apps.
4532         *
4533         * @param {function(string)} listener Listener function to be called when url changes.
4534         * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
4535         */
4536        self.onUrlChange = function (callback) {
4537            // TODO(vojta): refactor to use node's syntax for events
4538            if (!urlChangeInit) {
4539                // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
4540                // don't fire popstate when user change the address bar and don't fire hashchange when url
4541                // changed by push/replaceState
4542
4543                // html5 history api - popstate event
4544                if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
4545                // hashchange event
4546                if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
4547                // polling
4548                else self.addPollFn(fireUrlChange);
4549
4550                urlChangeInit = true;
4551            }
4552
4553            urlChangeListeners.push(callback);
4554            return callback;
4555        };
4556
4557        //////////////////////////////////////////////////////////////
4558        // Misc API
4559        //////////////////////////////////////////////////////////////
4560
4561        /**
4562         * @name $browser#baseHref
4563         *
4564         * @description
4565         * Returns current <base href>
4566         * (always relative - without domain)
4567         *
4568         * @returns {string} The current base href
4569         */
4570        self.baseHref = function () {
4571            var href = baseElement.attr('href');
4572            return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
4573        };
4574
4575        //////////////////////////////////////////////////////////////
4576        // Cookies API
4577        //////////////////////////////////////////////////////////////
4578        var lastCookies = {};
4579        var lastCookieString = '';
4580        var cookiePath = self.baseHref();
4581
4582        /**
4583         * @name $browser#cookies
4584         *
4585         * @param {string=} name Cookie name
4586         * @param {string=} value Cookie value
4587         *
4588         * @description
4589         * The cookies method provides a 'private' low level access to browser cookies.
4590         * It is not meant to be used directly, use the $cookie service instead.
4591         *
4592         * The return values vary depending on the arguments that the method was called with as follows:
4593         *
4594         * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
4595         *   it
4596         * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
4597         * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
4598         *   way)
4599         *
4600         * @returns {Object} Hash of all cookies (if called without any parameter)
4601         */
4602        self.cookies = function (name, value) {
4603            /* global escape: false, unescape: false */
4604            var cookieLength, cookieArray, cookie, i, index;
4605
4606            if (name) {
4607                if (value === undefined) {
4608                    rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
4609                        ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
4610                } else {
4611                    if (isString(value)) {
4612                        cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
4613                            ';path=' + cookiePath).length + 1;
4614
4615                        // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
4616                        // - 300 cookies
4617                        // - 20 cookies per unique domain
4618                        // - 4096 bytes per cookie
4619                        if (cookieLength > 4096) {
4620                            $log.warn("Cookie '" + name +
4621                                "' possibly not set or overflowed because it was too large (" +
4622                                cookieLength + " > 4096 bytes)!");
4623                        }
4624                    }
4625                }
4626            } else {
4627                if (rawDocument.cookie !== lastCookieString) {
4628                    lastCookieString = rawDocument.cookie;
4629                    cookieArray = lastCookieString.split("; ");
4630                    lastCookies = {};
4631
4632                    for (i = 0; i < cookieArray.length; i++) {
4633                        cookie = cookieArray[i];
4634                        index = cookie.indexOf('=');
4635                        if (index > 0) { //ignore nameless cookies
4636                            name = unescape(cookie.substring(0, index));
4637                            // the first value that is seen for a cookie is the most
4638                            // specific one.  values for the same cookie name that
4639                            // follow are for less specific paths.
4640                            if (lastCookies[name] === undefined) {
4641                                lastCookies[name] = unescape(cookie.substring(index + 1));
4642                            }
4643                        }
4644                    }
4645                }
4646                return lastCookies;
4647            }
4648        };
4649
4650
4651        /**
4652         * @name $browser#defer
4653         * @param {function()} fn A function, who's execution should be deferred.
4654         * @param {number=} [delay=0] of milliseconds to defer the function execution.
4655         * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
4656         *
4657         * @description
4658         * Executes a fn asynchronously via `setTimeout(fn, delay)`.
4659         *
4660         * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
4661         * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
4662         * via `$browser.defer.flush()`.
4663         *
4664         */
4665        self.defer = function (fn, delay) {
4666            var timeoutId;
4667            outstandingRequestCount++;
4668            timeoutId = setTimeout(function () {
4669                delete pendingDeferIds[timeoutId];
4670                completeOutstandingRequest(fn);
4671            }, delay || 0);
4672            pendingDeferIds[timeoutId] = true;
4673            return timeoutId;
4674        };
4675
4676
4677        /**
4678         * @name $browser#defer.cancel
4679         *
4680         * @description
4681         * Cancels a deferred task identified with `deferId`.
4682         *
4683         * @param {*} deferId Token returned by the `$browser.defer` function.
4684         * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
4685         *                    canceled.
4686         */
4687        self.defer.cancel = function (deferId) {
4688            if (pendingDeferIds[deferId]) {
4689                delete pendingDeferIds[deferId];
4690                clearTimeout(deferId);
4691                completeOutstandingRequest(noop);
4692                return true;
4693            }
4694            return false;
4695        };
4696
4697    }
4698
4699    function $BrowserProvider() {
4700        this.$get = ['$window', '$log', '$sniffer', '$document',
4701            function ($window, $log, $sniffer, $document) {
4702                return new Browser($window, $document, $log, $sniffer);
4703            }];
4704    }
4705
4706    /**
4707     * @ngdoc service
4708     * @name $cacheFactory
4709     *
4710     * @description
4711     * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
4712     * them.
4713     *
4714     * ```js
4715     *
4716     *  var cache = $cacheFactory('cacheId');
4717     *  expect($cacheFactory.get('cacheId')).toBe(cache);
4718     *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
4719     *
4720     *  cache.put("key", "value");
4721     *  cache.put("another key", "another value");
4722     *
4723     *  // We've specified no options on creation
4724     *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
4725     *
4726     * ```
4727     *
4728     *
4729     * @param {string} cacheId Name or id of the newly created cache.
4730     * @param {object=} options Options object that specifies the cache behavior. Properties:
4731     *
4732     *   - `{number=}` `capacity` — turns the cache into LRU cache.
4733     *
4734     * @returns {object} Newly created cache object with the following set of methods:
4735     *
4736     * - `{object}` `info()` — Returns id, size, and options of cache.
4737     * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
4738     *   it.
4739     * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
4740     * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
4741     * - `{void}` `removeAll()` — Removes all cached values.
4742     * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
4743     *
4744     * @example
4745     <example module="cacheExampleApp">
4746     <file name="index.jsp">
4747     <div ng-controller="CacheController">
4748     <input ng-model="newCacheKey" placeholder="Key">
4749     <input ng-model="newCacheValue" placeholder="Value">
4750     <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
4751
4752     <p ng-if="keys.length">Cached Values</p>
4753     <div ng-repeat="key in keys">
4754     <span ng-bind="key"></span>
4755     <span>: </span>
4756     <b ng-bind="cache.get(key)"></b>
4757     </div>
4758
4759     <p>Cache Info</p>
4760     <div ng-repeat="(key, value) in cache.info()">
4761     <span ng-bind="key"></span>
4762     <span>: </span>
4763     <b ng-bind="value"></b>
4764     </div>
4765     </div>
4766     </file>
4767     <file name="script.js">
4768     angular.module('cacheExampleApp', []).
4769     controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
4770           $scope.keys = [];
4771           $scope.cache = $cacheFactory('cacheId');
4772           $scope.put = function(key, value) {
4773             $scope.cache.put(key, value);
4774             $scope.keys.push(key);
4775           };
4776         }]);
4777     </file>
4778     <file name="style.css">
4779     p {
4780         margin: 10px 0 3px;
4781       }
4782     </file>
4783     </example>
4784     */
4785    function $CacheFactoryProvider() {
4786
4787        this.$get = function () {
4788            var caches = {};
4789
4790            function cacheFactory(cacheId, options) {
4791                if (cacheId in caches) {
4792                    throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
4793                }
4794
4795                var size = 0,
4796                    stats = extend({}, options, {id: cacheId}),
4797                    data = {},
4798                    capacity = (options && options.capacity) || Number.MAX_VALUE,
4799                    lruHash = {},
4800                    freshEnd = null,
4801                    staleEnd = null;
4802
4803                /**
4804                 * @ngdoc type
4805                 * @name $cacheFactory.Cache
4806                 *
4807                 * @description
4808                 * A cache object used to store and retrieve data, primarily used by
4809                 * {@link $http $http} and the {@link ng.directive:script script} directive to cache
4810                 * templates and other data.
4811                 *
4812                 * ```js
4813                 *  angular.module('superCache')
4814                 *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
4815       *      return $cacheFactory('super-cache');
4816       *    }]);
4817                 * ```
4818                 *
4819                 * Example test:
4820                 *
4821                 * ```js
4822                 *  it('should behave like a cache', inject(function(superCache) {
4823       *    superCache.put('key', 'value');
4824       *    superCache.put('another key', 'another value');
4825       *
4826       *    expect(superCache.info()).toEqual({
4827       *      id: 'super-cache',
4828       *      size: 2
4829       *    });
4830       *
4831       *    superCache.remove('another key');
4832       *    expect(superCache.get('another key')).toBeUndefined();
4833       *
4834       *    superCache.removeAll();
4835       *    expect(superCache.info()).toEqual({
4836       *      id: 'super-cache',
4837       *      size: 0
4838       *    });
4839       *  }));
4840                 * ```
4841                 */
4842                return caches[cacheId] = {
4843
4844                    /**
4845                     * @ngdoc method
4846                     * @name $cacheFactory.Cache#put
4847                     * @function
4848                     *
4849                     * @description
4850                     * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
4851                     * retrieved later, and incrementing the size of the cache if the key was not already
4852                     * present in the cache. If behaving like an LRU cache, it will also remove stale
4853                     * entries from the set.
4854                     *
4855                     * It will not insert undefined values into the cache.
4856                     *
4857                     * @param {string} key the key under which the cached data is stored.
4858                     * @param {*} value the value to store alongside the key. If it is undefined, the key
4859                     *    will not be stored.
4860                     * @returns {*} the value stored.
4861                     */
4862                    put: function (key, value) {
4863                        if (capacity < Number.MAX_VALUE) {
4864                            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
4865
4866                            refresh(lruEntry);
4867                        }
4868
4869                        if (isUndefined(value)) return;
4870                        if (!(key in data)) size++;
4871                        data[key] = value;
4872
4873                        if (size > capacity) {
4874                            this.remove(staleEnd.key);
4875                        }
4876
4877                        return value;
4878                    },
4879
4880                    /**
4881                     * @ngdoc method
4882                     * @name $cacheFactory.Cache#get
4883                     * @function
4884                     *
4885                     * @description
4886                     * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
4887                     *
4888                     * @param {string} key the key of the data to be retrieved
4889                     * @returns {*} the value stored.
4890                     */
4891                    get: function (key) {
4892                        if (capacity < Number.MAX_VALUE) {
4893                            var lruEntry = lruHash[key];
4894
4895                            if (!lruEntry) return;
4896
4897                            refresh(lruEntry);
4898                        }
4899
4900                        return data[key];
4901                    },
4902
4903
4904                    /**
4905                     * @ngdoc method
4906                     * @name $cacheFactory.Cache#remove
4907                     * @function
4908                     *
4909                     * @description
4910                     * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
4911                     *
4912                     * @param {string} key the key of the entry to be removed
4913                     */
4914                    remove: function (key) {
4915                        if (capacity < Number.MAX_VALUE) {
4916                            var lruEntry = lruHash[key];
4917
4918                            if (!lruEntry) return;
4919
4920                            if (lruEntry == freshEnd) freshEnd = lruEntry.p;
4921                            if (lruEntry == staleEnd) staleEnd = lruEntry.n;
4922                            link(lruEntry.n, lruEntry.p);
4923
4924                            delete lruHash[key];
4925                        }
4926
4927                        delete data[key];
4928                        size--;
4929                    },
4930
4931
4932                    /**
4933                     * @ngdoc method
4934                     * @name $cacheFactory.Cache#removeAll
4935                     * @function
4936                     *
4937                     * @description
4938                     * Clears the cache object of any entries.
4939                     */
4940                    removeAll: function () {
4941                        data = {};
4942                        size = 0;
4943                        lruHash = {};
4944                        freshEnd = staleEnd = null;
4945                    },
4946
4947
4948                    /**
4949                     * @ngdoc method
4950                     * @name $cacheFactory.Cache#destroy
4951                     * @function
4952                     *
4953                     * @description
4954                     * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
4955                     * removing it from the {@link $cacheFactory $cacheFactory} set.
4956                     */
4957                    destroy: function () {
4958                        data = null;
4959                        stats = null;
4960                        lruHash = null;
4961                        delete caches[cacheId];
4962                    },
4963
4964
4965                    /**
4966                     * @ngdoc method
4967                     * @name $cacheFactory.Cache#info
4968                     * @function
4969                     *
4970                     * @description
4971                     * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
4972                     *
4973                     * @returns {object} an object with the following properties:
4974                     *   <ul>
4975                     *     <li>**id**: the id of the cache instance</li>
4976                     *     <li>**size**: the number of entries kept in the cache instance</li>
4977                     *     <li>**...**: any additional properties from the options object when creating the
4978                     *       cache.</li>
4979                     *   </ul>
4980                     */
4981                    info: function () {
4982                        return extend({}, stats, {size: size});
4983                    }
4984                };
4985
4986
4987                /**
4988                 * makes the `entry` the freshEnd of the LRU linked list
4989                 */
4990                function refresh(entry) {
4991                    if (entry != freshEnd) {
4992                        if (!staleEnd) {
4993                            staleEnd = entry;
4994                        } else if (staleEnd == entry) {
4995                            staleEnd = entry.n;
4996                        }
4997
4998                        link(entry.n, entry.p);
4999                        link(entry, freshEnd);
5000                        freshEnd = entry;
5001                        freshEnd.n = null;
5002                    }
5003                }
5004
5005
5006                /**
5007                 * bidirectionally links two entries of the LRU linked list
5008                 */
5009                function link(nextEntry, prevEntry) {
5010                    if (nextEntry != prevEntry) {
5011                        if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
5012                        if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
5013                    }
5014                }
5015            }
5016
5017
5018            /**
5019             * @ngdoc method
5020             * @name $cacheFactory#info
5021             *
5022             * @description
5023             * Get information about all the of the caches that have been created
5024             *
5025             * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
5026             */
5027            cacheFactory.info = function () {
5028                var info = {};
5029                forEach(caches, function (cache, cacheId) {
5030                    info[cacheId] = cache.info();
5031                });
5032                return info;
5033            };
5034
5035
5036            /**
5037             * @ngdoc method
5038             * @name $cacheFactory#get
5039             *
5040             * @description
5041             * Get access to a cache object by the `cacheId` used when it was created.
5042             *
5043             * @param {string} cacheId Name or id of a cache to access.
5044             * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
5045             */
5046            cacheFactory.get = function (cacheId) {
5047                return caches[cacheId];
5048            };
5049
5050
5051            return cacheFactory;
5052        };
5053    }
5054
5055    /**
5056     * @ngdoc service
5057     * @name $templateCache
5058     *
5059     * @description
5060     * The first time a template is used, it is loaded in the template cache for quick retrieval. You
5061     * can load templates directly into the cache in a `script` tag, or by consuming the
5062     * `$templateCache` service directly.
5063     *
5064     * Adding via the `script` tag:
5065     *
5066     * ```html
5067     *   <script type="text/ng-template" id="templateId.html">
5068     *     <p>This is the content of the template</p>
5069     *   </script>
5070     * ```
5071     *
5072     * **Note:** the `script` tag containing the template does not need to be included in the `head` of
5073     * the document, but it must be below the `ng-app` definition.
5074     *
5075     * Adding via the $templateCache service:
5076     *
5077     * ```js
5078     * var myApp = angular.module('myApp', []);
5079     * myApp.run(function($templateCache) {
5080 *   $templateCache.put('templateId.html', 'This is the content of the template');
5081 * });
5082     * ```
5083     *
5084     * To retrieve the template later, simply use it in your HTML:
5085     * ```html
5086     * <div ng-include=" 'templateId.html' "></div>
5087     * ```
5088     *
5089     * or get it via Javascript:
5090     * ```js
5091     * $templateCache.get('templateId.html')
5092     * ```
5093     *
5094     * See {@link ng.$cacheFactory $cacheFactory}.
5095     *
5096     */
5097    function $TemplateCacheProvider() {
5098        this.$get = ['$cacheFactory', function ($cacheFactory) {
5099            return $cacheFactory('templates');
5100        }];
5101    }
5102
5103    /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
5104     *
5105     * DOM-related variables:
5106     *
5107     * - "node" - DOM Node
5108     * - "element" - DOM Element or Node
5109     * - "$node" or "$element" - jqLite-wrapped node or element
5110     *
5111     *
5112     * Compiler related stuff:
5113     *
5114     * - "linkFn" - linking fn of a single directive
5115     * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
5116     * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
5117     * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
5118     */
5119
5120
5121    /**
5122     * @ngdoc service
5123     * @name $compile
5124     * @function
5125     *
5126     * @description
5127     * Compiles an HTML string or DOM into a template and produces a template function, which
5128     * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
5129     *
5130     * The compilation is a process of walking the DOM tree and matching DOM elements to
5131     * {@link ng.$compileProvider#directive directives}.
5132     *
5133     * <div class="alert alert-warning">
5134     * **Note:** This document is an in-depth reference of all directive options.
5135     * For a gentle introduction to directives with examples of common use cases,
5136     * see the {@link guide/directive directive guide}.
5137     * </div>
5138     *
5139     * ## Comprehensive Directive API
5140     *
5141     * There are many different options for a directive.
5142     *
5143     * The difference resides in the return value of the factory function.
5144     * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
5145     * or just the `postLink` function (all other properties will have the default values).
5146     *
5147     * <div class="alert alert-success">
5148     * **Best Practice:** It's recommended to use the "directive definition object" form.
5149     * </div>
5150     *
5151     * Here's an example directive declared with a Directive Definition Object:
5152     *
5153     * ```js
5154     *   var myModule = angular.module(...);
5155     *
5156     *   myModule.directive('directiveName', function factory(injectables) {
5157 *     var directiveDefinitionObject = {
5158 *       priority: 0,
5159 *       template: '<div></div>
5159', // or // function(tElement, tAttrs) { ... },
5160 *       // or
5161 *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
5162 *       replace: false,
5163 *       transclude: false,
5164 *       restrict: 'A',
5165 *       scope: false,
5166 *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
5167 *       controllerAs: 'stringAlias',
5168 *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
5169 *       compile: function compile(tElement, tAttrs, transclude) {
5170 *         return {
5171 *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5172 *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
5173 *         }
5174 *         // or
5175 *         // return function postLink( ... ) { ... }
5176 *       },
5177 *       // or
5178 *       // link: {
5179 *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
5180 *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
5181 *       // }
5182 *       // or
5183 *       // link: function postLink( ... ) { ... }
5184 *     };
5185 *     return directiveDefinitionObject;
5186 *   });
5187     * ```
5188     *
5189     * <div class="alert alert-warning">
5190     * **Note:** Any unspecified options will use the default value. You can see the default values below.
5191     * </div>
5192     *
5193     * Therefore the above can be simplified as:
5194     *
5195     * ```js
5196     *   var myModule = angular.module(...);
5197     *
5198     *   myModule.directive('directiveName', function factory(injectables) {
5199 *     var directiveDefinitionObject = {
5200 *       link: function postLink(scope, iElement, iAttrs) { ... }
5201 *     };
5202 *     return directiveDefinitionObject;
5203 *     // or
5204 *     // return function postLink(scope, iElement, iAttrs) { ... }
5205 *   });
5206     * ```
5207     *
5208     *
5209     *
5210     * ### Directive Definition Object
5211     *
5212     * The directive definition object provides instructions to the {@link ng.$compile
5213 * compiler}. The attributes are:
5214     *
5215     * #### `priority`
5216     * When there are multiple directives defined on a single DOM element, sometimes it
5217     * is necessary to specify the order in which the directives are applied. The `priority` is used
5218     * to sort the directives before their `compile` functions get called. Priority is defined as a
5219     * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
5220     * are also run in priority order, but post-link functions are run in reverse order. The order
5221     * of directives with the same priority is undefined. The default priority is `0`.
5222     *
5223     * #### `terminal`
5224     * If set to true then the current `priority` will be the last set of directives
5225     * which will execute (any directives at the current priority will still execute
5226     * as the order of execution on same `priority` is undefined).
5227     *
5228     * #### `scope`
5229     * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
5230     * same element request a new scope, only one new scope is created. The new scope rule does not
5231     * apply for the root of the template since the root of the template always gets a new scope.
5232     *
5233     * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
5234     * normal scope in that it does not prototypically inherit from the parent scope. This is useful
5235     * when creating reusable components, which should not accidentally read or modify data in the
5236     * parent scope.
5237     *
5238     * The 'isolate' scope takes an object hash which defines a set of local scope properties
5239     * derived from the parent scope. These local properties are useful for aliasing values for
5240     * templates. Locals definition is a hash of local scope property to its source:
5241     *
5242     * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
5243     *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
5244     *   attribute name is assumed to be the same as the local name.
5245     *   Given `<widget my-attr="hello {{name}}">` and widget definition
5246     *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
5247     *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
5248     *   `localName` property on the widget scope. The `name` is read from the parent scope (not
5249     *   component scope).
5250     *
5251     * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
5252     *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
5253     *   name is specified then the attribute name is assumed to be the same as the local name.
5254     *   Given `<widget my-attr="parentModel">` and widget definition of
5255     *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
5256     *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
5257     *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
5258     *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
5259     *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
5260     *
5261     * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
5262     *   If no `attr` name is specified then the attribute name is assumed to be the same as the
5263     *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
5264     *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
5265     *   a function wrapper for the `count = count + value` expression. Often it's desirable to
5266     *   pass data from the isolated scope via an expression and to the parent scope, this can be
5267     *   done by passing a map of local variable names and values into the expression wrapper fn.
5268     *   For example, if the expression is `increment(amount)` then we can specify the amount value
5269     *   by calling the `localFn` as `localFn({amount: 22})`.
5270     *
5271     *
5272     *
5273     * #### `controller`
5274     * Controller constructor function. The controller is instantiated before the
5275     * pre-linking phase and it is shared with other directives (see
5276     * `require` attribute). This allows the directives to communicate with each other and augment
5277     * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
5278     *
5279     * * `$scope` - Current scope associated with the element
5280     * * `$element` - Current element
5281     * * `$attrs` - Current attributes object for the element
5282     * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
5283     *    The scope can be overridden by an optional first argument.
5284     *   `function([scope], cloneLinkingFn)`.
5285     *
5286     *
5287     * #### `require`
5288     * Require another directive and inject its controller as the fourth argument to the linking function. The
5289     * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
5290     * injected argument will be an array in corresponding order. If no such directive can be
5291     * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
5292     *
5293     * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5294     * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5295     * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5296     * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
5297     *   `link` fn if not found.
5298     *
5299     *
5300     * #### `controllerAs`
5301     * Controller alias at the directive scope. An alias for the controller so it
5302     * can be referenced at the directive template. The directive needs to define a scope for this
5303     * configuration to be used. Useful in the case when directive is used as component.
5304     *
5305     *
5306     * #### `restrict`
5307     * String of subset of `EACM` which restricts the directive to a specific directive
5308     * declaration style. If omitted, the default (attributes only) is used.
5309     *
5310     * * `E` - Element name: `<my-directive></my-directive>`
5311     * * `A` - Attribute (default): `<div my-directive="exp"></div>`
5312     * * `C` - Class: `<div class="my-directive: exp;"></div>`
5313     * * `M` - Comment: `<!-- directive: my-directive exp -->`
5314     *
5315     *
5316     * #### `template`
5317     * replace the current element with the contents of the HTML. The replacement process
5318     * migrates all of the attributes / classes from the old element to the new one. See the
5319     * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
5320 * Directives Guide} for an example.
5321     *
5322     * You can specify `template` as a string representing the template or as a function which takes
5323     * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
5324     * returns a string value representing the template.
5325     *
5326     *
5327     * #### `templateUrl`
5328     * Same as `template` but the template is loaded from the specified URL. Because
5329     * the template loading is asynchronous the compilation/linking is suspended until the template
5330     * is loaded.
5331     *
5332     * You can specify `templateUrl` as a string representing the URL or as a function which takes two
5333     * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
5334     * a string value representing the url.  In either case, the template URL is passed through {@link
5335        * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
5336     *
5337     *
5338     * #### `replace`
5339     * specify where the template should be inserted. Defaults to `false`.
5340     *
5341     * * `true` - the template will replace the current element.
5342     * * `false` - the template will replace the contents of the current element.
5343     *
5344     *
5345     * #### `transclude`
5346     * compile the content of the element and make it available to the directive.
5347     * Typically used with {@link ng.directive:ngTransclude
5348 * ngTransclude}. The advantage of transclusion is that the linking function receives a
5349     * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
5350     * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
5351     * scope. This makes it possible for the widget to have private state, and the transclusion to
5352     * be bound to the parent (pre-`isolate`) scope.
5353     *
5354     * * `true` - transclude the content of the directive.
5355     * * `'element'` - transclude the whole element including any directives defined at lower priority.
5356     *
5357     *
5358     * #### `compile`
5359     *
5360     * ```js
5361     *   function compile(tElement, tAttrs, transclude) { ... }
5362     * ```
5363     *
5364     * The compile function deals with transforming the template DOM. Since most directives do not do
5365     * template transformation, it is not used often. Examples that require compile functions are
5366     * directives that transform template DOM, such as {@link
5367        * api/ng.directive:ngRepeat ngRepeat}, or load the contents
5368     * asynchronously, such as {@link ngRoute.directive:ngView ngView}. The
5369     * compile function takes the following arguments.
5370     *
5371     *   * `tElement` - template element - The element where the directive has been declared. It is
5372     *     safe to do template transformation on the element and child elements only.
5373     *
5374     *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
5375     *     between all directive compile functions.
5376     *
5377     *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
5378     *
5379     * <div class="alert alert-warning">
5380     * **Note:** The template instance and the link instance may be different objects if the template has
5381     * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
5382     * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
5383     * should be done in a linking function rather than in a compile function.
5384     * </div>
5385
5386     * <div class="alert alert-warning">
5387     * **Note:** The compile function cannot handle directives that recursively use themselves in their
5388     * own templates or compile functions. Compiling these directives results in an infinite loop and a
5389     * stack overflow errors.
5390     *
5391     * This can be avoided by manually using $compile in the postLink function to imperatively compile
5392     * a directive's template instead of relying on automatic template compilation via `template` or
5393     * `templateUrl` declaration or manual compilation inside the compile function.
5394     * </div>
5395     *
5396     * <div class="alert alert-error">
5397     * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
5398     *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
5399     *   to the link function instead.
5400     * </div>
5401
5402     * A compile function can have a return value which can be either a function or an object.
5403     *
5404     * * returning a (post-link) function - is equivalent to registering the linking function via the
5405     *   `link` property of the config object when the compile function is empty.
5406     *
5407     * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
5408     *   control when a linking function should be called during the linking phase. See info about
5409     *   pre-linking and post-linking functions below.
5410     *
5411     *
5412     * #### `link`
5413     * This property is used only if the `compile` property is not defined.
5414     *
5415     * ```js
5416     *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
5417     * ```
5418     *
5419     * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
5420     * executed after the template has been cloned. This is where most of the directive logic will be
5421     * put.
5422     *
5423     *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
5424     *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
5425     *
5426     *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
5427     *     manipulate the children of the element only in `postLink` function since the children have
5428     *     already been linked.
5429     *
5430     *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
5431     *     between all directive linking functions.
5432     *
5433     *   * `controller` - a controller instance - A controller instance if at least one directive on the
5434     *     element defines a controller. The controller is shared among all the directives, which allows
5435     *     the directives to use the controllers as a communication channel.
5436     *
5437     *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
5438     *     The scope can be overridden by an optional first argument. This is the same as the `$transclude`
5439     *     parameter of directive controllers.
5440     *     `function([scope], cloneLinkingFn)`.
5441     *
5442     *
5443     * #### Pre-linking function
5444     *
5445     * Executed before the child elements are linked. Not safe to do DOM transformation since the
5446     * compiler linking function will fail to locate the correct elements for linking.
5447     *
5448     * #### Post-linking function
5449     *
5450     * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
5451     *
5452     * <a name="Attributes"></a>
5453     * ### Attributes
5454     *
5455     * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
5456     * `link()` or `compile()` functions. It has a variety of uses.
5457     *
5458     * accessing *Normalized attribute names:*
5459     * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
5460     * the attributes object allows for normalized access to
5461     *   the attributes.
5462     *
5463     * * *Directive inter-communication:* All directives share the same instance of the attributes
5464     *   object which allows the directives to use the attributes object as inter directive
5465     *   communication.
5466     *
5467     * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
5468     *   allowing other directives to read the interpolated value.
5469     *
5470     * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
5471     *   that contain interpolation (e.g. `src="{{bar}}
5471"`). Not only is this very efficient but it's also
5472     *   the only way to easily get the actual value because during the linking phase the interpolation
5473     *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
5474     *
5475     * ```js
5476     * function linkingFn(scope, elm, attrs, ctrl) {
5477 *   // get the attribute value
5478 *   console.log(attrs.ngModel);
5479 *
5480 *   // change the attribute
5481 *   attrs.$set('ngModel', 'new value');
5482 *
5483 *   // observe changes to interpolated attribute
5484 *   attrs.$observe('ngModel', function(value) {
5485 *     console.log('ngModel has changed value to ' + value);
5486 *   });
5487 * }
5488     * ```
5489     *
5490     * Below is an example using `$compileProvider`.
5491     *
5492     * <div class="alert alert-warning">
5493     * **Note**: Typically directives are registered with `module.directive`. The example below is
5494     * to illustrate how `$compile` works.
5495     * </div>
5496     *
5497     <example module="compile">
5498     <file name="index.jsp">
5499     <script>
5500     angular.module('compile', [], function($compileProvider) {
5501        // configure new 'compile' directive by passing a directive
5502        // factory function. The factory function injects the '$compile'
5503        $compileProvider.directive('compile', function($compile) {
5504          // directive factory creates a link function
5505          return function(scope, element, attrs) {
5506            scope.$watch(
5507              function(scope) {
5508                 // watch the 'compile' expression for changes
5509                return scope.$eval(attrs.compile);
5510              },
5511              function(value) {
5512                // when the 'compile' expression changes
5513                // assign it into the current DOM
5514                element.html(value);
5515
5516                // compile the new DOM and link it to the current
5517                // scope.
5518                // NOTE: we only compile .childNodes so that
5519                // we don't get into infinite loop compiling ourselves
5520                $compile(element.contents())(scope);
5521              }
5522            );
5523          };
5524        })
5525      });
5526
5527     function Ctrl($scope) {
5528        $scope.name = 'Angular';
5529        $scope.html = 'Hello {{name}}';
5530      }
5531     </script>
5532     <div ng-controller="Ctrl">
5533     <input ng-model="name"> <br>
5534     <textarea ng-model="html"></textarea> <br>
5535     <div compile="html"></div>
5536     </div>
5537     </file>
5538     <file name="protractor.js" type="protractor">
5539     it('should auto compile', function() {
5540       var textarea = $('textarea');
5541       var output = $('div[compile]');
5542       // The initial state reads 'Hello Angular'.
5543       expect(output.getText()).toBe('Hello Angular');
5544       textarea.clear();
5545       textarea.sendKeys('{{name}}!');
5546       expect(output.getText()).toBe('Angular!');
5547     });
5548     </file>
5549     </example>
5550
5551     *
5552     *
5553     * @param {string|DOMElement} element Element or HTML string to compile into a template function.
5554     * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
5555     * @param {number} maxPriority only apply directives lower than given priority (Only effects the
5556     *                 root element(s), not their children)
5557     * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
5558     * (a DOM element/tree) to a scope. Where:
5559     *
5560     *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
5561     *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
5562     *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
5563     *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
5564     *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
5565     *
5566     *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
5567     *      * `scope` - is the current scope with which the linking function is working with.
5568     *
5569     * Calling the linking function returns the element of the template. It is either the original
5570     * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
5571     *
5572     * After linking the view is not updated until after a call to $digest which typically is done by
5573     * Angular automatically.
5574     *
5575     * If you need access to the bound view, there are two ways to do it:
5576     *
5577     * - If you are not asking the linking function to clone the template, create the DOM element(s)
5578     *   before you send them to the compiler and keep this reference around.
5579     *   ```js
5580     *     var element = $compile('<p>{{total}}</p>')(scope);
5581     *   ```
5582     *
5583     * - if on the other hand, you need the element to be cloned, the view reference from the original
5584     *   example would not point to the clone, but rather to the original template that was cloned. In
5585     *   this case, you can access the clone via the cloneAttachFn:
5586     *   ```js
5587     *     var templateElement = angular.element('<p>{{total}}</p>'),
5588     *         scope = ....;
5589     *
5590     *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
5591 *       //attach the clone to DOM document at the right place
5592 *     });
5593     *
5594     *     //now we have reference to the cloned DOM via `clonedElement`
5595     *   ```
5596     *
5597     *
5598     * For information on how the compiler works, see the
5599     * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
5600     */
5601
5602    var $compileMinErr = minErr('$compile');
5603
5604    /**
5605     * @ngdoc provider
5606     * @name $compileProvider
5607     * @function
5608     *
vendor: 4,137 bytes, lines 5609-5689
5609     * @description
5610     */
5611    $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
5612    function $CompileProvider($provide, $$sanitizeUriProvider) {
5613        var hasDirectives = {},
5614            Suffix = 'Directive',
5615            COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
5616            CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
5617
5618        // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
5619        // The assumption is that future DOM event attribute names will begin with
5620        // 'on' and be composed of only English letters.
5621        var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
5622
5623        /**
5624         * @ngdoc method
5625         * @name $compileProvider#directive
5626         * @function
5627         *
5628         * @description
5629         * Register a new directive with the compiler.
5630         *
5631         * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
5632         *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
5633         *    names and the values are the factories.
5634         * @param {Function|Array} directiveFactory An injectable directive factory function. See
5635         *    {@link guide/directive} for more info.
5636         * @returns {ng.$compileProvider} Self for chaining.
5637         */
5638        this.directive = function registerDirective(name, directiveFactory) {
5639            assertNotHasOwnProperty(name, 'directive');
5640            if (isString(name)) {
5641                assertArg(directiveFactory, 'directiveFactory');
5642                if (!hasDirectives.hasOwnProperty(name)) {
5643                    hasDirectives[name] = [];
5644                    $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
5645                        function ($injector, $exceptionHandler) {
5646                            var directives = [];
5647                            forEach(hasDirectives[name], function (directiveFactory, index) {
5648                                try {
5649                                    var directive = $injector.invoke(directiveFactory);
5650                                    if (isFunction(directive)) {
5651                                        directive = { compile: valueFn(directive) };
5652                                    } else if (!directive.compile && directive.link) {
5653                                        directive.compile = valueFn(directive.link);
5654                                    }
5655                                    directive.priority = directive.priority || 0;
5656                                    directive.index = index;
5657                                    directive.name = directive.name || name;
5658                                    directive.require = directive.require || (directive.controller && directive.name);
5659                                    directive.restrict = directive.restrict || 'A';
5660                                    directives.push(directive);
5661                                } catch (e) {
5662                                    $exceptionHandler(e);
5663                                }
5664                            });
5665                            return directives;
5666                        }]);
5667                }
5668                hasDirectives[name].push(directiveFactory);
5669            } else {
5670                forEach(name, reverseParams(registerDirective));
5671            }
5672            return this;
5673        };
5674
5675
5676        /**
5677         * @ngdoc method
5678         * @name $compileProvider#aHrefSanitizationWhitelist
5679         * @function
5680         *
5681         * @description
5682         * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5683         * urls during a[href] sanitization.
5684         *
5685         * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5686         *
5687         * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
5688         * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
5689         * regular expression. If a match is found, the original url is 
5689written into the dom. Otherwise,
5690         * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5691         *
5692         * @param {RegExp=} regexp New regexp to whitelist urls with.
5693         * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5694         *    chaining otherwise.
5695         */
5696        this.aHrefSanitizationWhitelist = function (regexp) {
5697            if (isDefined(regexp)) {
5698                $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
5699                return this;
5700            } else {
5701                return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
5702            }
5703        };
5704
5705
5706        /**
5707         * @ngdoc method
5708         * @name $compileProvider#imgSrcSanitizationWhitelist
5709         * @function
5710         *
5711         * @description
5712         * Retrieves or overrides the default regular expression that is used for whitelisting of safe
5713         * urls during img[src] sanitization.
5714         *
5715         * The sanitization is a security measure aimed at prevent XSS attacks via html links.
5716         *
5717         * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
5718         * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
5719         * regular expression. If a match is found, the original url is written into the dom. Otherwise,
5720         * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
5721         *
5722         * @param {RegExp=} regexp New regexp to whitelist urls with.
5723         * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
5724         *    chaining otherwise.
5725         */
5726        this.imgSrcSanitizationWhitelist = function (regexp) {
5727            if (isDefined(regexp)) {
5728                $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
5729                return this;
5730            } else {
5731                return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
5732            }
5733        };
5734
5735        this.$get = [
5736            '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
5737            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
5738            function ($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse, $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
5739
5740                var Attributes = function (element, attr) {
5741                    this.$$element = element;
5742                    this.$attr = attr || {};
5743                };
5744
5745                Attributes.prototype = {
5746                    $normalize: directiveNormalize,
5747
5748
5749                    /**
5750                     * @ngdoc method
5751                     * @name $compile.directive.Attributes#$addClass
5752                     * @function
5753                     *
5754                     * @description
5755                     * Adds the CSS class value specified by the classVal parameter to the element. If animations
5756                     * are enabled then an animation will be triggered for the class addition.
5757                     *
5758                     * @param {string} classVal The className value that will be added to the element
5759                     */
5760                    $addClass: function (classVal) {
5761                        if (classVal && classVal.length > 0) {
5762                            $animate.addClass(this.$$element, classVal);
5763                        }
5764                    },
5765
5766                    /**
5767                     * @ngdoc method
5768                     * @name $compile.directive.Attributes#$removeClass
5769                     * @function
5770                     *
5771                     * @description
5772                     * Removes the CSS class value specified by the classVal parameter from the element. If
5773                     * animations are enabled then an animation will be triggered for the class removal.
5774                     *
5775                     * @param {string} classVal The className value that will be removed from the element
5776                     */
5777                    $removeClass: function (classVal) {
5778                        if (classVal && classVal.length > 0) {
5779                            $animate.removeClass(this.$$element, classVal);
5780                        }
5781                    },
5782
5783                    /**
5784                     * @ngdoc method
5785                     * @name $compile.directive.Attributes#$updateClass
5786                     * @function
5787                     *
5788                     * @description
5789                     * Adds and removes the appropriate CSS class values to the element based on the difference
5790                     * between the new and old CSS class values (specified as newClasses and oldClasses).
5791                     *
5792                     * @param {string} newClasses The current CSS className value
5793                     * @param {string} oldClasses The former CSS className value
5794                     */
5795                    $updateClass: function (newClasses, oldClasses) {
5796                        var toAdd = tokenDifference(newClasses, oldClasses);
5797                        var toRemove = tokenDifference(oldClasses, newClasses);
5798
5799                        if (toAdd.length === 0) {
5800                            $animate.removeClass(this.$$element, toRemove);
5801                        } else if (toRemove.length === 0) {
5802                            $animate.addClass(this.$$element, toAdd);
5803                        } else {
5804                            $animate.setClass(this.$$element, toAdd, toRemove);
5805                        }
5806                    },
5807
5808                    /**
5809                     * Set a normalized attribute on the element in a way such that all directives
5810                     * can share the attribute. This function properly handles boolean attributes.
5811                     * @param {string} key Normalized key. (ie ngAttribute)
5812                     * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
5813                     * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
5814                     *     Defaults to true.
5815                     * @param {string=} attrName Optional none normalized name. Defaults to key.
5816                     */
5817                    $set: function (key, value, writeAttr, attrName) {
5818                        // TODO: decide whether or not to throw an error if "class"
5819                        //is set through this function since it may cause $updateClass to
5820                        //become unstable.
5821
5822                        var booleanKey = getBooleanAttrName(this.$$element[0], key),
5823                            normalizedVal,
5824                            nodeName;
5825
5826                        if (booleanKey) {
5827                            this.$$element.prop(key, value);
5828                            attrName = booleanKey;
5829                        }
5830
5831                        this[key] = value;
5832
5833                        // translate normalized key to actual key
5834                        if (attrName) {
5835                            this.$attr[key] = attrName;
5836                        } else {
5837                            attrName = this.$attr[key];
5838                            if (!attrName) {
5839                                this.$attr[key] = attrName = snake_case(key, '-');
5840                            }
5841                        }
5842
5843                        nodeName = nodeName_(this.$$element);
5844
5845                        // sanitize a[href] and img[src] values
5846                        if ((nodeName === 'A' && key === 'href') ||
5847                            (nodeName === 'IMG' && key === 'src')) {
5848                            this[key] = value = $$sanitizeUri(value, key === 'src');
5849                        }
5850
5851                        if (writeAttr !== false) {
5852                            if (value === null || value === undefined) {
5853                                this.$$element.removeAttr(attrName);
5854                            } else {
5855                                this.$$element.attr(attrName, value);
5856                            }
5857                        }
5858
5859                        // fire observers
5860                        var $$observers = this.$$observers;
5861                        $$observers && forEach($$observers[key], function (fn) {
5862                            try {
5863                                fn(value);
5864                            } catch (e) {
5865                                $exceptionHandler(e);
5866                            }
5867                        });
5868                    },
5869
5870
5871                    /**
5872                     * @ngdoc method
5873                     * @name $compile.directive.Attributes#$observe
5874                     * @function
5875                     *
5876                     * @description
5877                     * Observes an interpolated attribute.
5878                     *
5879                     * The observer function will be invoked once during the next `$digest` following
5880                     * compilation. The observer is then invoked whenever the interpolated value
5881                     * changes.
5882                     *
5883                     * @param {string} key Normalized key. (ie ngAttribute) .
5884                     * @param {function(interpolatedValue)} fn Function that will be called whenever
5885                     the interpolated value of the attribute changes.
5886                     *        See the {@link guide/directive#Attributes Directives} guide for more info.
5887                     * @returns {function()} the `fn` parameter.
5888                     */
5889                    $observe: function (key, fn) {
5890                        var attrs = this,
5891                            $$observers = (attrs.$$observers || (attrs.$$observers = {})),
5892                            listeners = ($$observers[key] || ($$observers[key] = []));
5893
5894                        listeners.push(fn);
5895                        $rootScope.$evalAsync(function () {
5896                            if (!listeners.$$inter) {
5897                                // no one registered attribute interpolation function, so lets call it manually
5898                                fn(attrs[key]);
5899                            }
5900                        });
5901                        return fn;
5902                    }
5903                };
5904
5905                var startSymbol = $interpolate.startSymbol(),
5906                    endSymbol = $interpolate.endSymbol(),
5907                    denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
5908                        ? identity
5909                        : function denormalizeTemplate(template) {
5910                        return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5911                    },
5912                    NG_ATTR_BINDING = /^ngAttr[A-Z]/;
5913
5914
5915                return compile;
5916
5917                //================================
5918
5919                function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
5920                    if (!($compileNodes instanceof jqLite)) {
5921                        // jquery always rewraps, whereas we need to preserve the original selector so that we can
5922                        // modify it.
5923                        $compileNodes = jqLite($compileNodes);
5924                    }
5925                    // We can not compile top level text elements since text nodes can be merged and we will
5926                    // not be able to attach scope data to them, so we will wrap them in <span>
5927                    forEach($compileNodes, function (node, index) {
5928                        if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */) {
5929                            $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
5930                        }
5931                    });
5932                    var compositeLinkFn =
5933                        compileNodes($compileNodes, transcludeFn, $compileNodes,
5934                            maxPriority, ignoreDirective, previousCompileContext);
5935                    safeAddClass($compileNodes, 'ng-scope');
5936                    return function publicLinkFn(scope, cloneConnectFn, transcludeControllers) {
5937                        assertArg(scope, 'scope');
5938                        // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
5939                        // and sometimes changes the structure of the DOM.
5940                        var $linkNode = cloneConnectFn
5941                            ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
5942                            : $compileNodes;
5943
5944                        forEach(transcludeControllers, function (instance, name) {
5945                            $linkNode.data('$' + name + 'Controller', instance);
5946                        });
5947
5948                        // Attach scope only to non-text nodes.
5949                        for (var i = 0, ii = $linkNode.length; i < ii; i++) {
5950                            var node = $linkNode[i],
5951                                nodeType = node.nodeType;
5952                            if (nodeType === 1 /* element */ || nodeType === 9 /* document */) {
5953                                $linkNode.eq(i).data('$scope', scope);
5954                            }
5955                        }
5956
5957                        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
5958                        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
5959                        return $linkNode;
5960                    };
5961                }
5962
5963                function safeAddClass($element, className) {
5964                    try {
5965                        $element.addClass(className);
5966                    } catch (e) {
5967                        // ignore, since it means that we are trying to set class on
5968                        // SVG element, where class name is read-only.
5969                    }
5970                }
5971
5972                /**
5973                 * Compile function matches each node in nodeList against the directives. Once all directives
5974                 * for a particular node are collected their compile functions are executed. The compile
5975                 * functions return values - the linking functions - are combined into a composite linking
5976                 * function, which is the a linking function for the node.
5977                 *
5978                 * @param {NodeList} nodeList an array of nodes or NodeList to compile
5979                 * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
5980                 *        scope argument is auto-generated to the new child of the transcluded parent scope.
5981                 * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
5982                 *        the rootElement must be set the jqLite collection of the compile root. This is
5983                 *        needed so that the jqLite collection items can be replaced with widgets.
5984                 * @param {number=} maxPriority Max directive priority.
5985                 * @returns {Function} A composite linking function of all of the matched directives or null.
5986                 */
5987                function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, previousCompileContext) {
5988                    var linkFns = [],
5989                        attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound;
5990
5991                    for (var i = 0; i < nodeList.length; i++) {
5992                        attrs = new Attributes();
5993
5994                        // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
5995                        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
5996                            ignoreDirective);
5997
5998                        nodeLinkFn = (directives.length)
5999                            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
6000                            null, [], [], previousCompileContext)
6001                            : null;
6002
6003                        if (nodeLinkFn && nodeLinkFn.scope) {
6004                            safeAddClass(jqLite(nodeList[i]), 'ng-scope');
6005                        }
6006
6007                        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !(childNodes = nodeList[i].childNodes) || !childNodes.length)
6008                            ? null
6009                            : compileNodes(childNodes,
6010                            nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
6011
6012                        linkFns.push(nodeLinkFn, childLinkFn);
6013                        linkFnFound = linkFnFound || nodeLinkFn || childLinkFn;
6014                        //use the previous context only for the first element in the virtual group
6015                        previousCompileContext = null;
6016                    }
6017
6018                    // return a linking function if we have found anything, null otherwise
6019                    return linkFnFound ? compositeLinkFn : null;
6020
6021                    function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
6022                        var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
6023
6024                        // copy nodeList so that linking doesn't break due to live list updates.
6025                        var nodeListLength = nodeList.length,
6026                            stableNodeList = new Array(nodeListLength);
6027                        for (i = 0; i < nodeListLength; i++) {
6028                            stableNodeList[i] = nodeList[i];
6029                        }
6030
6031                        for (i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
6032                            node = stableNodeList[n];
6033                            nodeLinkFn = linkFns[i++];
6034                            childLinkFn = linkFns[i++];
6035                            $node = jqLite(node);
6036
6037                            if (nodeLinkFn) {
6038                                if (nodeLinkFn.scope) {
6039                                    childScope = scope.$new();
6040                                    $node.data('$scope', childScope);
6041                                } else {
6042                                    childScope = scope;
6043                                }
6044                                childTranscludeFn = nodeLinkFn.transclude;
6045                                if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
6046                                    nodeLinkFn(childLinkFn, childScope, node, $rootElement,
6047                                        createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
6048                                    );
6049                                } else {
6050                                    nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
6051                                }
6052                            } else if (childLinkFn) {
6053                                childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
6054                            }
6055                        }
6056                    }
6057                }
6058
6059                function createBoundTranscludeFn(scope, transcludeFn) {
6060                    return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
6061                        var scopeCreated = false;
6062
6063                        if (!transcludedScope) {
6064                            transcludedScope = scope.$new();
6065                            transcludedScope.$$transcluded = true;
6066                            scopeCreated = true;
6067                        }
6068
6069                        var clone = transcludeFn(transcludedScope, cloneFn, controllers);
6070                        if (scopeCreated) {
6071                            clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
6072                        }
6073                        return clone;
6074                    };
6075                }
6076
6077                /**
6078                 * Looks for directives on the given node and adds them to the directive collection which is
6079                 * sorted.
6080                 *
6081                 * @param node Node to search.
6082                 * @param directives An array to which the directives are added to. This array is sorted before
6083                 *        the function returns.
6084                 * @param attrs The shared attrs object which is used to populate the normalized attributes.
6085                 * @param {number=} maxPriority Max directive priority.
6086                 */
6087                function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
6088                    var nodeType = node.nodeType,
6089                        attrsMap = attrs.$attr,
6090                        match,
6091                        className;
6092
6093                    switch (nodeType) {
6094                        case 1: /* Element */
6095                            // use the node name: <directive>
6096                            addDirective(directives,
6097                                directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6098
6099                            // iterate over the attributes
6100                            for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
6101                                     j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6102                                var attrStartName = false;
6103                                var attrEndName = false;
6104
6105                                attr = nAttrs[j];
6106                                if (!msie || msie >= 8 || attr.specified) {
6107                                    name = attr.name;
6108                                    // support ngAttr attribute binding
6109                                    ngAttrName = directiveNormalize(name);
6110                                    if (NG_ATTR_BINDING.test(ngAttrName)) {
6111                                        name = snake_case(ngAttrName.substr(6), '-');
6112                                    }
6113
6114                                    var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
6115                                    if (ngAttrName === directiveNName + 'Start') {
6116                                        attrStartName = name;
6117                                        attrEndName = name.substr(0, name.length - 5) + 'end';
6118                                        name = name.substr(0, name.length - 6);
6119                                    }
6120
6121                                    nName = directiveNormalize(name.toLowerCase());
6122                                    attrsMap[nName] = name;
6123                                    attrs[nName] = value = trim(attr.value);
6124                                    if (getBooleanAttrName(node, nName)) {
6125                                        attrs[nName] = true; // presence means true
6126                                    }
6127                                    addAttrInterpolateDirective(node, directives, value, nName);
6128                                    addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
6129                                        attrEndName);
6130                                }
6131                            }
6132
6133                            // use class as directive
6134                            className = node.className;
6135                            if (isString(className) && className !== '') {
6136                                while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
6137                                    nName = directiveNormalize(match[2]);
6138                                    if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
6139                                        attrs[nName] = trim(match[3]);
6140                                    }
6141                                    className = className.substr(match.index + match[0].length);
6142                                }
6143                            }
6144                            break;
6145                        case 3: /* Text Node */
6146                            addTextInterpolateDirective(directives, node.nodeValue);
6147                            break;
6148                        case 8: /* Comment */
6149                            try {
6150                                match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
6151                                if (match) {
6152                                    nName = directiveNormalize(match[1]);
6153                                    if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
6154                                        attrs[nName] = trim(match[2]);
6155                                    }
6156                                }
6157                            } catch (e) {
6158                                // turns out that under some circumstances IE9 throws errors when one attempts to read
6159                                // comment's node value.
6160                                // Just ignore it and continue. (Can't seem to reproduce in test case.)
6161                            }
6162                            break;
6163                    }
6164
6165                    directives.sort(byPriority);
6166                    return directives;
6167                }
6168
6169                /**
6170                 * Given a node with an directive-start it collects all of the siblings until it finds
6171                 * directive-end.
6172                 * @param node
6173                 * @param attrStart
6174                 * @param attrEnd
6175                 * @returns {*}
6176                 */
6177                function groupScan(node, attrStart, attrEnd) {
6178                    var nodes = [];
6179                    var depth = 0;
6180                    if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
6181                        var startNode = node;
6182                        do {
6183                            if (!node) {
6184                                throw $compileMinErr('uterdir',
6185                                    "Unterminated attribute, found '{0}' but no matching '{1}' found.",
6186                                    attrStart, attrEnd);
6187                            }
6188                            if (node.nodeType == 1 /** Element **/) {
6189                                if (node.hasAttribute(attrStart)) depth++;
6190                                if (node.hasAttribute(attrEnd)) depth--;
6191                            }
6192                            nodes.push(node);
6193                            node = node.nextSibling;
6194                        } while (depth > 0);
6195                    } else {
6196                        nodes.push(node);
6197                    }
6198
6199                    return jqLite(nodes);
6200                }
6201
6202                /**
6203                 * Wrapper for linking function which converts normal linking function into a grouped
6204                 * linking function.
6205                 * @param linkFn
6206                 * @param attrStart
6207                 * @param attrEnd
6208                 * @returns {Function}
6209                 */
6210                function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
6211                    return function (scope, element, attrs, controllers, transcludeFn) {
6212                        element = groupScan(element[0], attrStart, attrEnd);
6213                        return linkFn(scope, element, attrs, controllers, transcludeFn);
6214                    };
6215                }
6216
6217                /**
6218                 * Once the directives have been collected, their compile functions are executed. This method
6219                 * is responsible for inlining directive templates as well as terminating the application
6220                 * of the directives if the terminal directive has been reached.
6221                 *
6222                 * @param {Array} directives Array of collected directives to execute their compile function.
6223                 *        this needs to be pre-sorted by priority order.
6224                 * @param {Node} compileNode The raw DOM node to apply the compile functions to
6225                 * @param {Object} templateAttrs The shared attribute function
6226                 * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
6227                 *                                                  scope argument is auto-generated to the new
6228                 *                                                  child of the transcluded parent scope.
6229                 * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
6230                 *                              argument has the root jqLite array so that we can replace nodes
6231                 *                              on it.
6232                 * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
6233                 *                                           compiling the transclusion.
6234                 * @param {Array.<Function>} preLinkFns
6235                 * @param {Array.<Function>} postLinkFns
6236                 * @param {Object} previousCompileContext Context used for previous compilation of the current
6237                 *                                        node
6238                 * @returns {Function} linkFn
6239                 */
6240                function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, previousCompileContext) {
6241                    previousCompileContext = previousCompileContext || {};
6242
6243                    var terminalPriority = -Number.MAX_VALUE,
6244                        newScopeDirective,
6245                        controllerDirectives = previousCompileContext.controllerDirectives,
6246                        newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
6247                        templateDirective = previousCompileContext.templateDirective,
6248                        nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
6249                        hasTranscludeDirective = false,
6250                        hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
6251                        $compileNode = templateAttrs.$$element = jqLite(compileNode),
6252                        directive,
6253                        directiveName,
6254                        $template,
6255                        replaceDirective = originalReplaceDirective,
6256                        childTranscludeFn = transcludeFn,
6257                        linkFn,
6258                        directiveValue;
6259
6260                    // executes all directives on the current element
6261                    for (var i = 0, ii = directives.length; i < ii; i++) {
6262                        directive = directives[i];
6263                        var attrStart = directive.$$start;
6264                        var attrEnd = directive.$$end;
6265
6266                        // collect multiblock sections
6267                        if (attrStart) {
6268                            $compileNode = groupScan(compileNode, attrStart, attrEnd);
6269                        }
6270                        $template = undefined;
6271
6272                        if (terminalPriority > directive.priority) {
6273                            break; // prevent further processing of directives
6274                        }
6275
6276                        if (directiveValue = directive.scope) {
6277                            newScopeDirective = newScopeDirective || directive;
6278
6279                            // skip the check for directives with async templates, we'll check the derived sync
6280                            // directive when the template arrives
6281                            if (!directive.templateUrl) {
6282                                assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
6283                                    $compileNode);
6284                                if (isObject(directiveValue)) {
6285                                    newIsolateScopeDirective = directive;
6286                                }
6287                            }
6288                        }
6289
6290                        directiveName = directive.name;
6291
6292                        if (!directive.templateUrl && directive.controller) {
6293                            directiveValue = directive.controller;
6294                            controllerDirectives = controllerDirectives || {};
6295                            assertNoDuplicate("'" + directiveName + "' controller",
6296                                controllerDirectives[directiveName], directive, $compileNode);
6297                            controllerDirectives[directiveName] = directive;
6298                        }
6299
6300                        if (directiveValue = directive.transclude) {
6301                            hasTranscludeDirective = true;
6302
6303                            // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
6304                            // This option should only be used by directives that know how to safely handle element transclusion,
6305                            // where the transcluded nodes are added or replaced after linking.
6306                            if (!directive.$$tlb) {
6307                                assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
6308                                nonTlbTranscludeDirective = directive;
6309                            }
6310
6311                            if (directiveValue == 'element') {
6312                                hasElementTranscludeDirective = true;
6313                                terminalPriority = directive.priority;
6314                                $template = groupScan(compileNode, attrStart, attrEnd);
6315                                $compileNode = templateAttrs.$$element =
6316                                    jqLite(document.createComment(' ' + directiveName + ': ' +
6317                                        templateAttrs[directiveName] + ' '));
6318                                compileNode = $compileNode[0];
6319                                replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
6320
6321                                childTranscludeFn = compile($template, transcludeFn, terminalPriority,
6322                                    replaceDirective && replaceDirective.name, {
6323                                        // Don't pass in:
6324                                        // - controllerDirectives - otherwise we'll create duplicates controllers
6325                                        // - newIsolateScopeDirective or templateDirective - comb
6325ining templates with
6326                                        //   element transclusion doesn't make sense.
6327                                        //
6328                                        // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
6329                                        // on the same element more than once.
6330                                        nonTlbTranscludeDirective: nonTlbTranscludeDirective
6331                                    });
6332                            } else {
6333                                $template = jqLite(jqLiteClone(compileNode)).contents();
6334                                $compileNode.empty(); // clear contents
6335                                childTranscludeFn = compile($template, transcludeFn);
6336                            }
6337                        }
6338
6339                        if (directive.template) {
6340                            assertNoDuplicate('template', templateDirective, directive, $compileNode);
6341                            templateDirective = directive;
6342
6343                            directiveValue = (isFunction(directive.template))
6344                                ? directive.template($compileNode, templateAttrs)
6345                                : directive.template;
6346
6347                            directiveValue = denormalizeTemplate(directiveValue);
6348
6349                            if (directive.replace) {
6350                                replaceDirective = directive;
6351                                if (jqLiteIsTextNode(directiveValue)) {
6352                                    $template = [];
6353                                } else {
6354                                    $template = jqLite(directiveValue);
6355                                }
6356                                compileNode = $template[0];
6357
6358                                if ($template.length != 1 || compileNode.nodeType !== 1) {
6359                                    throw $compileMinErr('tplrt',
6360                                        "Template for directive '{0}' must have exactly one root element. {1}",
6361                                        directiveName, '');
6362                                }
6363
6364                                replaceWith(jqCollection, $compileNode, compileNode);
6365
6366                                var newTemplateAttrs = {$attr: {}};
6367
6368                                // combine directives from the original node and from the template:
6369                                // - take the array of directives for this element
6370                                // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
6371                                // - collect directives from the template and sort them by priority
6372                                // - combine directives as: processed + template + unprocessed
6373                                var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
6374                                var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
6375
6376                                if (newIsolateScopeDirective) {
6377                                    markDirectivesAsIsolate(templateDirectives);
6378                                }
6379                                directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
6380                                mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
6381
6382                                ii = directives.length;
6383                            } else {
6384                                $compileNode.html(directiveValue);
6385                            }
6386                        }
6387
6388                        if (directive.templateUrl) {
6389                            assertNoDuplicate('template', templateDirective, directive, $compileNode);
6390                            templateDirective = directive;
6391
6392                            if (directive.replace) {
6393                                replaceDirective = directive;
6394                            }
6395
6396                            nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
6397                                templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
6398                                    controllerDirectives: controllerDirectives,
6399                                    newIsolateScopeDirective: newIsolateScopeDirective,
6400                                    templateDirective: templateDirective,
6401                                    nonTlbTranscludeDirective: nonTlbTranscludeDirective
6402                                });
6403                            ii = directives.length;
6404                        } else if (directive.compile) {
6405                            try {
6406                                linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
6407                                if (isFunction(linkFn)) {
6408                                    addLinkFns(null, linkFn, attrStart, attrEnd);
6409                                } else if (linkFn) {
6410                                    addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
6411                                }
6412                            } catch (e) {
6413                                $exceptionHandler(e, startingTag($compileNode));
6414                            }
6415                        }
6416
6417                        if (directive.terminal) {
6418                            nodeLinkFn.terminal = true;
6419                            terminalPriority = Math.max(terminalPriority, directive.priority);
6420                        }
6421
6422                    }
6423
6424                    nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
6425                    nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
6426                    previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
6427
6428                    // might be normal or delayed nodeLinkFn depending on if templateUrl is present
6429                    return nodeLinkFn;
6430
6431                    ////////////////////
6432
6433                    function addLinkFns(pre, post, attrStart, attrEnd) {
6434                        if (pre) {
6435                            if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
6436                            pre.require = directive.require;
6437                            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6438                                pre = cloneAndAnnotateFn(pre, {isolateScope: true});
6439                            }
6440                            preLinkFns.push(pre);
6441                        }
6442                        if (post) {
6443                            if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
6444                            post.require = directive.require;
6445                            if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
6446                                post = cloneAndAnnotateFn(post, {isolateScope: true});
6447                            }
6448                            postLinkFns.push(post);
6449                        }
6450                    }
6451
6452
6453                    function getControllers(require, $element, elementControllers) {
6454                        var value, retrievalMethod = 'data', optional = false;
6455                        if (isString(require)) {
6456                            while ((value = require.charAt(0)) == '^' || value == '?') {
6457                                require = require.substr(1);
6458                                if (value == '^') {
6459                                    retrievalMethod = 'inheritedData';
6460                                }
6461                                optional = optional || value == '?';
6462                            }
6463                            value = null;
6464
6465                            if (elementControllers && retrievalMethod === 'data') {
6466                                value = elementControllers[require];
6467                            }
6468                            value = value || $element[retrievalMethod]('$' + require + 'Controller');
6469
6470                            if (!value && !optional) {
6471                                throw $compileMinErr('ctreq',
6472                                    "Controller '{0}', required by directive '{1}', can't be found!",
6473                                    require, directiveName);
6474                            }
6475                            return value;
6476                        } else if (isArray(require)) {
6477                            value = [];
6478                            forEach(require, function (require) {
6479                                value.push(getControllers(require, $element, elementControllers));
6480                            });
6481                        }
6482                        return value;
6483                    }
6484
6485
6486                    function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
6487                        var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
6488
6489                        if (compileNode === linkNode) {
6490                            attrs = templateAttrs;
6491                        } else {
6492                            attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
6493                        }
6494                        $element = attrs.$$element;
6495
6496                        if (newIsolateScopeDirective) {
6497                            var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
6498                            var $linkNode = jqLite(linkNode);
6499
6500                            isolateScope = scope.$new(true);
6501
6502                            if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
6503                                $linkNode.data('$isolateScope', isolateScope);
6504                            } else {
6505                                $linkNode.data('$isolateScopeNoTemplate', isolateScope);
6506                            }
6507
6508
6509                            safeAddClass($linkNode, 'ng-isolate-scope');
6510
6511                            forEach(newIsolateScopeDirective.scope, function (definition, scopeName) {
6512                                var match = definition.match(LOCAL_REGEXP) || [],
6513                                    attrName = match[3] || scopeName,
6514                                    optional = (match[2] == '?'),
6515                                    mode = match[1], // @, =, or &
6516                                    lastValue,
6517                                    parentGet, parentSet, compare;
6518
6519                                isolateScope.$$isolateBindings[scopeName] = mode + attrName;
6520
6521                                switch (mode) {
6522
6523                                    case '@':
6524                                        attrs.$observe(attrName, function (value) {
6525                                            isolateScope[scopeName] = value;
6526                                        });
6527                                        attrs.$$observers[attrName].$$scope = scope;
6528                                        if (attrs[attrName]) {
6529                                            // If the attribute has been provided then we trigger an interpolation to ensure
6530                                            // the value is there for use in the link fn
6531                                            isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
6532                                        }
6533                                        break;
6534
6535                                    case '=':
6536                                        if (optional && !attrs[attrName]) {
6537                                            return;
6538                                        }
6539                                        parentGet = $parse(attrs[attrName]);
6540                                        if (parentGet.literal) {
6541                                            compare = equals;
6542                                        } else {
6543                                            compare = function (a, b) {
6544                                                return a === b;
6545                                            };
6546                                        }
6547                                        parentSet = parentGet.assign || function () {
6548                                            // reset the change, or we will throw this exception on every $digest
6549                                            lastValue = isolateScope[scopeName] = parentGet(scope);
6550                                            throw $compileMinErr('nonassign',
6551                                                "Expression '{0}' used with directive '{1}' is non-assignable!",
6552                                                attrs[attrName], newIsolateScopeDirective.name);
6553                                        };
6554                                        lastValue = isolateScope[scopeName] = parentGet(scope);
6555                                        isolateScope.$watch(function parentValueWatch() {
6556                                            var parentValue = parentGet(scope);
6557                                            if (!compare(parentValue, isolateScope[scopeName])) {
6558                                                // we are out of sync and need to copy
6559                                                if (!compare(parentValue, lastValue)) {
6560                                                    // parent changed and it has precedence
6561                                                    isolateScope[scopeName] = parentValue;
6562                                                } else {
6563                                                    // if the parent can be assigned then do so
6564                                                    parentSet(scope, parentValue = isolateScope[scopeName]);
6565                                                }
6566                                            }
6567                                            return lastValue = parentValue;
6568                                        }, null, parentGet.literal);
6569                                        break;
6570
6571                                    case '&':
6572                                        parentGet = $parse(attrs[attrName]);
6573                                        isolateScope[scopeName] = function (locals) {
6574                                            return parentGet(scope, locals);
6575                                        };
6576                                        break;
6577
6578                                    default:
6579                                        throw $compileMinErr('iscp',
6580                                            "Invalid isolate scope definition for directive '{0}'." +
6581                                                " Definition: {... {1}: '{2}' ...}",
6582                                            newIsolateScopeDirective.name, scopeName, definition);
6583                                }
6584                            });
6585                        }
6586                        transcludeFn = boundTranscludeFn && controllersBoundTransclude;
6587                        if (controllerDirectives) {
6588                            forEach(controllerDirectives, function (directive) {
6589                                var locals = {
6590                                    $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
6591                                    $element: $element,
6592                                    $attrs: attrs,
6593                                    $transclude: transcludeFn
6594                                }, controllerInstance;
6595
6596                                controller = directive.controller;
6597                                if (controller == '@') {
6598                                    controller = attrs[directive.name];
6599                                }
6600
6601                                controllerInstance = $controller(controller, locals);
6602                                // For directives with element transclusion the element is a comment,
6603                                // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
6604                                // clean up (http://bugs.jquery.com/ticket/8335).
6605                                // Instead, we save the controllers for the element in a local hash and attach to .data
6606                                // later, once we have the actual element.
6607                                elementControllers[directive.name] = controllerInstance;
6608                                if (!hasElementTranscludeDirective) {
6609                                    $element.data('$' + directive.name + 'Controller', controllerInstance);
6610                                }
6611
6612                                if (directive.controllerAs) {
6613                                    locals.$scope[directive.controllerAs] = controllerInstance;
6614                                }
6615                            });
6616                        }
6617
6618                        // PRELINKING
6619                        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
6620                            try {
6621                                linkFn = preLinkFns[i];
6622                                linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6623                                    linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6624                            } catch (e) {
6625                                $exceptionHandler(e, startingTag($element));
6626                            }
6627                        }
6628
6629                        // RECURSION
6630                        // We only pass the isolate scope, if the isolate directive has a template,
6631                        // otherwise the child elements do not belong to the isolate directive.
6632                        var scopeToChild = scope;
6633                        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
6634                            scopeToChild = isolateScope;
6635                        }
6636                        childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
6637
6638                        // POSTLINKING
6639                        for (i = postLinkFns.length - 1; i >= 0; i--) {
6640                            try {
6641                                linkFn = postLinkFns[i];
6642                                linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
6643                                    linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
6644                            } catch (e) {
6645                                $exceptionHandler(e, startingTag($element));
6646                            }
6647                        }
6648
6649                        // This is the function that is injected as `$transclude`.
6650                        function controllersBoundTransclude(scope, cloneAttachFn) {
6651                            var transcludeControllers;
6652
6653                            // no scope passed
6654                            if (arguments.length < 2) {
6655                                cloneAttachFn = scope;
6656                                scope = undefined;
6657                            }
6658
6659                            if (hasElementTranscludeDirective) {
6660                                transcludeControllers = elementControllers;
6661                            }
6662
6663                            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
6664                        }
6665                    }
6666                }
6667
6668                function markDirectivesAsIsolate(directives) {
6669                    // mark all directives as needing isolate scope.
6670                    for (var j = 0, jj = directives.length; j < jj; j++) {
6671                        directives[j] = inherit(directives[j], {$$isolateScope: true});
6672                    }
6673                }
6674
6675                /**
6676                 * looks up the directive and decorates it with exception handling and proper parameters. We
6677                 * call this the boundDirective.
6678                 *
6679                 * @param {string} name name of the directive to look up.
6680                 * @param {string} location The directive must be found in specific format.
6681                 *   String containing any of theses characters:
6682                 *
6683                 *   * `E`: element name
6684                 *   * `A': attribute
6685                 *   * `C`: class
6686                 *   * `M`: comment
6687                 * @returns {boolean} true if directive was added.
6688                 */
6689                function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName) {
6690                    if (name === ignoreDirective) return null;
6691                    var match = null;
6692                    if (hasDirectives.hasOwnProperty(name)) {
6693                        for (var directive, directives = $injector.get(name + Suffix),
6694                                 i = 0, ii = directives.length; i < ii; i++) {
6695                            try {
6696                                directive = directives[i];
6697                                if ((maxPriority === undefined || maxPriority > directive.priority) &&
6698                                    directive.restrict.indexOf(location) != -1) {
6699                                    if (startAttrName) {
6700                                        directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
6701                                    }
6702                                    tDirectives.push(directive);
6703                                    match = directive;
6704                                }
6705                            } catch (e) {
6706                                $exceptionHandler(e);
6707                            }
6708                        }
6709                    }
6710                    return match;
6711                }
6712
6713
6714                /**
6715                 * When the element is replaced with HTML template then the new attributes
6716                 * on the template need to be merged with the existing attributes in the DOM.
6717                 * The desired effect is to have both of the attributes present.
6718                 *
6719                 * @param {object} dst destination attributes (original DOM)
6720                 * @param {object} src source attributes (from the directive template)
6721                 */
6722                function mergeTemplateAttributes(dst, src) {
6723                    var srcAttr = src.$attr,
6724                        dstAttr = dst.$attr,
6725                        $element = dst.$$element;
6726
6727                    // reapply the old attributes to the new element
6728                    forEach(dst, function (value, key) {
6729                        if (key.charAt(0) != '$') {
6730                            if (src[key]) {
6731                                value += (key === 'style' ? ';' : ' ') + src[key];
6732                            }
6733                            dst.$set(key, value, true, srcAttr[key]);
6734                        }
6735                    });
6736
6737                    // copy the new attributes on the old attrs object
6738                    forEach(src, function (value, key) {
6739                        if (key == 'class') {
6740                            safeAddClass($element, value);
6741                            dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
6742                        } else if (key == 'style') {
6743                            $element.attr('style', $element.attr('style') + ';' + value);
6744                            dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
6745                            // `dst` will never contain hasOwnProperty as DOM parser won't let it.
6746                            // You will get an "InvalidCharacterError: DOM Exception 5" error if you
6747                            // have an attribute like "has-own-property" or "data-has-own-property", etc.
6748                        } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
6749                            dst[key] = value;
6750                            dstAttr[key] = srcAttr[key];
6751                        }
6752                    });
6753                }
6754
6755
6756                function compileTemplateUrl(directives, $compileNode, tAttrs, $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
6757                    var linkQueue = [],
6758                        afterTemplateNodeLinkFn,
6759                        afterTemplateChildLinkFn,
6760                        beforeTemplateCompileNode = $compileNode[0],
6761                        origAsyncDirective = directives.shift(),
6762                    // The fact that we have to copy and patch the directive seems wrong!
6763                        derivedSyncDirective = extend({}, origAsyncDirective, {
6764                            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
6765                        }),
6766                        templateUrl = (isFunction(origAsyncDirective.templateUrl))
6767                            ? origAsyncDirective.templateUrl($compileNode, tAttrs)
6768                            : origAsyncDirective.templateUrl;
6769
6770                    $compileNode.empty();
6771
6772                    $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
6773                        success(function (content) {
6774                            var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
6775
6776                            content = denormalizeTemplate(content);
6777
6778                            if (origAsyncDirective.replace) {
6779                                if (jqLiteIsTextNode(content)) {
6780                                    $template = [];
6781                                } else {
6782                                    $template = jqLite(content);
6783                                }
6784                                compileNode = $template[0];
6785
6786                                if ($template.length != 1 || compileNode.nodeType !== 1) {
6787                                    throw $compileMinErr('tplrt',
6788                                        "Template for directive '{0}' must have exactly one root element. {1}",
6789                                        origAsyncDirective.name, templateUrl);
6790                                }
6791
6792                                tempTemplateAttrs = {$attr: {}};
6793                                replaceWith($rootElement, $compileNode, compileNode);
6794                                var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
6795
6796                                if (isObject(origAsyncDirective.scope)) {
6797                                    markDirectivesAsIsolate(templateDirectives);
6798                                }
6799                                directives = templateDirectives.concat(directives);
6800                                mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
6801                            } else {
6802                                compileNode = beforeTemplateCompileNode;
6803                                $compileNode.html(content);
6804                            }
6805
6806                            directives.unshift(derivedSyncDirective);
6807
6808                            afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
6809                                childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
6810                                previousCompileContext);
6811                            forEach($rootElement, function (node, i) {
6812                                if (node == compileNode) {
6813                                    $rootElement[i] = $compileNode[0];
6814                                }
6815                            });
6816                            afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
6817
6818
6819                            while (linkQueue.length) {
6820                                var scope = linkQueue.shift(),
6821                                    beforeTemplateLinkNode = linkQueue.shift(),
6822                                    linkRootElement = linkQueue.shift(),
6823                                    boundTranscludeFn = linkQueue.shift(),
6824                                    linkNode = $compileNode[0];
6825
6826                                if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
6827                                    var oldClasses = beforeTemplateLinkNode.className;
6828
6829                                    if (!(previousCompileContext.hasElementTranscludeDirective &&
6830                                        origAsyncDirective.replace)) {
6831                                        // it was cloned therefore we have to clone as well.
6832                                        linkNode = jqLiteClone(compileNode);
6833                                    }
6834
6835                                    replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
6836
6837                                    // Copy in CSS classes from original node
6838                                    safeAddClass(jqLite(linkNode), oldClasses);
6839                                }
6840                                if (afterTemplateNodeLinkFn.transclude) {
6841                                    childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
6842                                } else {
6843                                    childBoundTranscludeFn = boundTranscludeFn;
6844                                }
6845                                afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
6846                                    childBoundTranscludeFn);
6847                            }
6848                            linkQueue = null;
6849                        }).
6850                        error(function (response, code, headers, config) {
6851                            throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
6852                        });
6853
6854                    return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
6855                        if (linkQueue) {
6856                            linkQueue.push(scope);
6857                            linkQueue.push(node);
6858                            linkQueue.push(rootElement);
6859                            linkQueue.push(boundTranscludeFn);
6860                        } else {
6861                            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
6862                        }
6863                    };
6864                }
6865
6866
6867                /**
6868                 * Sorting function for bound directives.
6869                 */
6870                function byPriority(a, b) {
6871                    var diff = b.priority - a.priority;
6872                    if (diff !== 0) return diff;
6873                    if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
6874                    return a.index - b.index;
6875                }
6876
6877
6878                function assertNoDuplicate(what, previousDirective, directive, element) {
6879                    if (previousDirective) {
6880                        throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
6881                            previousDirective.name, directive.name, what, startingTag(element));
6882                    }
6883                }
6884
6885
6886                function addTextInterpolateDirective(directives, text) {
6887                    var interpolateFn = $interpolate(text, true);
6888                    if (interpolateFn) {
6889                        directives.push({
6890                            priority: 0,
6891                            compile: valueFn(function textInterpolateLinkFn(scope, node) {
6892                                var parent = node.parent(),
6893                                    bindings = parent.data('$binding') || [];
6894                                bindings.push(interpolateFn);
6895                                safeAddClass(parent.data('$binding', bindings), 'ng-binding');
6896                                scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
6897                                    node[0].nodeValue = value;
6898                                });
6899                            })
6900                        });
6901                    }
6902                }
6903
6904
6905                function getTrustedContext(node, attrNormalizedName) {
6906                    if (attrNormalizedName == "srcdoc") {
6907                        return $sce.HTML;
6908                    }
6909                    var tag = nodeName_(node);
6910                    // maction[xlink:href] can source SVG.  It's not limited to <maction>.
6911                    if (attrNormalizedName == "xlinkHref" ||
6912                        (tag == "FORM" && attrNormalizedName == "action") ||
6913                        (tag != "IMG" && (attrNormalizedName == "src" ||
6914                            attrNormalizedName == "ngSrc"))) {
6915                        return $sce.RESOURCE_URL;
6916                    }
6917                }
6918
6919
6920                function addAttrInterpolateDirective(node, directives, value, name) {
6921                    var interpolateFn = $interpolate(value, true);
6922
6923                    // no interpolation found -> ignore
6924                    if (!interpolateFn) return;
6925
6926
6927                    if (name === "multiple" && nodeName_(node) === "SELECT") {
6928                        throw $compileMinErr("selmulti",
6929                            "Binding to the 'multiple' attribute is not supported. Element: {0}",
6930                            startingTag(node));
6931                    }
6932
6933                    directives.push({
6934                        priority: 100,
6935                        compile: function () {
6936                            return {
6937                                pre: function attrInterpolatePreLinkFn(scope, element, attr) {
6938                                    var $$observers = (attr.$$observers || (attr.$$observers = {}));
6939
6940                                    if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
6941                                        throw $compileMinErr('nodomevents',
6942                                            "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
6943                                                "ng- versions (such as ng-click instead of onclick) instead.");
6944                                    }
6945
6946                                    // we need to interpolate again, in case the attribute value has been updated
6947                                    // (e.g. by another directive's compile function)
6948                                    interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
6949
6950                                    // if attribute was updated so that there is no interpolation going on we don't want to
6951                                    // register any observers
6952                                    if (!interpolateFn) return;
6953
6954                                    // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
6955                                    // actual attr value
6956                                    attr[name] = interpolateFn(scope);
6957                                    ($$observers[name] || ($$observers[name] = [])).$$inter = true;
6958                                    (attr.$$observers && attr.$$observers[name].$$scope || scope).
6959                                        $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
6960                                            //special case for class attribute addition + removal
6961                                            //so that class changes can tap into the animation
6962                                            //hooks provided by the $animate service. Be sure to
6963                                            //skip animations when the first digest occurs (when
6964                                            //both the new and the old values are the same) since
6965                                            //the CSS classes are the non-interpolated values
6966                                            if (name === 'class' && newValue != oldValue) {
6967                                                attr.$updateClass(newValue, oldValue);
6968                                            } else {
6969                                                attr.$set(name, newValue);
6970                                            }
6971                                        });
6972                                }
6973                            };
6974                        }
6975                    });
6976                }
6977
6978
6979                /**
6980                 * This is a special jqLite.replaceWith, which can replace items which
6981                 * have no parents, provided that the containing jqLite collection is provided.
6982                 *
6983                 * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
6984                 *                               in the root of the tree.
6985                 * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
6986                 *                                  the shell, but replace its DOM node reference.
6987                 * @param {Node} newNode The new DOM node.
6988                 */
6989                function replaceWith($rootElement, elementsToRemove, newNode) {
6990                    var firstElementToRemove = elementsToRemove[0],
6991                        removeCount = elementsToRemove.length,
6992                        parent = firstElementToRemove.parentNode,
6993                        i, ii;
6994
6995                    if ($rootElement) {
6996                        for (i = 0, ii = $rootElement.length; i < ii; i++) {
6997                            if ($rootElement[i] == firstElementToRemove) {
6998                                $rootElement[i++] = newNode;
6999                                for (var j = i, j2 = j + removeCount - 1,
7000                                         jj = $rootElement.length;
7001                                     j < jj; j++, j2++) {
7002                                    if (j2 < jj) {
7003                                        $rootElement[j] = $rootElement[j2];
7004                                    } else {
7005                                        delete $rootElement[j];
7006                                    }
7007                                }
7008                                $rootElement.length -= removeCount - 1;
7009                                break;
7010                            }
7011                        }
7012                    }
7013
7014                    if (parent) {
7015                        parent.replaceChild(newNode, firstElementToRemove);
7016                    }
7017                    var fragment = document.createDocumentFragment();
7018                    fragment.appendChild(firstElementToRemove);
7019                    newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
7020                    for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
7021                        var element = elementsToRemove[k];
7022                        jqLite(element).remove(); // must do this way to clean up expando
7023                        fragment.appendChild(element);
7024                        delete elementsToRemove[k];
7025                    }
7026
7027                    elementsToRemove[0] = newNode;
7028                    elementsToRemove.length = 1;
7029                }
7030
7031
7032                function cloneAndAnnotateFn(fn, annotation) {
7033                    return extend(function () {
7034                        return fn.apply(null, arguments);
7035                    }, fn, annotation);
7036                }
7037            }];
7038    }
7039
7040    var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
7041
7042    /**
7043     * Converts all accepted directives format into proper directive name.
7044     * All of these will become 'myDirective':
7045     *   my:Directive
7046     *   my-directive
7047     *   x-my-directive
7048     *   data-my:directive
7049     *
7050     * Also there is special case for Moz prefix starting with upper case letter.
7051     * @param name Name to normalize
7052     */
7053    function directiveNormalize(name) {
7054        return camelCase(name.replace(PREFIX_REGEXP, ''));
7055    }
7056
7057    /**
7058     * @ngdoc type
7059     * @name $compile.directive.Attributes
7060     *
7061     * @description
7062     * A shared object between directive compile / linking functions which contains normalized DOM
7063     * element attributes. The values reflect current binding state `{{ }}`. The normalization is
7064     * needed since all of these are treated as equivalent in Angular:
7065     *
7066     *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
7067     */
7068
7069    /**
7070     * @ngdoc property
7071     * @name $compile.directive.Attributes#$attr
7072     * @returns {object} A map of DOM element attribute names to the normalized name. This is
7073     *                   needed to do reverse lookup from normalized name back to actual name.
7074     */
7075
7076
7077    /**
7078     * @ngdoc method
7079     * @name $compile.directive.Attributes#$set
7080     * @function
7081     *
7082     * @description
7083     * Set DOM element attribute value.
7084     *
7085     *
7086     * @param {string} name Normalized element attribute name of the property to modify. The name is
7087     *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
7088     *          property to the original name.
7089     * @param {string} value Value to set the attribute to. The value can be an interpolated string.
7090     */
7091
7092
7093    /**
7094     * Closure compiler type information
7095     */
7096
7097    function nodesetLinkingFn(/* angular.Scope */ scope, /* NodeList */ nodeList, /* Element */ rootElement, /* function(Function) */ boundTranscludeFn) {
7098    }
7099
7100    function directiveLinkingFn(/* nodesetLinkingFn */ nodesetLinkingFn, /* angular.Scope */ scope, /* Node */ node, /* Element */ rootElement, /* function(Function) */ boundTranscludeFn) {
7101    }
7102
7103    function tokenDifference(str1, str2) {
7104        var values = '',
7105            tokens1 = str1.split(/\s+/),
7106            tokens2 = str2.split(/\s+/);
7107
7108        outer:
7109            for (var i = 0; i < tokens1.length; i++) {
7110                var token = tokens1[i];
7111                for (var j = 0; j < tokens2.length; j++) {
7112                    if (token == tokens2[j]) continue outer;
7113                }
7114                values += (values.length > 0 ? ' ' : '') + token;
7115            }
7116        return values;
7117    }
7118
7119    /**
7120     * @ngdoc provider
7121     * @name $controllerProvider
7122     * @description
7123     * The {@link ng.$controller $controller service} is used by Angular to create new
7124     * controllers.
7125     *
7126     * This provider allows controller registration via the
7127     * {@link ng.$controllerProvider#register register} method.
7128     */
7129    function $ControllerProvider() {
7130        var controllers = {},
7131            CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
7132
7133
7134        /**
7135         * @ngdoc method
7136         * @name $controllerProvider#register
7137         * @param {string|Object} name Controller name, or an object map of controllers where the keys are
7138         *    the names and the values are the constructors.
7139         * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
7140         *    annotations in the array notation).
7141         */
7142        this.register = function (name, constructor) {
7143            assertNotHasOwnProperty(name, 'controller');
7144            if (isObject(name)) {
7145                extend(controllers, name);
7146            } else {
7147                controllers[name] = constructor;
7148            }
7149        };
7150
7151
7152        this.$get = ['$injector', '$window', function ($injector, $window) {
7153
7154            /**
7155             * @ngdoc service
7156             * @name $controller
7157             * @requires $injector
7158             *
7159             * @param {Function|string} constructor If called with a function then it's considered to be the
7160             *    controller constructor function. Otherwise it's considered to be a string which is used
7161             *    to retrieve the controller constructor using the following steps:
7162             *
7163             *    * check if a controller with given name is registered via `$controllerProvider`
7164             *    * check if evaluating the string on the current scope returns a constructor
7165             *    * check `window[constructor]` on the global `window` object
7166             *
7167             * @param {Object} locals Injection locals for Controller.
7168             * @return {Object} Instance of given controller.
7169             *
7170             * @description
7171             * `$controller` service is responsible for instantiating controllers.
7172             *
7173             * It's just a simple call to {@link auto.$injector $injector}, but extracted into
7174             * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
7175             */
7176            return function (expression, locals) {
7177                var instance, match, constructor, identifier;
7178
7179                if (isString(expression)) {
7180                    match = expression.match(CNTRL_REG),
7181                        constructor = match[1],
7182                        identifier = match[3];
7183                    expression = controllers.hasOwnProperty(constructor)
7184                        ? controllers[constructor]
7185                        : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
7186
7187                    assertArgFn(expression, constructor, true);
7188                }
7189
7190                instance = $injector.instantiate(expression, locals);
7191
7192                if (identifier) {
7193                    if (!(locals && typeof locals.$scope == 'object')) {
7194                        throw minErr('$controller')('noscp',
7195                            "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7196                            constructor || expression.name, identifier);
7197                    }
7198
7199                    locals.$scope[identifier] = instance;
7200                }
7201
7202                return instance;
7203            };
7204        }];
7205    }
7206
7207    /**
7208     * @ngdoc service
7209     * @name $document
7210     * @requires $window
7211     *
7212     * @description
7213     * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
7214     *
7215     * @example
7216     <example>
7217     <file name="index.jsp">
7218     <div ng-controller="MainCtrl">
7219     <p>$document title: <b ng-bind="title"></b></p>
7220     <p>window.document title: <b ng-bind="windowTitle"></b></p>
7221     </div>
7222     </file>
7223     <file name="script.js">
7224     function MainCtrl($scope, $document) {
7225         $scope.title = $document[0].title;
7226         $scope.windowTitle = angular.element(window.document)[0].title;
7227       }
7228     </file>
7229     </example>
7230     */
7231    function $DocumentProvider() {
7232        this.$get = ['$window', function (window) {
7233            return jqLite(window.document);
7234        }];
7235    }
7236
7237    /**
7238     * @ngdoc service
7239     * @name $exceptionHandler
7240     * @requires ng.$log
7241     *
7242     * @description
7243     * Any uncaught exception in angular expressions is delegated to this service.
7244     * The default implementation simply delegates to `$log.error` which logs it into
7245     * the browser console.
7246     *
7247     * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
7248     * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
7249     *
7250     * ## Example:
7251     *
7252     * ```js
7253     *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
7254 *     return function (exception, cause) {
7255 *       exception.message += ' (caused by "' + cause + '")';
7256 *       throw exception;
7257 *     };
7258 *   });
7259     * ```
7260     *
7261     * This example will override the normal action of `$exceptionHandler`, to make angular
7262     * exceptions fail hard when they happen, instead of just logging to the console.
7263     *
7264     * @param {Error} exception Exception associated with the error.
7265     * @param {string=} cause optional information about the context in which
7266     *       the error was thrown.
7267     *
7268     */
7269    function $ExceptionHandlerProvider() {
7270        this.$get = ['$log', function ($log) {
7271            return function (exception, cause) {
7272                $log.error.apply($log, arguments);
7273            };
7274        }];
7275    }
7276
7277    /**
7278     * Parse headers into key value object
7279     *
7280     * @param {string} headers Raw headers as a string
7281     * @returns {Object} Parsed headers as key value object
7282     */
7283    function parseHeaders(headers) {
7284        var parsed = {}, key, val, i;
7285
7286        if (!headers) return parsed;
7287
7288        forEach(headers.split('\n'), function (line) {
7289            i = line.indexOf(':');
7290            key = lowercase(trim(line.substr(0, i)));
7291            val = trim(line.substr(i + 1));
7292
7293            if (key) {
7294                if (parsed[key]) {
7295                    parsed[key] += ', ' + val;
7296                } else {
7297                    parsed[key] = val;
7298                }
7299            }
7300        });
7301
7302        return parsed;
7303    }
7304
7305
7306    /**
7307     * Returns a function that provides access to parsed headers.
7308     *
7309     * Headers are lazy parsed when first requested.
7310     * @see parseHeaders
7311     *
7312     * @param {(string|Object)} headers Headers to provide access to.
7313     * @returns {function(string=)} Returns a getter function which if called with:
7314     *
7315     *   - if called with single an argument returns a single header value or null
7316     *   - if called with no arguments returns an object containing all headers.
7317     */
7318    function headersGetter(headers) {
7319        var headersObj = isObject(headers) ? headers : undefined;
7320
7321        return function (name) {
7322            if (!headersObj) headersObj = parseHeaders(headers);
7323
7324            if (name) {
7325                return headersObj[lowercase(name)] || null;
7326            }
7327
7328            return headersObj;
7329        };
7330    }
7331
7332
7333    /**
7334     * Chain all given functions
7335     *
7336     * This function is used for both request and response transforming
7337     *
7338     * @param {*} data Data to transform.
7339     * @param {function(string=)} headers Http headers getter fn.
7340     * @param {(Function|Array.<Function>)} fns Function or an array of functions.
7341     * @returns {*} Transformed data.
7342     */
7343    function transformData(data, headers, fns) {
7344        if (isFunction(fns))
7345            return fns(data, headers);
7346
7347        forEach(fns, function (fn) {
7348            data = fn(data, headers);
7349        });
7350
7351        return data;
7352    }
7353
7354
7355    function isSuccess(status) {
7356        return 200 <= status && status < 300;
7357    }
7358
7359
7360    function $HttpProvider() {
7361        var JSON_START = /^\s*(\[|\{[^\{])/,
7362            JSON_END = /[\}\]]\s*$/,
7363            PROTECTION_PREFIX = /^\)\]\}',?\n/,
7364            CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
7365
7366        var defaults = this.defaults = {
7367            // transform incoming response data
7368            transformResponse: [function (data) {
7369                if (isString(data)) {
7370                    // strip json vulnerability protection prefix
7371                    data = data.replace(PROTECTION_PREFIX, '');
7372                    if (JSON_START.test(data) && JSON_END.test(data))
7373                        data = fromJson(data);
7374                }
7375                return data;
7376            }],
7377
7378            // transform outgoing request data
7379            transformRequest: [function (d) {
7380                return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
7381            }],
7382
7383            // default headers
7384            headers: {
7385                common: {
7386                    'Accept': 'application/json, text/plain, */*'
7387                },
7388                post: copy(CONTENT_TYPE_APPLICATION_JSON),
7389                put: copy(CONTENT_TYPE_APPLICATION_JSON),
7390                patch: copy(CONTENT_TYPE_APPLICATION_JSON)
7391            },
7392
7393            xsrfCookieName: 'XSRF-TOKEN',
7394            xsrfHeaderName: 'X-XSRF-TOKEN'
7395        };
7396
7397        /**
7398         * Are ordered by request, i.e. they are applied in the same order as the
7399         * array, on request, but reverse order, on response.
7400         */
7401        var interceptorFactories = this.interceptors = [];
7402
7403        /**
7404         * For historical reasons, response interceptors are ordered by the order in which
7405         * they are applied to the response. (This is the opposite of interceptorFactories)
7406         */
7407        var responseInterceptorFactories = this.responseInterceptors = [];
7408
7409        this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
7410            function ($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
7411
7412                var defaultCache = $cacheFactory('$http');
7413
7414                /**
7415                 * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
7416                 * The reversal is needed so that we can build up the interception chain around the
7417                 * server request.
7418                 */
7419                var reversedInterceptors = [];
7420
7421                forEach(interceptorFactories, function (interceptorFactory) {
7422                    reversedInterceptors.unshift(isString(interceptorFactory)
7423                        ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
7424                });
7425
7426                forEach(responseInterceptorFactories, function (interceptorFactory, index) {
7427                    var responseFn = isString(interceptorFactory)
7428                        ? $injector.get(interceptorFactory)
7429                        : $injector.invoke(interceptorFactory);
7430
7431                    /**
7432                     * Response interceptors go before "around" interceptors (no real reason, just
7433                     * had to pick one.) But they are already reversed, so we can't use unshift, hence
7434                     * the splice.
7435                     */
7436                    reversedInterceptors.splice(index, 0, {
7437                        response: function (response) {
7438                            return responseFn($q.when(response));
7439                        },
7440                        responseError: function (response) {
7441                            return responseFn($q.reject(response));
7442                        }
7443                    });
7444                });
7445
7446
7447                /**
7448                 * @ngdoc service
7449                 * @kind function
7450                 * @name $http
7451                 * @requires ng.$httpBackend
7452                 * @requires $cacheFactory
7453                 * @requires $rootScope
7454                 * @requires $q
7455                 * @requires $injector
7456                 *
7457                 * @description
7458                 * The `$http` service is a core Angular service that facilitates communication with the remote
7459                 * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
7460                 * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
7461                 *
7462                 * For unit testing applications that use `$http` service, see
7463                 * {@link ngMock.$httpBackend $httpBackend mock}.
7464                 *
7465                 * For a higher level of abstraction, please check out the {@link ngResource.$resource
7466     * $resource} service.
7467                 *
7468                 * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
7469                 * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
7470                 * it is important to familiarize yourself with these APIs and the guarantees they provide.
7471                 *
7472                 *
7473                 * # General usage
7474                 * The `$http` service is a function which takes a single argument — a configuration object —
7475                 * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
7476                 * with two $http specific methods: `success` and `error`.
7477                 *
7478                 * ```js
7479                 *   $http({method: 'GET', url: '/someUrl'}).
7480                 *     success(function(data, status, headers, config) {
7481     *       // this callback will be called asynchronously
7482     *       // when the response is available
7483     *     }).
7484                 *     error(function(data, status, headers, config) {
7485     *       // called asynchronously if an error occurs
7486     *       // or server returns response with an error status.
7487     *     });
7488                 * ```
7489                 *
7490                 * Since the returned value of calling the $http function is a `promise`, you can also use
7491                 * the `then` method to register callbacks, and these callbacks will receive a single argument –
7492                 * an object representing the response. See the API signature and type info below for more
7493                 * details.
7494                 *
7495                 * A response status code between 200 and 299 is considered a success status and
7496                 * will result in the success callback being called. Note that if the response is a redirect,
7497                 * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
7498                 * called for such responses.
7499                 *
7500                 * # Writing Unit Tests that use $http
7501                 * When unit testing (using {@link ngMock ngMock}), it is necessary to call
7502                 * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
7503                 * request using trained responses.
7504                 *
7505                 * ```
7506                 * $httpBackend.expectGET(...);
7507                 * $http.get(...);
7508                 * $httpBackend.flush();
7509                 * ```
7510                 *
7511                 * # Shortcut methods
7512                 *
7513                 * Shortcut methods are also available. All shortcut methods require passing in the URL, and
7514                 * request data must be passed in for POST/PUT requests.
7515                 *
7516                 * ```js
7517                 *   $http.get('/someUrl').success(successCallback);
7518                 *   $http.post('/someUrl', data).success(successCallback);
7519                 * ```
7520                 *
7521                 * Complete list of shortcut methods:
7522                 *
7523                 * - {@link ng.$http#get $http.get}
7524                 * - {@link ng.$http#head $http.head}
7525                 * - {@link ng.$http#post $http.post}
7526                 * - {@link ng.$http#put $http.put}
7527                 * - {@link ng.$http#delete $http.delete}
7528                 * - {@link ng.$http#jsonp $http.jsonp}
7529                 *
7530                 *
7531                 * # Setting HTTP Headers
7532                 *
7533                 * The $http service will automatically add certain HTTP headers to all requests. These defaults
7534                 * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
7535                 * object, which currently contains this default configuration:
7536                 *
7537                 * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
7538                 *   - `Accept: application/json, text/plain, * / *`
7539                 * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
7540                 *   - `Content-Type: application/json`
7541                 * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
7542                 *   - `Content-Type: application/json`
7543                 *
7544                 * To add or overwrite these defaults, simply add or remove a property from these configuration
7545                 * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
7546                 * with the lowercased HTTP method name as the key, e.g.
7547                 * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
7548                 *
7549                 * The defaults can also be set at runtime via the `$http.defaults` object in the same
7550                 * fashion. For example:
7551                 *
7552                 * ```
7553                 * module.run(function($http) {
7554     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
7555     * });
7556                 * ```
7557                 *
7558                 * In addition, you can supply a `headers` property in the config object passed when
7559                 * calling `$http(config)`, which overrides the defaults without changing them globally.
7560                 *
7561                 *
7562                 * # Transforming Requests and Responses
7563                 *
7564                 * Both requests and responses can be transformed using transform functions. By default, Angular
7565                 * applies these transformations:
7566                 *
7567                 * Request transformations:
7568                 *
7569                 * - If the `data` property of the request configuration object contains an object, serialize it
7570                 *   into JSON format.
7571                 *
7572                 * Response transformations:
7573                 *
7574                 *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
7575                 *  - If JSON response is detected, deserialize it using a JSON parser.
7576                 *
7577                 * To globally augment or override the default transforms, modify the
7578                 * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
7579                 * properties. These properties are by default an array of transform functions, which allows you
7580                 * to `push` or `unshift` a new transformation function into the transformation chain. You can
7581                 * also decide to completely override any default transformations by assigning your
7582                 * transformation functions to these properties directly without the array wrapper.  These defaults
7583                 * are again available on the $http factory at run-time, which may be useful if you have run-time
7584                 * services you wish to be involved in your transformations.
7585                 *
7586                 * Similarly, to locally override the request/response transforms, augment the
7587                 * `transformRequest` and/or `transformResponse` properties of the configuration object passed
7588                 * into `$http`.
7589                 *
7590                 *
7591                 * # Caching
7592                 *
7593                 * To enable caching, set the request configuration `cache` property to `true` (to use default
7594                 * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
7595                 * When the cache is enabled, `$http` stores the response from the server in the specified
7596                 * cache. The next time the same request is made, the response is served from the cache without
7597                 * sending a request to the server.
7598                 *
7599                 * Note that even if the response is served from cache, delivery of the data is asynchronous in
7600                 * the same way that real requests are.
7601                 *
7602                 * If there are multiple GET requests for the same URL that should be cached using the same
7603                 * cache, but the cache is not populated yet, only one request to the server will be made and
7604                 * the remaining requests will be fulfilled using the response from the first request.
7605                 *
7606                 * You can change the default cache to a new object (built with
7607                 * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
7608                 * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
7609                 * their `cache` property to `true` will now use this cache object.
7610                 *
7611                 * If you set the default cache to `false` then only requests that specify their own custom
7612                 * cache object will be cached.
7613                 *
7614                 * # Interceptors
7615                 *
7616                 * Before you start creating interceptors, be sure to understand the
7617                 * {@link ng.$q $q and deferred/promise APIs}.
7618                 *
7619                 * For purposes of global error handling, authentication, or any kind of synchronous or
7620                 * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
7621                 * able to intercept requests before they are handed to the server and
7622                 * responses before they are handed over to the application code that
7623                 * initiated these requests. The interceptors leverage the {@link ng.$q
7624     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
7625                 *
7626                 * The interceptors are service factories that are registered with the `$httpProvider` by
7627                 * adding them to the `$httpProvider.interceptors` array. The factory is called and
7628                 * injected with dependencies (if specified) and returns the interceptor.
7629                 *
7630                 * There are two kinds of interceptors (and two kinds of rejection interceptors):
7631                 *
7632                 *   * `request`: interceptors get called with http `config` object. The function is free to
7633                 *     modify the `config` or create a new one. The function needs to return the `config`
7634                 *     directly or as a promise.
7635                 *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
7636                 *     resolved with a rejection.
7637                 *   * `response`: interceptors get called with http `response` object. The function is free to
7638                 *     modify the `response` or create a new one. The function needs to return the `response`
7639                 *     directly or as a promise.
7640                 *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
7641                 *     resolved with a rejection.
7642                 *
7643                 *
7644                 * ```js
7645                 *   // register the interceptor as a service
7646                 *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7647     *     return {
7648     *       // optional method
7649     *       'request': function(config) {
7650     *         // do something on success
7651     *         return config || $q.when(config);
7652     *       },
7653     *
7654     *       // optional method
7655     *      'requestError': function(rejection) {
7656     *         // do something on error
7657     *         if (canRecover(rejection)) {
7658     *           return responseOrNewPromise
7659     *         }
7660     *         return $q.reject(rejection);
7661     *       },
7662     *
7663     *
7664     *
7665     *       // optional method
7666     *       'response': function(response) {
7667     *         // do something on success
7668     *         return response || $q.when(response);
7669     *       },
7670     *
7671     *       // optional method
7672     *      'responseError': function(rejection) {
7673     *         // do something on error
7674     *         if (canRecover(rejection)) {
7675     *           return responseOrNewPromise
7676     *         }
7677     *         return $q.reject(rejection);
7678     *       }
7679     *     };
7680     *   });
7681                 *
7682                 *   $httpProvider.interceptors.push('myHttpInterceptor');
7683                 *
7684                 *
7685                 *   // alternatively, register the interceptor via an anonymous factory
7686                 *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
7687     *     return {
7688     *      'request': function(config) {
7689     *          // same as above
7690     *       },
7691     *
7692     *       'response': function(response) {
7693     *          // same as above
7694     *       }
7695     *     };
7696     *   });
7697                 * ```
7698                 *
7699                 * # Response interceptors (DEPRECATED)
7700                 *
7701                 * Before you start creating interceptors, be sure to understand the
7702                 * {@link ng.$q $q and deferred/promise APIs}.
7703                 *
7704                 * For purposes of global error handling, authentication or any kind of synchronous or
7705                 * asynchronous preprocessing of received responses, it is desirable to be able to intercept
7706                 * responses for http requests before they are handed over to the application code that
7707                 * initiated these requests. The response interceptors leverage the {@link ng.$q
7708     * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
7709                 *
7710                 * The interceptors are service factories that are registered with the $httpProvider by
7711                 * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
7712                 * injected with dependencies (if specified) and returns the interceptor  — a function that
7713                 * takes a {@link ng.$q promise} and returns the original or a new promise.
7714                 *
7715                 * ```js
7716                 *   // register the interceptor as a service
7717                 *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
7718     *     return function(promise) {
7719     *       return promise.then(function(response) {
7720     *         // do something on success
7721     *         return response;
7722     *       }, function(response) {
7723     *         // do something on error
7724     *         if (canRecover(response)) {
7725     *           return responseOrNewPromise
7726     *         }
7727     *         return $q.reject(response);
7728     *       });
7729     *     }
7730     *   });
7731                 *
7732                 *   $httpProvider.responseInterceptors.push('myHttpInterceptor');
7733                 *
7734                 *
7735                 *   // register the interceptor via an anonymous factory
7736                 *   $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
7737     *     return function(promise) {
7738     *       // same as above
7739     *     }
7740     *   });
7741                 * ```
7742                 *
7743                 *
7744                 * # Security Considerations
7745                 *
7746                 * When designing web applications, consider security threats from:
7747                 *
7748                 * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7749                 * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
7750                 *
7751                 * Both server and the client must cooperate in order to eliminate these threats. Angular comes
7752                 * pre-configured with strategies that address these issues, but for this to work backend server
7753                 * cooperation is required.
7754                 *
7755                 * ## JSON Vulnerability Protection
7756                 *
7757                 * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
7758                 * allows third party website to turn your JSON resource URL into
7759                 * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
7760                 * counter this your server can prefix all JSON requests with following str
7760ing `")]}',\n"`.
7761                 * Angular will automatically strip the prefix before processing it as JSON.
7762                 *
7763                 * For example if your server needs to return:
7764                 * ```js
7765                 * ['one','two']
7766                 * ```
7767                 *
7768                 * which is vulnerable to attack, your server can return:
7769                 * ```js
7770                 * )]}',
7771                 * ['one','two']
7772                 * ```
7773                 *
7774                 * Angular will strip the prefix, before processing the JSON.
7775                 *
7776                 *
7777                 * ## Cross Site Request Forgery (XSRF) Protection
7778                 *
7779                 * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
7780                 * an unauthorized site can gain your user's private data. Angular provides a mechanism
7781                 * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
7782                 * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
7783                 * JavaScript that runs on your domain could read the cookie, your server can be assured that
7784                 * the XHR came from JavaScript running on your domain. The header will not be set for
7785                 * cross-domain requests.
7786                 *
7787                 * To take advantage of this, your server needs to set a token in a JavaScript readable session
7788                 * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
7789                 * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
7790                 * that only JavaScript running on your domain could have sent the request. The token must be
7791                 * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7792                 * making up its own tokens). We recommend that the token is a digest of your site's
7793                 * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
7794                 * for added security.
7795                 *
7796                 * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
7797                 * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
7798                 * or the per-request config object.
7799                 *
7800                 *
7801                 * @param {object} config Object describing the request to be made and how it should be
7802                 *    processed. The object has following properties:
7803                 *
7804                 *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
7805                 *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
7806                 *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
7807                 *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
7808                 *      JSONified.
7809                 *    - **data** – `{string|Object}` – Data to be sent as the request message data.
7810                 *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
7811                 *      HTTP headers to send to the server. If the return value of a function is null, the
7812                 *      header will not be sent.
7813                 *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
7814                 *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
7815                 *    - **transformRequest** –
7816                 *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
7817                 *      transform function or an array of such functions. The transform function takes the http
7818                 *      request body and headers and returns its transformed (typically serialized) version.
7819                 *    - **transformResponse** –
7820                 *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>
7820}` –
7821                 *      transform function or an array of such functions. The transform function takes the http
7822                 *      response body and headers and returns its transformed (typically deserialized) version.
7823                 *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
7824                 *      GET request, otherwise if a cache instance built with
7825                 *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
7826                 *      caching.
7827                 *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
7828                 *      that should abort the request when resolved.
7829                 *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
7830                 *      XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5
7831                 *      for more information.
7832                 *    - **responseType** - `{string}` - see
7833                 *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
7834                 *
7835                 * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
7836                 *   standard `then` method and two http specific methods: `success` and `error`. The `then`
7837                 *   method takes two arguments a success and an error callback which will be called with a
7838                 *   response object. The `success` and `error` methods take a single argument - a function that
7839                 *   will be called when the request succeeds or fails respectively. The arguments passed into
7840                 *   these functions are destructured representation of the response object passed into the
7841                 *   `then` method. The response object has these properties:
7842                 *
7843                 *   - **data** – `{string|Object}` – The response body transformed with the transform
7844                 *     functions.
7845                 *   - **status** – `{number}` – HTTP status code of the response.
7846                 *   - **headers** – `{function([headerName])}` – Header getter function.
7847                 *   - **config** – `{Object}` – The configuration object that was used to generate the request.
7848                 *   - **statusText** – `{string}` – HTTP status text of the response.
7849                 *
7850                 * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
7851                 *   requests. This is primarily meant to be used for debugging purposes.
7852                 *
7853                 *
7854                 * @example
7855                 <example>
7856                 <file name="index.jsp">
7857                 <div ng-controller="FetchCtrl">
7858                 <select ng-model="method">
7859                 <option>GET</option>
7860                 <option>JSONP</option>
7861                 </select>
7862                 <input type="text" ng-model="url" size="80"/>
7863                 <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
7864                 <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
7865                 <button id="samplejsonpbtn"
7866                 ng-click="updateModel('JSONP',
7867                 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
7868                 Sample JSONP
7869                 </button>
7870                 <button id="invalidjsonpbtn"
7871                 ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
7872                 Invalid JSONP
7873                 </button>
7874                 <pre>http status code: {{status}}</pre>
7875                 <pre>http response data: {{data}}</pre>
7876                 </div>
7877                 </file>
7878                 <file name="script.js">
7879                 function FetchCtrl($scope, $http, $templateCache) {
7880    $scope.method = 'GET';
7881    $scope.url = 'http-hello.html';
7882
7883    $scope.fetch = function() {
7884      $scope.code = null;
7885      $scope.response = null;
7886
7887      $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
7888        success(function(data, status) {
7889          $scope.status = status;
7890          $scope.data = data;
7891        }).
7892        error(function(data, status) {
7893          $scope.data = data || "Request failed";
7894          $scope.status = status;
7895      });
7896    };
7897
7898    $scope.updateModel = function(method, url) {
7899      $scope.method = method;
7900      $scope.url = url;
7901    };
7902  }
7903                 </file>
7904                 <file name="http-hello.html">
7905                 Hello, $http!
7906                 </file>
7907                 <file name="protractor.js" type="protractor">
7908                 var status = element(by.binding('status'));
7909                 var data = element(by.binding('data'));
7910                 var fetchBtn = element(by.id('fetchbtn'));
7911                 var sampleGetBtn = element(by.id('samplegetbtn'));
7912                 var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
7913                 var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
7914
7915                 it('should make an xhr GET request', function() {
7916    sampleGetBtn.click();
7917    fetchBtn.click();
7918    expect(status.getText()).toMatch('200');
7919    expect(data.getText()).toMatch(/Hello, \$http!/);
7920  });
7921
7922                 it('should make a JSONP request to angularjs.org', function() {
7923    sampleJsonpBtn.click();
7924    fetchBtn.click();
7925    expect(status.getText()).toMatch('200');
7926    expect(data.getText()).toMatch(/Super Hero!/);
7927  });
7928
7929                 it('should make JSONP request to invalid URL and invoke the error handler',
7930                 function() {
7931    invalidJsonpBtn.click();
7932    fetchBtn.click();
7933    expect(status.getText()).toMatch('0');
7934    expect(data.getText()).toMatch('Request failed');
7935  });
7936                 </file>
7937                 </example>
7938                 */
7939                function $http(requestConfig) {
7940                    var config = {
7941                        method: 'get',
7942                        transformRequest: defaults.transformRequest,
7943                        transformResponse: defaults.transformResponse
7944                    };
7945                    var headers = mergeHeaders(requestConfig);
7946
7947                    extend(config, requestConfig);
7948                    config.headers = headers;
7949                    config.method = uppercase(config.method);
7950
7951                    var xsrfValue = urlIsSameOrigin(config.url)
7952                        ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
7953                        : undefined;
7954                    if (xsrfValue) {
7955                        headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
7956                    }
7957
7958
7959                    var serverRequest = function (config) {
7960                        headers = config.headers;
7961                        var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
7962
7963                        // strip content-type if data is undefined
7964                        if (isUndefined(config.data)) {
7965                            forEach(headers, function (value, header) {
7966                                if (lowercase(header) === 'content-type') {
7967                                    delete headers[header];
7968                                }
7969                            });
7970                        }
7971
7972                        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
7973                            config.withCredentials = defaults.withCredentials;
7974                        }
7975
7976                        // send request
7977                        return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
7978                    };
7979
7980                    var chain = [serverRequest, undefined];
7981                    var promise = $q.when(config);
7982
7983                    // apply interceptors
7984                    forEach(reversedInterceptors, function (interceptor) {
7985                        if (interceptor.request || interceptor.requestError) {
7986                            chain.unshift(interceptor.request, interceptor.requestError);
7987                        }
7988                        if (interceptor.response || interceptor.responseError) {
7989                            chain.push(interceptor.response, interceptor.responseError);
7990                        }
7991                    });
7992
7993                    while (chain.length) {
7994                        var thenFn = chain.shift();
7995                        var rejectFn = chain.shift();
7996
7997                        promise = promise.then(thenFn, rejectFn);
7998                    }
7999
8000                    promise.success = function (fn) {
8001                        promise.then(function (response) {
8002                            fn(response.data, response.status, response.headers, config);
8003                        });
8004                        return promise;
8005                    };
8006
8007                    promise.error = function (fn) {
8008                        promise.then(null, function (response) {
8009                            fn(response.data, response.status, response.headers, config);
8010                        });
8011                        return promise;
8012                    };
8013
8014                    return promise;
8015
8016                    function transformResponse(response) {
8017                        // make a copy since the response must be cacheable
8018                        var resp = extend({}, response, {
8019                            data: transformData(response.data, response.headers, config.transformResponse)
8020                        });
8021                        return (isSuccess(response.status))
8022                            ? resp
8023                            : $q.reject(resp);
8024                    }
8025
8026                    function mergeHeaders(config) {
8027                        var defHeaders = defaults.headers,
8028                            reqHeaders = extend({}, config.headers),
8029                            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
8030
8031                        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
8032
8033                        // execute if header value is function
8034                        execHeaders(defHeaders);
8035                        execHeaders(reqHeaders);
8036
8037                        // using for-in instead of forEach to avoid unecessary iteration after header has been found
8038                        defaultHeadersIteration:
8039                            for (defHeaderName in defHeaders) {
8040                                lowercaseDefHeaderName = lowercase(defHeaderName);
8041
8042                                for (reqHeaderName in reqHeaders) {
8043                                    if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
8044                                        continue defaultHeadersIteration;
8045                                    }
8046                                }
8047
8048                                reqHeaders[defHeaderName] = defHeaders[defHeaderName];
8049                            }
8050
8051                        return reqHeaders;
8052
8053                        function execHeaders(headers) {
8054                            var headerContent;
8055
8056                            forEach(headers, function (headerFn, header) {
8057                                if (isFunction(headerFn)) {
8058                                    headerContent = headerFn();
8059                                    if (headerContent != null) {
8060                                        headers[header] = headerContent;
8061                                    } else {
8062                                        delete headers[header];
8063                                    }
8064                                }
8065                            });
8066                        }
8067                    }
8068                }
8069
8070                $http.pendingRequests = [];
8071
8072                /**
8073                 * @ngdoc method
8074                 * @name $http#get
8075                 *
8076                 * @description
8077                 * Shortcut method to perform `GET` request.
8078                 *
8079                 * @param {string} url Relative or absolute URL specifying the destination of the request
8080                 * @param {Object=} config Optional configuration object
8081                 * @returns {HttpPromise} Future object
8082                 */
8083
8084                /**
8085                 * @ngdoc method
8086                 * @name $http#delete
8087                 *
8088                 * @description
8089                 * Shortcut method to perform `DELETE` request.
8090                 *
8091                 * @param {string} url Relative or absolute URL specifying the destination of the request
8092                 * @param {Object=} config Optional configuration object
8093                 * @returns {HttpPromise} Future object
8094                 */
8095
8096                /**
8097                 * @ngdoc method
8098                 * @name $http#head
8099                 *
8100                 * @description
8101                 * Shortcut method to perform `HEAD` request.
8102                 *
8103                 * @param {string} url Relative or absolute URL specifying the destination of the request
8104                 * @param {Object=} config Optional configuration object
8105                 * @returns {HttpPromise} Future object
8106                 */
8107
8108                /**
8109                 * @ngdoc method
8110                 * @name $http#jsonp
8111                 *
8112                 * @description
8113                 * Shortcut method to perform `JSONP` request.
8114                 *
8115                 * @param {string} url Relative or absolute URL specifying the destination of the request.
8116                 *                     Should contain `JSON_CALLBACK` string.
8117                 * @param {Object=} config Optional configuration object
8118                 * @returns {HttpPromise} Future object
8119                 */
8120                createShortMethods('get', 'delete', 'head', 'jsonp');
8121
8122                /**
8123                 * @ngdoc method
8124                 * @name $http#post
8125                 *
8126                 * @description
8127                 * Shortcut method to perform `POST` request.
8128                 *
8129                 * @param {string} url Relative or absolute URL specifying the destination of the request
8130                 * @param {*} data Request content
8131                 * @param {Object=} config Optional configuration object
8132                 * @returns {HttpPromise} Future object
8133                 */
8134
8135                /**
8136                 * @ngdoc method
8137                 * @name $http#put
8138                 *
8139                 * @description
8140                 * Shortcut method to perform `PUT` request.
8141                 *
8142                 * @param {string} url Relative or absolute URL specifying the destination of the request
8143                 * @param {*} data Request content
8144                 * @param {Object=} config Optional configuration object
8145                 * @returns {HttpPromise} Future object
8146                 */
8147                createShortMethodsWithData('post', 'put');
8148
8149                /**
8150                 * @ngdoc property
8151                 * @name $http#defaults
8152                 *
8153                 * @description
8154                 * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
8155                 * default headers, withCredentials as well as request and response transformations.
8156                 *
8157                 * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
8158                 */
8159                $http.defaults = defaults;
8160
8161
8162                return $http;
8163
8164
8165                function createShortMethods(names) {
8166                    forEach(arguments, function (name) {
8167                        $http[name] = function (url, config) {
8168                            return $http(extend(config || {}, {
8169                                method: name,
8170                                url: url
8171                            }));
8172                        };
8173                    });
8174                }
8175
8176
8177                function createShortMethodsWithData(name) {
8178                    forEach(arguments, function (name) {
8179                        $http[name] = function (url, data, config) {
8180                            return $http(extend(config || {}, {
8181                                method: name,
8182                                url: url,
8183                                data: data
8184                            }));
8185                        };
8186                    });
8187                }
8188
8189
8190                /**
8191                 * Makes the request.
8192                 *
8193                 * !!! ACCESSES CLOSURE VARS:
8194                 * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
8195                 */
8196                function sendReq(config, reqData, reqHeaders) {
8197                    var deferred = $q.defer(),
8198                        promise = deferred.promise,
8199                        cache,
8200                        cachedResp,
8201                        url = buildUrl(config.url, config.params);
8202
8203                    $http.pendingRequests.push(config);
8204                    promise.then(removePendingReq, removePendingReq);
8205
8206
8207                    if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
8208                        cache = isObject(config.cache) ? config.cache
8209                            : isObject(defaults.cache) ? defaults.cache
8210                            : defaultCache;
8211                    }
8212
8213                    if (cache) {
8214                        cachedResp = cache.get(url);
8215                        if (isDefined(cachedResp)) {
8216                            if (cachedResp.then) {
8217                                // cached request has already been sent, but there is no response yet
8218                                cachedResp.then(removePendingReq, removePendingReq);
8219                                return cachedResp;
8220                            } else {
8221                                // serving from cache
8222                                if (isArray(cachedResp)) {
8223                                    resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]), cachedResp[3]);
8224                                } else {
8225                                    resolvePromise(cachedResp, 200, {}, 'OK');
8226                                }
8227                            }
8228                        } else {
8229                            // put the promise for the non-transformed response into cache as a placeholder
8230                            cache.put(url, promise);
8231                        }
8232                    }
8233
8234                    // if we won't have the response in cache, send the request to the backend
8235                    if (isUndefined(cachedResp)) {
8236                        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
8237                            config.withCredentials, config.responseType);
8238                    }
8239
8240                    return promise;
8241
8242
8243                    /**
8244                     * Callback registered to $httpBackend():
8245                     *  - caches the response if desired
8246                     *  - resolves the raw $http promise
8247                     *  - calls $apply
8248                     */
8249                    function done(status, response, headersString, statusText) {
8250                        if (cache) {
8251                            if (isSuccess(status)) {
8252                                cache.put(url, [status, response, parseHeaders(headersString), statusText]);
8253                            } else {
8254                                // remove promise from the cache
8255                                cache.remove(url);
8256                            }
8257                        }
8258
8259                        resolvePromise(response, status, headersString, statusText);
8260                        if (!$rootScope.$$phase) $rootScope.$apply();
8261                    }
8262
8263
8264                    /**
8265                     * Resolves the raw $http promise.
8266                     */
8267                    function resolvePromise(response, status, headers, statusText) {
8268                        // normalize internal statuses to 0
8269                        status = Math.max(status, 0);
8270
8271                        (isSuccess(status) ? deferred.resolve : deferred.reject)({
8272                            data: response,
8273                            status: status,
8274                            headers: headersGetter(headers),
8275                            config: config,
8276                            statusText: statusText
8277                        });
8278                    }
8279
8280
8281                    function removePendingReq() {
8282                        var idx = indexOf($http.pendingRequests, config);
8283                        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
8284                    }
8285                }
8286
8287
8288                function buildUrl(url, params) {
8289                    if (!params) return url;
8290                    var parts = [];
8291                    forEachSorted(params, function (value, key) {
8292                        if (value === null || isUndefined(value)) return;
8293                        if (!isArray(value)) value = [value];
8294
8295                        forEach(value, function (v) {
8296                            if (isObject(v)) {
8297                                v = toJson(v);
8298                            }
8299                            parts.push(encodeUriQuery(key) + '=' +
8300                                encodeUriQuery(v));
8301                        });
8302                    });
8303                    if (parts.length > 0) {
8304                        url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
8305                    }
8306                    return url;
8307                }
8308
8309
8310            }];
8311    }
8312
8313    function createXhr(method) {
8314        //if IE and the method is not RFC2616 compliant, or if XMLHttpRequest
8315        //is not available, try getting an ActiveXObject. Otherwise, use XMLHttpRequest
8316        //if it is available
8317        if (msie <= 8 && (!method.match(/^(get|post|head|put|delete|options)$/i) || !window.XMLHttpRequest)) {
8318            return new window.ActiveXObject("Microsoft.XMLHTTP");
8319        } else if (window.XMLHttpRequest) {
8320            return new window.XMLHttpRequest();
8321        }
8322
8323        throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
8324    }
8325
8326    /**
8327     * @ngdoc service
8328     * @name $httpBackend
8329     * @requires $window
8330     * @requires $document
8331     *
8332     * @description
8333     * HTTP backend used by the {@link ng.$http service} that delegates to
8334     * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
8335     *
8336     * You should never need to use this service directly, instead use the higher-level abstractions:
8337     * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
8338     *
8339     * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
8340 * $httpBackend} which can be trained with responses.
8341     */
8342    function $HttpBackendProvider() {
8343        this.$get = ['$browser', '$window', '$document', function ($browser, $window, $document) {
8344            return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
8345        }];
8346    }
8347
8348    function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
8349        var ABORTED = -1;
8350
8351        // TODO(vojta): fix the signature
8352        return function (method, url, post, callback, headers, timeout, withCredentials, responseType) {
8353            var status;
8354            $browser.$$incOutstandingRequestCount();
8355            url = url || $browser.url();
8356
8357            if (lowercase(method) == 'jsonp') {
8358                var callbackId = '_' + (callbacks.counter++).toString(36);
8359                callbacks[callbackId] = function (data) {
8360                    callbacks[callbackId].data = data;
8361                };
8362
8363                var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
8364                    function () {
8365                        if (callbacks[callbackId].data) {
8366                            completeRequest(callback, 200, callbacks[callbackId].data);
8367                        } else {
8368                            completeRequest(callback, status || -2);
8369                        }
8370                        callbacks[callbackId] = angular.noop;
8371                    });
8372            } else {
8373
8374                var xhr = createXhr(method);
8375
8376                xhr.open(method, url, true);
8377                forEach(headers, function (value, key) {
8378                    if (isDefined(value)) {
8379                        xhr.setRequestHeader(key, value);
8380                    }
8381                });
8382
8383                // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
8384                // response is in the cache. the promise api will ensure that to the app code the api is
8385                // always async
8386                xhr.onreadystatechange = function () {
8387                    // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
8388                    // xhrs that are resolved while the app is in the background (see #5426).
8389                    // since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
8390                    // continuing
8391                    //
8392                    // we can't set xhr.onreadystatechange to undefined or delete it because that breaks IE8 (method=PATCH) and
8393                    // Safari respectively.
8394                    if (xhr && xhr.readyState == 4) {
8395                        var responseHeaders = null,
8396                            response = null;
8397
8398                        if (status !== ABORTED) {
8399                            responseHeaders = xhr.getAllResponseHeaders();
8400
8401                            // responseText is the old-school way of retrieving response 
8401(supported by IE8 & 9)
8402                            // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
8403                            response = ('response' in xhr) ? xhr.response : xhr.responseText;
8404                        }
8405
8406                        completeRequest(callback,
8407                            status || xhr.status,
8408                            response,
8409                            responseHeaders,
8410                            xhr.statusText || '');
8411                    }
8412                };
8413
8414                if (withCredentials) {
8415                    xhr.withCredentials = true;
8416                }
8417
8418                if (responseType) {
8419                    try {
8420                        xhr.responseType = responseType;
8421                    } catch (e) {
8422                        // WebKit added support for the json responseType value on 09/03/2013
8423                        // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
8424                        // known to throw when setting the value "json" as the response type. Other older
8425                        // browsers implementing the responseType
8426                        //
8427                        // The json response type can be ignored if not supported, because JSON payloads are
8428                        // parsed on the client-side regardless.
8429                        if (responseType !== 'json') {
8430                            throw e;
8431                        }
8432                    }
8433                }
8434
8435                xhr.send(post || null);
8436            }
8437
8438            if (timeout > 0) {
8439                var timeoutId = $browserDefer(timeoutRequest, timeout);
8440            } else if (timeout && timeout.then) {
8441                timeout.then(timeoutRequest);
8442            }
8443
8444
8445            function timeoutRequest() {
8446                status = ABORTED;
8447                jsonpDone && jsonpDone();
8448                xhr && xhr.abort();
8449            }
8450
8451            function completeRequest(callback, status, response, headersString, statusText) {
8452                // cancel timeout and subsequent timeout promise resolution
8453                timeoutId && $browserDefer.cancel(timeoutId);
8454                jsonpDone = xhr = null;
8455
8456                // fix status code when it is 0 (0 status is undocumented).
8457                // Occurs when accessing file resources or on Android 4.1 stock browser
8458                // while retrieving files from application cache.
8459                if (status === 0) {
8460                    status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
8461                }
8462
8463                // normalize IE bug (http://bugs.jquery.com/ticket/1450)
8464                status = status === 1223 ? 204 : status;
8465                statusText = statusText || '';
8466
8467                callback(status, response, headersString, statusText);
8468                $browser.$$completeOutstandingRequest(noop);
8469            }
8470        };
8471
8472        function jsonpReq(url, done) {
8473            // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
8474            // - fetches local scripts via XHR and evals them
8475            // - adds and immediately removes script elements from the document
8476            var script = rawDocument.createElement('script'),
8477                doneWrapper = function () {
8478                    script.onreadystatechange = script.onload = script.onerror = null;
8479                    rawDocument.body.removeChild(script);
8480                    if (done) done();
8481                };
8482
8483            script.type = 'text/javascript';
8484            script.src = url;
8485
8486            if (msie && msie <= 8) {
8487                script.onreadystatechange = function () {
8488                    if (/loaded|complete/.test(script.readyState)) {
8489                        doneWrapper();
8490                    }
8491                };
8492            } else {
8493                script.onload = script.onerror = function () {
8494                    doneWrapper();
8495                };
8496            }
8497
8498            rawDocument.body.appendChild(script);
8499            return doneWrapper;
8500        }
8501    }
8502
8503    var $interpolateMinErr = minErr('$interpolate');
8504
8505    /**
8506     * @ngdoc provider
8507     * @name $interpolateProvider
8508     * @function
8509     *
8510     * @description
8511     *
8512     * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
8513     *
8514     * @example
8515     <example module="customInterpolationApp">
8516     <file name="index.jsp">
8517     <script>
8518     var customInterpolationApp = angular.module('customInterpolationApp', []);
8519
8520     customInterpolationApp.config(function($interpolateProvider) {
8521    $interpolateProvider.startSymbol('//');
8522    $interpolateProvider.endSymbol('//');
8523  });
8524
8525
8526     customInterpolationApp.controller('DemoController', function DemoController() {
8527      this.label = "This binding is brought you by // interpolation symbols.";
8528  });
8529     </script>
8530     <div ng-app="App" ng-controller="DemoController as demo">
8531     //demo.label//
8532     </div>
8533     </file>
8534     <file name="protractor.js" type="protractor">
8535     it('should interpolate binding with custom symbols', function() {
8536    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
8537  });
8538     </file>
8539     </example>
8540     */
8541    function $InterpolateProvider() {
8542        var startSymbol = '{{';
8543        var endSymbol = '}}';
8544
8545        /**
8546         * @ngdoc method
8547         * @name $interpolateProvider#startSymbol
8548         * @description
8549         * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
8550   *
8551   * @param {string=} value new value to set the starting symbol to.
8552         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8553         */
8554        this.startSymbol = function (value) {
8555            if (value) {
8556                startSymbol = value;
8557                return this;
8558            } else {
8559                return startSymbol;
8560            }
8561        };
8562
8563        /**
8564         * @ngdoc method
8565         * @name $interpolateProvider#endSymbol
8566         * @description
8567         * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8568         *
8569         * @param {string=} value new value to set the ending symbol to.
8570         * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
8571         */
8572        this.endSymbol = function (value) {
8573            if (value) {
8574                endSymbol = value;
8575                return this;
8576            } else {
8577                return endSymbol;
8578            }
8579        };
8580
8581
8582        this.$get = ['$parse', '$exceptionHandler', '$sce', function ($parse, $exceptionHandler, $sce) {
8583            var startSymbolLength = startSymbol.length,
8584                endSymbolLength = endSymbol.length;
8585
8586            /**
8587             * @ngdoc service
8588             * @name $interpolate
8589             * @function
8590             *
8591             * @requires $parse
8592             * @requires $sce
8593             *
8594             * @description
8595             *
8596             * Compiles a string with markup into an interpolation function. This service is used by the
8597             * HTML {@link ng.$compile $compile} service for data binding. See
8598             * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
8599             * interpolation markup.
8600             *
8601             *
8602             * ```js
8603             *   var $interpolate = ...; // injected
8604             *   var exp = $interpolate('Hello {{name | uppercase}}!');
8605             *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8606             * ```
8607             *
8608             *
8609             * @param {string} text The text with markup to interpolate.
8610             * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
8611             *    embedded expression in order to return an interpolation function. Strings with no
8612             *    embedded expression will return null for the interpolation function.
8613             * @param {string=} trustedContext when provided, the returned function passes the interpolated
8614             *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
8615     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
8616             *    provides Strict Contextual Escaping for details.
8617             * @returns {function(context)} an interpolation function which is used to compute the
8618             *    interpolated string. The function has these parameters:
8619             *
8620             *    * `context`: an object against which any expressions embedded in the strings are evaluated
8621             *      against.
8622             *
8623             */
8624            function $interpolate(text, mustHaveExpression, trustedContext) {
8625                var startIndex,
8626                    endIndex,
8627                    index = 0,
8628                    parts = [],
8629                    length = text.length,
8630                    hasInterpolation = false,
8631                    fn,
8632                    exp,
8633                    concat = [];
8634
8635                while (index < length) {
8636                    if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
8637                        ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
8638                        (index != startIndex) && parts.push(text.substring(index, startIndex));
8639                        parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
8640                        fn.exp = exp;
8641                        index = endIndex + endSymbolLength;
8642                        hasInterpolation = true;
8643                    } else {
8644                        // we did not find anything, so we have to add the remainder to the parts array
8645                        (index != length) && parts.push(text.substring(index));
8646                        index = length;
8647                    }
8648                }
8649
8650                if (!(length = parts.length)) {
8651                    // we added, nothing, must have been an empty string.
8652                    parts.push('');
8653                    length = 1;
8654                }
8655
8656                // Concatenating expressions makes it hard to reason about whether some combination of
8657                // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
8658                // single expression be used for iframe[src], object[src], etc., we ensure that the value
8659                // that's used is assigned or constructed by some JS code somewhere that is more testable or
8660                // make it obvious that you bound the value to some user controlled value.  This helps reduce
8661                // the load when auditing for XSS issues.
8662                if (trustedContext && parts.length > 1) {
8663                    throw $interpolateMinErr('noconcat',
8664                        "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
8665                            "interpolations that concatenate multiple expressions when a trusted value is " +
8666                            "required.  See http://docs.angularjs.org/api/ng.$sce", text);
8667                }
8668
8669                if (!mustHaveExpression || hasInterpolation) {
8670                    concat.length = length;
8671                    fn = function (context) {
8672                        try {
8673                            for (var i = 0, ii = length, part; i < ii; i++) {
8674                                if (typeof (part = parts[i]) == 'function') {
8675                                    part = part(context);
8676                                    if (trustedContext) {
8677                                        part = $sce.getTrusted(trustedContext, part);
8678                                    } else {
8679                                        part = $sce.valueOf(part);
8680                                    }
8681                                    if (part === null || isUndefined(part)) {
8682                                        part = '';
8683                                    } else if (typeof part != 'string') {
8684                                        part = toJson(part);
8685                                    }
8686                                }
8687                                concat[i] = part;
8688                            }
8689                            return concat.join('');
8690                        }
8691                        catch (err) {
8692                            var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
8693                                err.toString());
8694                            $exceptionHandler(newErr);
8695                        }
8696                    };
8697                    fn.exp = text;
8698                    fn.parts = parts;
8699                    return fn;
8700                }
8701            }
8702
8703
8704            /**
8705             * @ngdoc method
8706             * @name $interpolate#startSymbol
8707             * @description
8708             * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8709     *
8710     * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8711             * the symbol.
8712             *
8713             * @returns {string} start symbol.
8714             */
8715            $interpolate.startSymbol = function () {
8716                return startSymbol;
8717            };
8718
8719
8720            /**
8721             * @ngdoc method
8722             * @name $interpolate#endSymbol
8723             * @description
8724             * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8725             *
8726             * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8727             * the symbol.
8728             *
8729             * @returns {string} end symbol.
8730             */
8731            $interpolate.endSymbol = function () {
8732                return endSymbol;
8733            };
8734
8735            return $interpolate;
8736        }];
8737    }
8738
8739    function $IntervalProvider() {
8740        this.$get = ['$rootScope', '$window', '$q',
8741            function ($rootScope, $window, $q) {
8742                var intervals = {};
8743
8744
8745                /**
8746                 * @ngdoc service
8747                 * @name $interval
8748                 *
8749                 * @description
8750                 * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
8751                 * milliseconds.
8752                 *
8753                 * The return value of registering an interval function is a promise. This promise will be
8754                 * notified upon each tick of the interval, and will be resolved after `count` iterations, or
8755                 * run indefinitely if `count` is not defined. The value of the notification will be the
8756                 * number of iterations that have run.
8757                 * To cancel an interval, call `$interval.cancel(promise)`.
8758                 *
8759                 * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
8760                 * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
8761                 * time.
8762                 *
8763                 * <div class="alert alert-warning">
8764                 * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
8765                 * with them.  In particular they are not automatically destroyed when a controller's scope or a
8766                 * directive's element are destroyed.
8767                 * You should take this into consideration and make sure to always cancel the interval at the
8768                 * appropriate moment.  See the example below for more details on how and when to do this.
8769                 * </div>
8770                 *
8771                 * @param {function()} fn A function that should be called repeatedly.
8772                 * @param {number} delay Number of milliseconds between each function call.
8773                 * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
8774                 *   indefinitely.
8775                 * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
8776                 *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
8777                 * @returns {promise} A promise which will be notified on each iteration.
8778                 *
8779                 * @example
8780                 * <example module="time">
8781                 *   <file name="index.jsp">
8782                 *     <script>
8783                 *       function Ctrl2($scope,$interval) {
8784      *         $scope.format = 'M/d/yy h:mm:ss a';
8785      *         $scope.blood_1 = 100;
8786      *         $scope.blood_2 = 120;
8787      *
8788      *         var stop;
8789      *         $scope.fight = function() {
8790      *           // Don't start a new fight if we are already fighting
8791      *           if ( angular.isDefined(stop) ) return;
8792      *
8793      *           stop = $interval(function() {
8794      *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
8795      *                 $scope.blood_1 = $scope.blood_1 - 3;
8796      *                 $scope.blood_2 = $scope.blood_2 - 4;
8797      *             } else {
8798      *                 $scope.stopFight();
8799      *             }
8800      *           }, 100);
8801      *         };
8802      *
8803      *         $scope.stopFight = function() {
8804      *           if (angular.isDefined(stop)) {
8805      *             $interval.cancel(stop);
8806      *             stop = undefined;
8807      *           }
8808      *         };
8809      *
8810      *         $scope.resetFight = function() {
8811      *           $scope.blood_1 = 100;
8812      *           $scope.blood_2 = 120;
8813      *         }
8814      *
8815      *         $scope.$on('$destroy', function() {
8816      *           // Make sure that the interval is destroyed too
8817      *           $scope.stopFight();
8818      *         });
8819      *       }
8820                 *
8821                 *       angular.module('time', [])
8822                 *         // Register the 'myCurrentTime' directive factory method.
8823                 *         // We inject $interval and dateFilter service since the factory method is DI.
8824                 *         .directive('myCurrentTime', function($interval, dateFilter) {
8825      *           // return the directive link function. (compile function not needed)
8826      *           return function(scope, element, attrs) {
8827      *             var format,  // date format
8828      *             stopTime; // so that we can cancel the time updates
8829      *
8830      *             // used to update the UI
8831      *             function updateTime() {
8832      *               element.text(dateFilter(new Date(), format));
8833      *             }
8834      *
8835      *             // watch the expression, and update the UI on change.
8836      *             scope.$watch(attrs.myCurrentTime, function(value) {
8837      *               format = value;
8838      *               updateTime();
8839      *             });
8840      *
8841      *             stopTime = $interval(updateTime, 1000);
8842      *
8843      *             // listen on DOM destroy (removal) event, and cancel the next UI update
8844      *             // to prevent updating time ofter the DOM element was removed.
8845      *             element.bind('$destroy', function() {
8846      *               $interval.cancel(stopTime);
8847      *             });
8848      *           }
8849      *         });
8850                 *     </script>
8851                 *
8852                 *     <div>
8853                 *       <div ng-controller="Ctrl2">
8854                 *         Date format: <input ng-model="format"> <hr/>
8855                 *         Current time is: <span my-current-time="format"></span>
8856                 *         <hr/>
8857                 *         Blood 1 : <font color='red'>{{blood_1}}</font>
8858                 *         Blood 2 : <font color='red'>{{blood_2}}</font>
8859                 *         <button type="button" data-ng-click="fight()">Fight</button>
8860                 *         <button type="button" data-ng-click="stopFight()">StopFight</button>
8861                 *         <button type="button" data-ng-click="resetFight()">resetFight</button>
8862                 *       </div>
8863                 *     </div>
8864                 *
8865                 *   </file>
8866                 * </example>
8867                 */
8868                function interval(fn, delay, count, invokeApply) {
8869                    var setInterval = $window.setInterval,
8870                        clearInterval = $window.clearInterval,
8871                        deferred = $q.defer(),
8872                        promise = deferred.promise,
8873                        iteration = 0,
8874                        skipApply = (isDefined(invokeApply) && !invokeApply);
8875
8876                    count = isDefined(count) ? count : 0;
8877
8878                    promise.then(null, null, fn);
8879
8880                    promise.$$intervalId = setInterval(function tick() {
8881                        deferred.notify(iteration++);
8882
8883                        if (count > 0 && iteration >= count) {
8884                            deferred.resolve(iteration);
8885                            clearInterval(promise.$$intervalId);
8886                            delete intervals[promise.$$intervalId];
8887                        }
8888
8889                        if (!skipApply) $rootScope.$apply();
8890
8891                    }, delay);
8892
8893                    intervals[promise.$$intervalId] = deferred;
8894
8895                    return promise;
8896                }
8897
8898
8899                /**
8900                 * @ngdoc method
8901                 * @name $interval#cancel
8902                 *
8903                 * @description
8904                 * Cancels a task associated with the `promise`.
8905                 *
8906                 * @param {promise} promise returned by the `$interval` function.
8907                 * @returns {boolean} Returns `true` if the task was successfully canceled.
8908                 */
8909                interval.cancel = function (promise) {
8910                    if (promise && promise.$$intervalId in intervals) {
8911                        intervals[promise.$$intervalId].reject('canceled');
8912                        clearInterval(promise.$$intervalId);
8913                        delete intervals[promise.$$intervalId];
8914                        return true;
8915                    }
8916                    return false;
8917                };
8918
8919                return interval;
8920            }];
8921    }
8922
8923    /**
8924     * @ngdoc service
8925     * @name $locale
8926     *
8927     * @description
8928     * $locale service provides localization rules for various Angular components. As of right now the
8929     * only public api is:
8930     *
8931     * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
8932     */
8933    function $LocaleProvider() {
8934        this.$get = function () {
8935            return {
8936                id: 'en-us',
8937
8938                NUMBER_FORMATS: {
8939                    DECIMAL_SEP: '.',
8940                    GROUP_SEP: ',',
8941                    PATTERNS: [
8942                        { // Decimal Pattern
8943                            minInt: 1,
8944                            minFrac: 0,
8945                            maxFrac: 3,
8946                            posPre: '',
8947                            posSuf: '',
8948                            negPre: '-',
8949                            negSuf: '',
8950                            gSize: 3,
8951                            lgSize: 3
8952                        },
8953                        { //Currency Pattern
8954                            minInt: 1,
8955                            minFrac: 2,
8956                            maxFrac: 2,
8957                            posPre: '\u00A4',
8958                            posSuf: '',
8959                            negPre: '(\u00A4',
8960                            negSuf: ')',
8961                            gSize: 3,
8962                            lgSize: 3
8963                        }
8964                    ],
8965                    CURRENCY_SYM: '$'
8966                },
8967
8968                DATETIME_FORMATS: {
8969                    MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
8970                        .split(','),
8971                    SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
8972                    DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
8973                    SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
8974                    AMPMS: ['AM', 'PM'],
8975                    medium: 'MMM d, y h:mm:ss a',
8976                    short: 'M/d/yy h:mm a',
8977                    fullDate: 'EEEE, MMMM d, y',
8978                    longDate: 'MMMM d, y',
8979                    mediumDate: 'MMM d, y',
8980                    shortDate: 'M/d/yy',
8981                    mediumTime: 'h:mm:ss a',
8982                    shortTime: 'h:mm a'
8983                },
8984
8985                pluralCat: function (num) {
8986                    if (num === 1) {
8987                        return 'one';
8988                    }
8989                    return 'other';
8990                }
8991            };
8992        };
8993    }
8994
8995    var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
8996        DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
8997    var $locationMinErr = minErr('$location');
8998
8999
9000    /**
9001     * Encode path using encodeUriSegment, ignoring forward slashes
9002     *
9003     * @param {string} path Path to encode
9004     * @returns {string}
9005     */
9006    function encodePath(path) {
9007        var segments = path.split('/'),
9008            i = segments.length;
9009
9010        while (i--) {
9011            segments[i] = encodeUriSegment(segments[i]);
9012        }
9013
9014        return segments.join('/');
9015    }
9016
9017    function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
9018        var parsedUrl = urlResolve(absoluteUrl, appBase);
9019
9020        locationObj.$$protocol = parsedUrl.protocol;
9021        locationObj.$$host = parsedUrl.hostname;
9022        locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
9023    }
9024
9025
9026    function parseAppUrl(relativeUrl, locationObj, appBase) {
9027        var prefixed = (relativeUrl.charAt(0) !== '/');
9028        if (prefixed) {
9029            relativeUrl = '/' + relativeUrl;
9030        }
9031        var match = urlResolve(relativeUrl, appBase);
9032        locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
9033            match.pathname.substring(1) : match.pathname);
9034        locationObj.$$search = parseKeyValue(match.search);
9035        locationObj.$$hash = decodeURIComponent(match.hash);
9036
9037        // make sure path starts with '/';
9038        if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
9039            locationObj.$$path = '/' + locationObj.$$path;
9040        }
9041    }
9042
9043
9044    /**
9045     *
9046     * @param {string} begin
9047     * @param {string} whole
9048     * @returns {string} returns text from whole after begin or undefined if it does not begin with
9049     *                   expected string.
9050     */
9051    function beginsWith(begin, whole) {
9052        if (whole.indexOf(begin) === 0) {
9053            return whole.substr(begin.length);
9054        }
9055    }
9056
9057
9058    function stripHash(url) {
9059        var index = url.indexOf('#');
9060        return index == -1 ? url : url.substr(0, index);
9061    }
9062
9063
9064    function stripFile(url) {
9065        return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
9066    }
9067
9068    /* return the server only (scheme://host:port) */
9069    function serverBase(url) {
9070        return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
9071    }
9072
9073
9074    /**
9075     * LocationHtml5Url represents an url
9076     * This object is exposed as $location service when HTML5 mode is enabled and supported
9077     *
9078     * @constructor
9079     * @param {string} appBase application base URL
9080     * @param {string} basePrefix url path prefix
9081     */
9082    function LocationHtml5Url(appBase, basePrefix) {
9083        this.$$html5 = true;
9084        basePrefix = basePrefix || '';
9085        var appBaseNoFile = stripFile(appBase);
9086        parseAbsoluteUrl(appBase, this, appBase);
9087
9088
9089        /**
9090         * Parse given html5 (regular) url string into properties
9091         * @param {string} newAbsoluteUrl HTML5 url
9092         * @private
9093         */
9094        this.$$parse = function (url) {
9095            var pathUrl = beginsWith(appBaseNoFile, url);
9096            if (!isString(pathUrl)) {
9097                throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
9098                    appBaseNoFile);
9099            }
9100
9101            parseAppUrl(pathUrl, this, appBase);
9102
9103            if (!this.$$path) {
9104                this.$$path = '/';
9105            }
9106
9107            this.$$compose();
9108        };
9109
9110        /**
9111         * Compose url and update `absUrl` property
9112         * @private
9113         */
9114        this.$$compose = function () {
9115            var search = toKeyValue(this.$$search),
9116                hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9117
9118            this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9119            this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
9120        };
9121
9122        this.$$rewrite = function (url) {
9123            var appUrl, prevAppUrl;
9124
9125            if ((appUrl = beginsWith(appBase, url)) !== undefined) {
9126                prevAppUrl = appUrl;
9127                if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) {
9128                    return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
9129                } else {
9130                    return appBase + prevAppUrl;
9131                }
9132            } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) {
9133                return appBaseNoFile + appUrl;
9134            } else if (appBaseNoFile == url + '/') {
9135                return appBaseNoFile;
9136            }
9137        };
9138    }
9139
9140
9141    /**
9142     * LocationHashbangUrl represents url
9143     * This object is exposed as $location service when developer doesn't opt into html5 mode.
9144     * It also serves as the base class for html5 mode fallback on legacy browsers.
9145     *
9146     * @constructor
9147     * @param {string} appBase application base URL
9148     * @param {string} hashPrefix hashbang prefix
9149     */
9150    function LocationHashbangUrl(appBase, hashPrefix) {
9151        var appBaseNoFile = stripFile(appBase);
9152
9153        parseAbsoluteUrl(appBase, this, appBase);
9154
9155
9156        /**
9157         * Parse given hashbang url into properties
9158         * @param {string} url Hashbang url
9159         * @private
9160         */
9161        this.$$parse = function (url) {
9162            var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
9163            var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
9164                ? beginsWith(hashPrefix, withoutBaseUrl)
9165                : (this.$$html5)
9166                ? withoutBaseUrl
9167                : '';
9168
9169            if (!isString(withoutHashUrl)) {
9170                throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
9171                    hashPrefix);
9172            }
9173            parseAppUrl(withoutHashUrl, this, appBase);
9174
9175            this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
9176
9177            this.$$compose();
9178
9179            /*
9180             * In Windows, on an anchor node on documents loaded from
9181             * the filesystem, the browser will return a pathname
9182             * prefixed with the drive name ('/C:/path') when a
9183             * pathname without a drive is set:
9184             *  * a.setAttribute('href', '/foo')
9185             *   * a.pathname === '/C:/foo' //true
9186             *
9187             * Inside of Angular, we're always using pathnames that
9188             * do not include drive names for routing.
9189             */
9190            function removeWindowsDriveName(path, url, base) {
9191                /*
9192                 Matches paths for file protocol on windows,
9193                 such as /C:/foo/bar, and captures only /foo/bar.
9194                 */
9195                var windowsFilePathExp = /^\/?.*?:(\/.*)/;
9196
9197                var firstPathSegmentMatch;
9198
9199                //Get the relative path from the input URL.
9200                if (url.indexOf(base) === 0) {
9201                    url = url.replace(base, '');
9202                }
9203
9204                /*
9205                 * The input URL intentionally contains a
9206                 * first path segment that ends with a colon.
9207                 */
9208                if (windowsFilePathExp.exec(url)) {
9209                    return path;
9210                }
9211
9212                firstPathSegmentMatch = windowsFilePathExp.exec(path);
9213                return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
9214            }
9215        };
9216
9217        /**
9218         * Compose hashbang url and update `absUrl` property
9219         * @private
9220         */
9221        this.$$compose = function () {
9222            var search = toKeyValue(this.$$search),
9223                hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
9224
9225            this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
9226            this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
9227        };
9228
9229        this.$$rewrite = function (url) {
9230            if (stripHash(appBase) == stripHash(url)) {
9231                return url;
9232            }
9233        };
9234    }
9235
9236
9237    /**
9238     * LocationHashbangUrl represents url
9239     * This object is exposed as $location service when html5 history api is enabled but the browser
9240     * does not support it.
9241     *
9242     * @constructor
9243     * @param {string} appBase application base URL
9244     * @param {string} hashPrefix hashbang prefix
9245     */
9246    function LocationHashbangInHtml5Url(appBase, hashPrefix) {
9247        this.$$html5 = true;
9248        LocationHashbangUrl.apply(this, arguments);
9249
9250        var appBaseNoFile = stripFile(appBase);
9251
9252        this.$$rewrite = function (url) {
9253            var appUrl;
9254
9255            if (appBase == stripHash(url)) {
9256                return url;
9257            } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
9258                return appBase + hashPrefix + appUrl;
9259            } else if (appBaseNoFile === url + '/') {
9260                return appBaseNoFile;
9261            }
9262        };
9263    }
9264
9265
9266    LocationHashbangInHtml5Url.prototype =
9267        LocationHashbangUrl.prototype =
9268            LocationHtml5Url.prototype = {
9269
9270                /**
9271                 * Are we in html5 mode?
9272                 * @private
9273                 */
9274                $$html5: false,
9275
9276                /**
9277                 * Has any change been replacing ?
9278                 * @private
9279                 */
9280                $$replace: false,
9281
9282                /**
9283                 * @ngdoc method
9284                 * @name $location#absUrl
9285                 *
9286                 * @description
9287                 * This method is getter only.
9288                 *
9289                 * Return full url representation with all segments encoded according to rules specified in
9290                 * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
9291                 *
9292                 * @return {string} full url
9293                 */
9294                absUrl: locationGetter('$$absUrl'),
9295
9296                /**
9297                 * @ngdoc method
9298                 * @name $location#url
9299                 *
9300                 * @description
9301                 * This method is getter / setter.
9302                 *
9303                 * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
9304                 *
9305                 * Change path, search and hash, when called with parameter and return `$location`.
9306                 *
9307                 * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9308                 * @param {string=} replace The path that will be changed
9309                 * @return {string} url
9310                 */
9311                url: function (url, replace) {
9312                    if (isUndefined(url))
9313                        return this.$$url;
9314
9315                    var match = PATH_MATCH.exec(url);
9316                    if (match[1]) this.path(decodeURIComponent(match[1]));
9317                    if (match[2] || match[1]) this.search(match[3] || '');
9318                    this.hash(match[5] || '', replace);
9319
9320                    return this;
9321                },
9322
9323                /**
9324                 * @ngdoc method
9325                 * @name $location#protocol
9326                 *
9327                 * @description
9328                 * This method is getter only.
9329                 *
9330                 * Return protocol of current url.
9331                 *
9332                 * @return {string} protocol of current url
9333                 */
9334                protocol: locationGetter('$$protocol'),
9335
9336                /**
9337                 * @ngdoc method
9338                 * @name $location#host
9339                 *
9340                 * @description
9341                 * This method is getter only.
9342                 *
9343                 * Return host of current url.
9344                 *
9345                 * @return {string} host of current url.
9346                 */
9347                host: locationGetter('$$host'),
9348
9349                /**
9350                 * @ngdoc method
9351                 * @name $location#port
9352                 *
9353                 * @description
9354                 * This method is getter only.
9355                 *
9356                 * Return port of current url.
9357                 *
9358                 * @return {Number} port
9359                 */
9360                port: locationGetter('$$port'),
9361
9362                /**
9363                 * @ngdoc method
9364                 * @name $location#path
9365                 *
9366                 * @description
9367                 * This method is getter / setter.
9368                 *
9369                 * Return path of current url when called without any parameter.
9370                 *
9371                 * Change path when called with parameter and return `$location`.
9372                 *
9373                 * Note: Path should always begin with forward slash (/), this method will add the forward slash
9374                 * if it is missing.
9375                 *
9376                 * @param {string=} path New path
9377                 * @return {string} path
9378                 */
9379                path: locationGetterSetter('$$path', function (path) {
9380                    return path.charAt(0) == '/' ? path : '/' + path;
9381                }),
9382
9383                /**
9384                 * @ngdoc method
9385                 * @name $location#search
9386                 *
9387                 * @description
9388                 * This method is getter / setter.
9389                 *
9390                 * Return search part (as object) of current url when called without any parameter.
9391                 *
9392                 * Change search part when called with parameter and return `$location`.
9393                 *
9394                 * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
9395                 * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
9396                 * the url.
9397                 *
9398                 * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
9399                 * single search parameter. If `paramValue` is an array, it will set the parameter as a
9400                 * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
9401                 *
9402                 * @return {string} search
9403                 */
9404                search: function (search, paramValue) {
9405                    switch (arguments.length) {
9406                        case 0:
9407                            return this.$$search;
9408                        case 1:
9409                            if (isString(search)) {
9410                                this.$$search = parseKeyValue(search);
9411                            } else if (isObject(search)) {
9412                                this.$$search = search;
9413                            } else {
9414                                throw $locationMinErr('isrcharg',
9415                                    'The first argument of the `$location#search()` call must be a string or an object.');
9416                            }
9417                            break;
9418                        default:
9419                            if (isUndefined(paramValue) || paramValue === null) {
9420                                delete this.$$search[search];
9421                            } else {
9422                                this.$$search[search] = paramValue;
9423                            }
9424                    }
9425
9426                    this.$$compose();
9427                    return this;
9428                },
9429
9430                /**
9431                 * @ngdoc method
9432                 * @name $location#hash
9433                 *
9434                 * @description
9435                 * This method is getter / setter.
9436                 *
9437                 * Return hash fragment when called without any parameter.
9438                 *
9439                 * Change hash fragment when called with parameter and return `$location`.
9440                 *
9441                 * @param {string=} hash New hash fragment
9442                 * @return {string} hash
9443                 */
9444                hash: locationGetterSetter('$$hash', identity),
9445
9446                /**
9447                 * @ngdoc method
9448                 * @name $location#replace
9449                 *
9450                 * @description
9451                 * If called, all changes to $location during current `$digest` will be replacing current history
9452                 * record, instead of adding new one.
9453                 */
9454                replace: function () {
9455                    this.$$replace = true;
9456                    return this;
9457                }
9458            };
9459
9460    function locationGetter(property) {
9461        return function () {
9462            return this[property];
9463        };
9464    }
9465
9466
9467    function locationGetterSetter(property, preprocess) {
9468        return function (value) {
9469            if (isUndefined(value))
9470                return this[property];
9471
9472            this[property] = preprocess(value);
9473            this.$$compose();
9474
9475            return this;
9476        };
9477    }
9478
9479
9480    /**
9481     * @ngdoc service
9482     * @name $location
9483     *
9484     * @requires $rootElement
9485     *
9486     * @description
9487     * The $location service parses the URL in the browser address bar (based on the
9488     * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
9489     * available to your application. Changes to the URL in the address bar are reflected into
9490     * $location service and changes to $location are reflected into the browser address bar.
9491     *
9492     * **The $location service:**
9493     *
9494     * - Exposes the current URL in the browser address bar, so you can
9495     *   - Watch and observe the URL.
9496     *   - Change the URL.
9497     * - Synchronizes the URL with the browser when the user
9498     *   - Changes the address bar.
9499     *   - Clicks the back or forward button (or clicks a History link).
9500     *   - Clicks on a link.
9501     * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
9502     *
9503     * For more information see {@link guide/$location Developer Guide: Using $location}
9504     */
9505
9506    /**
9507     * @ngdoc provider
9508     * @name $locationProvider
9509     * @description
9510     * Use the `$locationProvider` to configure how the application deep linking paths are stored.
9511     */
9512    function $LocationProvider() {
9513        var hashPrefix = '',
9514            html5Mode = false;
9515
9516        /**
9517         * @ngdoc property
9518         * @name $locationProvider#hashPrefix
9519         * @description
9520         * @param {string=} prefix Prefix for hash part (containing path and search)
9521         * @returns {*} current value if used as getter or itself (chaining) if used as setter
9522         */
9523        this.hashPrefix = function (prefix) {
9524            if (isDefined(prefix)) {
9525                hashPrefix = prefix;
9526                return this;
9527            } else {
9528                return hashPrefix;
9529            }
9530        };
9531
9532        /**
9533         * @ngdoc property
9534         * @name $locationProvider#html5Mode
9535         * @description
9536         * @param {boolean=} mode Use HTML5 strategy if available.
9537         * @returns {*} current value if used as getter or itself (chaining) if used as setter
9538         */
9539        this.html5Mode = function (mode) {
9540            if (isDefined(mode)) {
9541                html5Mode = mode;
9542                return this;
9543            } else {
9544                return html5Mode;
9545            }
9546        };
9547
9548        /**
9549         * @ngdoc event
9550         * @name $location#$locationChangeStart
9551         * @eventType broadcast on root scope
9552         * @description
9553         * Broadcasted before a URL will change. This change can be prevented by calling
9554         * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
9555         * details about event object. Upon successful change
9556         * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
9557         *
9558         * @param {Object} angularEvent Synthetic event object.
9559         * @param {string} newUrl New URL
9560         * @param {string=} oldUrl URL that was before it was changed.
9561         */
9562
9563        /**
9564         * @ngdoc event
9565         * @name $location#$locationChangeSuccess
9566         * @eventType broadcast on root scope
9567         * @description
9568         * Broadcasted after a URL was changed.
9569         *
9570         * @param {Object} angularEvent Synthetic event object.
9571         * @param {string} newUrl New URL
9572         * @param {string=} oldUrl URL that was before it was changed.
9573         */
9574
9575        this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
9576            function ($rootScope, $browser, $sniffer, $rootElement) {
9577                var $location,
9578                    LocationMode,
9579                    baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
9580                    initialUrl = $browser.url(),
9581                    appBase;
9582
9583                if (html5Mode) {
9584                    appBase = serverBase(initialUrl) + (baseHref || '/');
9585                    LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
9586                } else {
9587                    appBase = stripHash(initialUrl);
9588                    LocationMode = LocationHashbangUrl;
9589                }
9590                $location = new LocationMode(appBase, '#' + hashPrefix);
9591                $location.$$parse($location.$$rewrite(initialUrl));
9592
9593                $rootElement.on('click', function (event) {
9594                    // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
9595                    // currently we open nice url link and redirect then
9596
9597                    if (event.ctrlKey || event.metaKey || event.which == 2) return;
9598
9599                    var elm = jqLite(event.target);
9600
9601                    // traverse the DOM up to find first A tag
9602                    while (lowercase(elm[0].nodeName) !== 'a') {
9603                        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9604                        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9605                    }
9606
9607                    var absHref = elm.prop('href');
9608
9609                    if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
9610                        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
9611                        // an animation.
9612                        absHref = urlResolve(absHref.animVal).href;
9613                    }
9614
9615                    var rewrittenUrl = $location.$$rewrite(absHref);
9616
9617                    if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
9618                        event.preventDefault();
9619                        if (rewrittenUrl != $browser.url()) {
9620                            // update location manually
9621                            $location.$$parse(rewrittenUrl);
9622                            $rootScope.$apply();
9623                            // hack to work around FF6 bug 684208 when scenario runner clicks on links
9624                            window.angular['ff-684208-preventDefault'] = true;
9625                        }
9626                    }
9627                });
9628
9629
9630                // rewrite hashbang url <> html5 url
9631                if ($location.absUrl() != initialUrl) {
9632                    $browser.url($location.absUrl(), true);
9633                }
9634
9635                // update $location when $browser url changes
9636                $browser.onUrlChange(function (newUrl) {
9637                    if ($location.absUrl() != newUrl) {
9638                        $rootScope.$evalAsync(function () {
9639                            var oldUrl = $location.absUrl();
9640
9641                            $location.$$parse(newUrl);
9642                            if ($rootScope.$broadcast('$locationChangeStart', newUrl,
9643                                oldUrl).defaultPrevented) {
9644                                $location.$$parse(oldUrl);
9645                                $browser.url(oldUrl);
9646                            } else {
9647                                afterLocationChange(oldUrl);
9648                            }
9649                        });
9650                        if (!$rootScope.$$phase) $rootScope.$digest();
9651                    }
9652                });
9653
9654                // update browser
9655                var changeCounter = 0;
9656                $rootScope.$watch(function $locationWatch() {
9657                    var oldUrl = $browser.url();
9658                    var currentReplace = $location.$$replace;
9659
9660                    if (!changeCounter || oldUrl != $location.absUrl()) {
9661                        changeCounter++;
9662                        $rootScope.$evalAsync(function () {
9663                            if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
9664                                defaultPrevented) {
9665                                $location.$$parse(oldUrl);
9666                            } else {
9667                                $browser.url($location.absUrl(), currentReplace);
9668                                afterLocationChange(oldUrl);
9669                            }
9670                        });
9671                    }
9672                    $location.$$replace = false;
9673
9674                    return changeCounter;
9675                });
9676
9677                return $location;
9678
9679                function afterLocationChange(oldUrl) {
9680                    $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
9681                }
9682            }];
9683    }
9684
9685    /**
9686     * @ngdoc service
9687     * @name $log
9688     * @requires $window
9689     *
9690     * @description
9691     * Simple service for logging. Default implementation safely writes the message
9692     * into the browser's console (if present).
9693     *
9694     * The main purpose of this service is to simplify debugging and troubleshooting.
9695     *
9696     * The default is to log `debug` messages. You can use
9697     * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
9698     *
9699     * @example
9700     <example>
9701     <file name="script.js">
9702     function LogCtrl($scope, $log) {
9703         $scope.$log = $log;
9704         $scope.message = 'Hello World!';
9705       }
9706     </file>
9707     <file name="index.jsp">
9708     <div ng-controller="LogCtrl">
9709     <p>Reload this page with open console, enter text and hit the log button...</p>
9710     Message:
9711     <input type="text" ng-model="message"/>
9712     <button ng-click="$log.log(message)">log</button>
9713     <button ng-click="$log.warn(message)">warn</button>
9714     <button ng-click="$log.info(message)">info</button>
9715     <button ng-click="$log.error(message)">error</button>
9716     </div>
9717     </file>
9718     </example>
9719     */
9720
9721    /**
9722     * @ngdoc provider
9723     * @name $logProvider
9724     * @description
9725     * Use the `$logProvider` to configure how the application logs messages
9726     */
9727    function $LogProvider() {
9728        var debug = true,
9729            self = this;
9730
9731        /**
9732         * @ngdoc property
9733         * @name $logProvider#debugEnabled
9734         * @description
9735         * @param {boolean=} flag enable or disable debug level messages
9736         * @returns {*} current value if used as getter or itself (chaining) if used as setter
9737         */
9738        this.debugEnabled = function (flag) {
9739            if (isDefined(flag)) {
9740                debug = flag;
9741                return this;
9742            } else {
9743                return debug;
9744            }
9745        };
9746
9747        this.$get = ['$window', function ($window) {
9748            return {
9749                /**
9750                 * @ngdoc method
9751                 * @name $log#log
9752                 *
9753                 * @description
9754                 * Write a log message
9755                 */
9756                log: consoleLog('log'),
9757
9758                /**
9759                 * @ngdoc method
9760                 * @name $log#info
9761                 *
9762                 * @description
9763                 * Write an information message
9764                 */
9765                info: consoleLog('info'),
9766
9767                /**
9768                 * @ngdoc method
9769                 * @name $log#warn
9770                 *
9771                 * @description
9772                 * Write a warning message
9773                 */
9774                warn: consoleLog('warn'),
9775
9776                /**
9777                 * @ngdoc method
9778                 * @name $log#error
9779                 *
9780                 * @description
9781                 * Write an error message
9782                 */
9783                error: consoleLog('error'),
9784
9785                /**
9786                 * @ngdoc method
9787                 * @name $log#debug
9788                 *
9789                 * @description
9790                 * Write a debug message
9791                 */
9792                debug: (function () {
9793                    var fn = consoleLog('debug');
9794
9795                    return function () {
9796                        if (debug) {
9797                            fn.apply(self, arguments);
9798                        }
9799                    };
9800                }())
9801            };
9802
9803            function formatError(arg) {
9804                if (arg instanceof Error) {
9805                    if (arg.stack) {
9806                        arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
9807                            ? 'Error: ' + arg.message + '\n' + arg.stack
9808                            : arg.stack;
9809                    } else if (arg.sourceURL) {
9810                        arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
9811                    }
9812                }
9813                return arg;
9814            }
9815
9816            function consoleLog(type) {
9817                var console = $window.console || {},
9818                    logFn = console[type] || console.log || noop,
9819                    hasApply = false;
9820
9821                // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
9822                // The reason behind this is that console.log has type "object" in IE8...
9823                try {
9824                    hasApply = !!logFn.apply;
9825                } catch (e) {
9826                }
9827
9828                if (hasApply) {
9829                    return function () {
9830                        var args = [];
9831                        forEach(arguments, function (arg) {
9832                            args.push(formatError(arg));
9833                        });
9834                        return logFn.apply(console, args);
9835                    };
9836                }
9837
9838                // we are IE which either doesn't have window.console => this is noop and we do nothing,
9839                // or we are IE where console.log doesn't have apply so we log at least first 2 args
9840                return function (arg1, arg2) {
9841                    logFn(arg1, arg2 == null ? '' : arg2);
9842                };
9843            }
9844        }];
9845    }
9846
9847    var $parseMinErr = minErr('$parse');
9848    var promiseWarningCache = {};
9849    var promiseWarning;
9850
9851// Sandboxing Angular Expressions
9852// ------------------------------
9853// Angular expressions are generally considered safe because these expressions only have direct
9854// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
9855// obtaining a reference to native JS functions such as the Function constructor.
9856//
9857// As an example, consider the following Angular expression:
9858//
9859//   {}.toString.constructor(alert("evil JS code"))
9860//
9861// We want to prevent this type of access. For the sake of performance, during the lexing phase we
9862// disallow any "dotted" access to any member named "constructor".
9863//
9864// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
9865// while evaluating the expression, which is a stronger but more expensive test. Since reflective
9866// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
9867//
9868// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
9869// against the expression language, but not to prevent exploits that were enabled by exposing
9870// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
9871// practice and therefore we are not even trying to protect against interaction with an object
9872// explicitly exposed in this way.
9873//
9874// A developer could foil the name check by aliasing the Function constructor under a different
9875// name on the scope.
9876//
9877// In general, it is not possible to access a Window object from an angular expression unless a
9878// window or some DOM object that has a reference to window is published onto a Scope.
9879
9880    function ensureSafeMemberName(name, fullExpression) {
9881        if (name === "constructor") {
9882            throw $parseMinErr('isecfld',
9883                'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
9884                fullExpression);
9885        }
9886        return name;
9887    }
9888
9889    function ensureSafeObject(obj, fullExpression) {
9890        // nifty check if obj is Function that is fast and works across iframes and other contexts
9891        if (obj) {
9892            if (obj.constructor === obj) {
9893                throw $parseMinErr('isecfn',
9894                    'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9895                    fullExpression);
9896            } else if (// isWindow(obj)
9897                obj.document && obj.location && obj.alert && obj.setInterval) {
9898                throw $parseMinErr('isecwindow',
9899                    'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9900                    fullExpression);
9901            } else if (// isElement(obj)
9902                obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
9903                throw $parseMinErr('isecdom',
9904                    'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9905                    fullExpression);
9906            }
9907        }
9908        return obj;
9909    }
9910
9911    var OPERATORS = {
9912        /* jshint bitwise : false */
9913        'null': function () {
9914            return null;
9915        },
9916        'true': function () {
9917            return true;
9918        },
9919        'false': function () {
9920            return false;
9921        },
9922        undefined: noop,
9923        '+': function (self, locals, a, b) {
9924            a = a(self, locals);
9925            b = b(self, locals);
9926            if (isDefined(a)) {
9927                if (isDefined(b)) {
9928                    return a + b;
9929                }
9930                return a;
9931            }
9932            return isDefined(b) ? b : undefined;
9933        },
9934        '-': function (self, locals, a, b) {
9935            a = a(self, locals);
9936            b = b(self, locals);
9937            return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
9938        },
9939        '*': function (self, locals, a, b) {
9940            return a(self, locals) * b(self, locals);
9941        },
9942        '/': function (self, locals, a, b) {
9943            return a(self, locals) / b(self, locals);
9944        },
9945        '%': function (self, locals, a, b) {
9946            return a(self, locals) % b(self, locals);
9947        },
9948        '^': function (self, locals, a, b) {
9949            return a(self, locals) ^ b(self, locals);
9950        },
9951        '=': noop,
9952        '===': function (self, locals, a, b) {
9953            return a(self, locals) === b(self, locals);
9954        },
9955        '!==': function (self, locals, a, b) {
9956            return a(self, locals) !== b(self, locals);
9957        },
9958        '==': function (self, locals, a, b) {
9959            return a(self, locals) == b(self, locals);
9960        },
9961        '!=': function (self, locals, a, b) {
9962            return a(self, locals) != b(self, locals);
9963        },
9964        '<': function (self, locals, a, b) {
9965            return a(self, locals) < b(self, locals);
9966        },
9967        '>': function (self, locals, a, b) {
9968            return a(self, locals) > b(self, locals);
9969        },
9970        '<=': function (self, locals, a, b) {
9971            return a(self, locals) <= b(self, locals);
9972        },
9973        '>=': function (self, locals, a, b) {
9974            return a(self, locals) >= b(self, locals);
9975        },
9976        '&&': function (self, locals, a, b) {
9977            return a(self, locals) && b(self, locals);
9978        },
9979        '||': function (self, locals, a, b) {
9980            return a(self, locals) || b(self, locals);
9981        },
9982        '&': function (self, locals, a, b) {
9983            return a(self, locals) & b(self, locals);
9984        },
9985//    '|':function(self, locals, a,b){return a|b;},
9986        '|': function (self, locals, a, b) {
9987            return b(self, locals)(self, locals, a(self, locals));
9988        },
9989        '!': function (self, locals, a) {
9990            return !a(self, locals);
9991        }
9992    };
9993    /* jshint bitwise: true */
9994    var ESCAPE = {"n": "\n", "f": "\f", "r": "\r", "t": "\t", "v": "\v", "'": "'", '"': '"'};
9995
9996
9997/////////////////////////////////////////
9998
9999
10000    /**
10001     * @constructor
10002     */
10003    var Lexer = function (options) {
10004        this.options = options;
10005    };
10006
10007    Lexer.prototype = {
10008        constructor: Lexer,
10009
10010        lex: function (text) {
10011            this.text = text;
10012
10013            this.index = 0;
10014            this.ch = undefined;
10015            this.lastCh = ':'; // can start regexp
10016
10017            this.tokens = [];
10018
10019            var token;
10020            var json = [];
10021
10022            while (this.index < this.text.length) {
10023                this.ch = this.text.charAt(this.index);
10024                if (this.is('"\'')) {
10025                    this.readString(this.ch);
10026                } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
10027                    this.readNumber();
10028                } else if (this.isIdent(this.ch)) {
10029                    this.readIdent();
10030                    // identifiers can only be if the preceding char was a { or ,
10031                    if (this.was('{,') && json[0] === '{' &&
10032                        (token = this.tokens[this.tokens.length - 1])) {
10033                        token.json = token.text.indexOf('.') === -1;
10034                    }
10035                } else if (this.is('(){}[].,;:?')) {
10036                    this.tokens.push({
10037                        index: this.index,
10038                        text: this.ch,
10039                        json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
10040                    });
10041                    if (this.is('{[')) json.unshift(this.ch);
10042                    if (this.is('}
10042]')) json.shift();
10043                    this.index++;
10044                } else if (this.isWhitespace(this.ch)) {
10045                    this.index++;
10046                    continue;
10047                } else {
10048                    var ch2 = this.ch + this.peek();
10049                    var ch3 = ch2 + this.peek(2);
10050                    var fn = OPERATORS[this.ch];
10051                    var fn2 = OPERATORS[ch2];
10052                    var fn3 = OPERATORS[ch3];
10053                    if (fn3) {
10054                        this.tokens.push({index: this.index, text: ch3, fn: fn3});
10055                        this.index += 3;
10056                    } else if (fn2) {
10057                        this.tokens.push({index: this.index, text: ch2, fn: fn2});
10058                        this.index += 2;
10059                    } else if (fn) {
10060                        this.tokens.push({
10061                            index: this.index,
10062                            text: this.ch,
10063                            fn: fn,
10064                            json: (this.was('[,:') && this.is('+-'))
10065                        });
10066                        this.index += 1;
10067                    } else {
10068                        this.throwError('Unexpected next character ', this.index, this.index + 1);
10069                    }
10070                }
10071                this.lastCh = this.ch;
10072            }
10073            return this.tokens;
10074        },
10075
10076        is: function (chars) {
10077            return chars.indexOf(this.ch) !== -1;
10078        },
10079
10080        was: function (chars) {
10081            return chars.indexOf(this.lastCh) !== -1;
10082        },
10083
10084        peek: function (i) {
10085            var num = i || 1;
10086            return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
10087        },
10088
10089        isNumber: function (ch) {
10090            return ('0' <= ch && ch <= '9');
10091        },
10092
10093        isWhitespace: function (ch) {
10094            // IE treats non-breaking space as \u00A0
10095            return (ch === ' ' || ch === '\r' || ch === '\t' ||
10096                ch === '\n' || ch === '\v' || ch === '\u00A0');
10097        },
10098
10099        isIdent: function (ch) {
10100            return ('a' <= ch && ch <= 'z' ||
10101                'A' <= ch && ch <= 'Z' ||
10102                '_' === ch || ch === '$');
10103        },
10104
10105        isExpOperator: function (ch) {
10106            return (ch === '-' || ch === '+' || this.isNumber(ch));
10107        },
10108
10109        throwError: function (error, start, end) {
10110            end = end || this.index;
10111            var colStr = (isDefined(start)
10112                ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']'
10113                : ' ' + end);
10114            throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
10115                error, colStr, this.text);
10116        },
10117
10118        readNumber: function () {
10119            var number = '';
10120            var start = this.index;
10121            while (this.index < this.text.length) {
10122                var ch = lowercase(this.text.charAt(this.index));
10123                if (ch == '.' || this.isNumber(ch)) {
10124                    number += ch;
10125                } else {
10126                    var peekCh = this.peek();
10127                    if (ch == 'e' && this.isExpOperator(peekCh)) {
10128                        number += ch;
10129                    } else if (this.isExpOperator(ch) &&
10130                        peekCh && this.isNumber(peekCh) &&
10131                        number.charAt(number.length - 1) == 'e') {
10132                        number += ch;
10133                    } else if (this.isExpOperator(ch) &&
10134                        (!peekCh || !this.isNumber(peekCh)) &&
10135                        number.charAt(number.length - 1) == 'e') {
10136                        this.throwError('Invalid exponent');
10137                    } else {
10138                        break;
10139                    }
10140                }
10141                this.index++;
10142            }
10143            number = 1 * number;
10144            this.tokens.push({
10145                index: start,
10146                text: number,
10147                json: true,
10148                fn: function () {
10149                    return number;
10150                }
10151            });
10152        },
10153
10154        readIdent: function () {
10155            var parser = this;
10156
10157            var ident = '';
10158            var start = this.index;
10159
10160            var lastDot, peekIndex, methodName, ch;
10161
10162            while (this.index < this.text.length) {
10163                ch = this.text.charAt(this.index);
10164                if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
10165                    if (ch === '.') lastDot = this.index;
10166                    ident += ch;
10167                } else {
10168                    break;
10169                }
10170                this.index++;
10171            }
10172
10173            //check if this is not a method invocation and if it is back out to last dot
10174            if (lastDot) {
10175                peekIndex = this.index;
10176                while (peekIndex < this.text.length) {
10177                    ch = this.text.charAt(peekIndex);
10178                    if (ch === '(') {
10179                        methodName = ident.substr(lastDot - start + 1);
10180                        ident = ident.substr(0, lastDot - start);
10181                        this.index = peekIndex;
10182                        break;
10183                    }
10184                    if (this.isWhitespace(ch)) {
10185                        peekIndex++;
10186                    } else {
10187                        break;
10188                    }
10189                }
10190            }
10191
10192
10193            var token = {
10194                index: start,
10195                text: ident
10196            };
10197
10198            // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
10199            if (OPERATORS.hasOwnProperty(ident)) {
10200                token.fn = OPERATORS[ident];
10201                token.json = OPERATORS[ident];
10202            } else {
10203                var getter = getterFn(ident, this.options, this.text);
10204                token.fn = extend(function (self, locals) {
10205                    return (getter(self, locals));
10206                }, {
10207                    assign: function (self, value) {
10208                        return setter(self, ident, value, parser.text, parser.options);
10209                    }
10210                });
10211            }
10212
10213            this.tokens.push(token);
10214
10215            if (methodName) {
10216                this.tokens.push({
10217                    index: lastDot,
10218                    text: '.',
10219                    json: false
10220                });
10221                this.tokens.push({
10222                    index: lastDot + 1,
10223                    text: methodName,
10224                    json: false
10225                });
10226            }
10227        },
10228
10229        readString: function (quote) {
10230            var start = this.index;
10231            this.index++;
10232            var string = '';
10233            var rawString = quote;
10234            var escape = false;
10235            while (this.index < this.text.length) {
10236                var ch = this.text.charAt(this.index);
10237                rawString += ch;
10238                if (escape) {
10239                    if (ch === 'u') {
10240                        var hex = this.text.substring(this.index + 1, this.index + 5);
10241                        if (!hex.match(/[\da-f]{4}/i))
10242                            this.throwError('Invalid unicode escape [\\u' + hex + ']');
10243                        this.index += 4;
10244                        string += String.fromCharCode(parseInt(hex, 16));
10245                    } else {
10246                        var rep = ESCAPE[ch];
10247                        if (rep) {
10248                            string += rep;
10249                        } else {
10250                            string += ch;
10251                        }
10252                    }
10253                    escape = false;
10254                } else if (ch === '\\') {
10255                    escape = true;
10256                } else if (ch === quote) {
10257                    this.index++;
10258                    this.tokens.push({
10259                        index: start,
10260                        text: rawString,
10261                        string: string,
10262                        json: true,
10263                        fn: function () {
10264                            return string;
10265                        }
10266                    });
10267                    return;
10268                } else {
10269                    string += ch;
10270                }
10271                this.index++;
10272            }
10273            this.throwError('Unterminated quote', start);
10274        }
10275    };
10276
10277
10278    /**
10279     * @constructor
10280     */
10281    var Parser = function (lexer, $filter, options) {
10282        this.lexer = lexer;
10283        this.$filter = $filter;
10284        this.options = options;
10285    };
10286
10287    Parser.ZERO = extend(function () {
10288        return 0;
10289    }, {
10290        constant: true
10291    });
10292
10293    Parser.prototype = {
10294        constructor: Parser,
10295
10296        parse: function (text, json) {
10297            this.text = text;
10298
10299            //TODO(i): strip all the obsolte json stuff from this file
10300            this.json = json;
10301
10302            this.tokens = this.lexer.lex(text);
10303
10304            if (json) {
10305                // The extra level of aliasing is here, just in case the lexer misses something, so that
10306                // we prevent any accidental execution in JSON.
10307                this.assignment = this.logicalOR;
10308
10309                this.functionCall =
10310                    this.fieldAccess =
10311                        this.objectIndex =
10312                            this.filterChain = function () {
10313                                this.throwError('is not valid json', {text: text, index: 0});
10314                            };
10315            }
10316
10317            var value = json ? this.primary() : this.statements();
10318
10319            if (this.tokens.length !== 0) {
10320                this.throwError('is an unexpected token', this.tokens[0]);
10321            }
10322
10323            value.literal = !!value.literal;
10324            value.constant = !!value.constant;
10325
10326            return value;
10327        },
10328
10329        primary: function () {
10330            var primary;
10331            if (this.expect('(')) {
10332                primary = this.filterChain();
10333                this.consume(')');
10334            } else if (this.expect('[')) {
10335                primary = this.arrayDeclaration();
10336            } else if (this.expect('{')) {
10337                primary = this.object();
10338            } else {
10339                var token = this.expect();
10340                primary = token.fn;
10341                if (!primary) {
10342                    this.throwError('not a primary expression', token);
10343                }
10344                if (token.json) {
10345                    primary.constant = true;
10346                    primary.literal = true;
10347                }
10348            }
10349
10350            var next, context;
10351            while ((next = this.expect('(', '[', '.'))) {
10352                if (next.text === '(') {
10353                    primary = this.functionCall(primary, context);
10354                    context = null;
10355                } else if (next.text === '[') {
10356                    context = primary;
10357                    primary = this.objectIndex(primary);
10358                } else if (next.text === '.') {
10359                    context = primary;
10360                    primary = this.fieldAccess(primary);
10361                } else {
10362                    this.throwError('IMPOSSIBLE');
10363                }
10364            }
10365            return primary;
10366        },
10367
10368        throwError: function (msg, token) {
10369            throw $parseMinErr('syntax',
10370                'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
10371                token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
10372        },
10373
10374        peekToken: function () {
10375            if (this.tokens.length === 0)
10376                throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
10377            return this.tokens[0];
10378        },
10379
10380        peek: function (e1, e2, e3, e4) {
10381            if (this.tokens.length > 0) {
10382                var token = this.tokens[0];
10383                var t = token.text;
10384                if (t === e1 || t === e2 || t === e3 || t === e4 ||
10385                    (!e1 && !e2 && !e3 && !e4)) {
10386                    return token;
10387                }
10388            }
10389            return false;
10390        },
10391
10392        expect: function (e1, e2, e3, e4) {
10393            var token = this.peek(e1, e2, e3, e4);
10394            if (token) {
10395                if (this.json && !token.json) {
10396                    this.throwError('is not valid json', token);
10397                }
10398                this.tokens.shift();
10399                return token;
10400            }
10401            return false;
10402        },
10403
10404        consume: function (e1) {
10405            if (!this.expect(e1)) {
10406                this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
10407            }
10408        },
10409
10410        unaryFn: function (fn, right) {
10411            return extend(function (self, locals) {
10412                return fn(self, locals, right);
10413            }, {
10414                constant: right.constant
10415            });
10416        },
10417
10418        ternaryFn: function (left, middle, right) {
10419            return extend(function (self, locals) {
10420                return left(self, locals) ? middle(self, locals) : right(self, locals);
10421            }, {
10422                constant: left.constant && middle.constant && right.constant
10423            });
10424        },
10425
10426        binaryFn: function (left, fn, right) {
10427            return extend(function (self, locals) {
10428                return fn(self, locals, left, right);
10429            }, {
10430                constant: left.constant && right.constant
10431            });
10432        },
10433
10434        statements: function () {
10435            var statements = [];
10436            while (true) {
10437                if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
10438                    statements.push(this.filterChain());
10439                if (!this.expect(';')) {
10440                    // optimize for the common case where there is only one statement.
10441                    // TODO(size): maybe we should not support multiple statements?
10442                    return (statements.length === 1)
10443                        ? statements[0]
10444                        : function (self, locals) {
10445                        var value;
10446                        for (var i = 0; i < statements.length; i++) {
10447                            var statement = statements[i];
10448                            if (statement) {
10449                                value = statement(self, locals);
10450                            }
10451                        }
10452                        return value;
10453                    };
10454                }
10455            }
10456        },
10457
10458        filterChain: function () {
10459            var left = this.expression();
10460            var token;
10461            while (true) {
10462                if ((token = this.expect('|'))) {
10463                    left = this.binaryFn(left, token.fn, this.filter());
10464                } else {
10465                    return left;
10466                }
10467            }
10468        },
10469
10470        filter: function () {
10471            var token = this.expect();
10472            var fn = this.$filter(token.text);
10473            var argsFn = [];
10474            while (true) {
10475                if ((token = this.expect(':'))) {
10476                    argsFn.push(this.expression());
10477                } else {
10478                    var fnInvoke = function (self, locals, input) {
10479                        var args = [input];
10480                        for (var i = 0; i < argsFn.length; i++) {
10481                            args.push(argsFn[i](self, locals));
10482                        }
10483                        return fn.apply(self, args);
10484                    };
10485                    return function () {
10486                        return fnInvoke;
10487                    };
10488                }
10489            }
10490        },
10491
10492        expression: function () {
10493            return this.assignment();
10494        },
10495
10496        assignment: function () {
10497            var left = this.ternary();
10498            var right;
10499            var token;
10500            if ((token = this.expect('='))) {
10501                if (!left.assign) {
10502                    this.throwError('implies assignment but [' +
10503                        this.text.substring(0, token.index) + '] can not be assigned to', token);
10504                }
10505                right = this.ternary();
10506                return function (scope, locals) {
10507                    return left.assign(scope, right(scope, locals), locals);
10508                };
10509            }
10510            return left;
10511        },
10512
10513        ternary: function () {
10514            var left = this.logicalOR();
10515            var middle;
10516            var token;
10517            if ((token = this.expect('?'))) {
10518                middle = this.ternary();
10519                if ((token = this.expect(':'))) {
10520                    return this.ternaryFn(left, middle, this.ternary());
10521                } else {
10522                    this.throwError('expected :', token);
10523                }
10524            } else {
10525                return left;
10526            }
10527        },
10528
10529        logicalOR: function () {
10530            var left = this.logicalAND();
10531            var token;
10532            while (true) {
10533                if ((token = this.expect('||'))) {
10534                    left = this.binaryFn(left, token.fn, this.logicalAND());
10535                } else {
10536                    return left;
10537                }
10538            }
10539        },
10540
10541        logicalAND: function () {
10542            var left = this.equality();
10543            var token;
10544            if ((token = this.expect('&&'))) {
10545                left = this.binaryFn(left, token.fn, this.logicalAND());
10546            }
10547            return left;
10548        },
10549
10550        equality: function () {
10551            var left = this.relational();
10552            var token;
10553            if ((token = this.expect('==', '!=', '===', '!=='))) {
10554                left = this.binaryFn(left, token.fn, this.equality());
10555            }
10556            return left;
10557        },
10558
10559        relational: function () {
10560            var left = this.additive();
10561            var token;
10562            if ((token = this.expect('<', '>', '<=', '>='))) {
10563                left = this.binaryFn(left, token.fn, this.relational());
10564            }
10565            return left;
10566        },
10567
10568        additive: function () {
10569            var left = this.multiplicative();
10570            var token;
10571            while ((token = this.expect('+', '-'))) {
10572                left = this.binaryFn(left, token.fn, this.multiplicative());
10573            }
10574            return left;
10575        },
10576
10577        multiplicative: function () {
10578            var left = this.unary();
10579            var token;
10580            while ((token = this.expect('*', '/', '%'))) {
10581                left = this.binaryFn(left, token.fn, this.unary());
10582            }
10583            return left;
10584        },
10585
10586        unary: function () {
10587            var token;
10588            if (this.expect('+')) {
10589                return this.primary();
10590            } else if ((token = this.expect('-'))) {
10591                return this.binaryFn(Parser.ZERO, token.fn, this.unary());
10592            } else if ((token = this.expect('!'))) {
10593                return this.unaryFn(token.fn, this.unary());
10594            } else {
10595                return this.primary();
10596            }
10597        },
10598
10599        fieldAccess: function (object) {
10600            var parser = this;
10601            var field = this.expect().text;
10602            var getter = getterFn(field, this.options, this.text);
10603
10604            return extend(function (scope, locals, self) {
10605                return getter(self || object(scope, locals));
10606            }, {
10607                assign: function (scope, value, locals) {
10608                    return setter(object(scope, locals), field, value, parser.text, parser.options);
10609                }
10610            });
10611        },
10612
10613        objectIndex: function (obj) {
10614            var parser = this;
10615
10616            var indexFn = this.expression();
10617            this.consume(']');
10618
10619            return extend(function (self, locals) {
10620                var o = obj(self, locals),
10621                    i = indexFn(self, locals),
10622                    v, p;
10623
10624                if (!o) return undefined;
10625                v = ensureSafeObject(o[i], parser.text);
10626                if (v && v.then && parser.options.unwrapPromises) {
10627                    p = v;
10628                    if (!('$$v' in v)) {
10629                        p.$$v = undefined;
10630                        p.then(function (val) {
10631                            p.$$v = val;
10632                        });
10633                    }
10634                    v = v.$$v;
10635                }
10636                return v;
10637            }, {
10638                assign: function (self, value, locals) {
10639                    var key = indexFn(self, locals);
10640                    // prevent overwriting of Function.constructor which would break ensureSafeObject check
10641                    var safe = ensureSafeObject(obj(self, locals), parser.text);
10642                    return safe[key] = value;
10643                }
10644            });
10645        },
10646
10647        functionCall: function (fn, contextGetter) {
10648            var argsFn = [];
10649            if (this.peekToken().text !== ')') {
10650                do {
10651                    argsFn.push(this.expression());
10652                } while (this.expect(','));
10653            }
10654            this.consume(')');
10655
10656            var parser = this;
10657
10658            return function (scope, locals) {
10659                var args = [];
10660                var context = contextGetter ? contextGetter(scope, locals) : scope;
10661
10662                for (var i = 0; i < argsFn.length; i++) {
10663                    args.push(argsFn[i](scope, locals));
10664                }
10665                var fnPtr = fn(scope, locals, context) || noop;
10666
10667                ensureSafeObject(context, parser.text);
10668                ensureSafeObject(fnPtr, parser.text);
10669
10670                // IE stupidity! (IE doesn't have apply for some native functions)
10671                var v = fnPtr.apply
10672                    ? fnPtr.apply(context, args)
10673                    : fnPtr(args[0], args[1], args[2], args[3], args[4]);
10674
10675                return ensureSafeObject(v, parser.text);
10676            };
10677        },
10678
10679        // This is used with json array declaration
10680        arrayDeclaration: function () {
10681            var elementFns = [];
10682            var allConstant = true;
10683            if (this.peekToken().text !== ']') {
10684                do {
10685                    if (this.peek(']')) {
10686                        // Support trailing commas per ES5.1.
10687                        break;
10688                    }
10689                    var elementFn = this.expression();
10690                    elementFns.push(elementFn);
10691                    if (!elementFn.constant) {
10692                        allConstant = false;
10693                    }
10694                } while (this.expect(','));
10695            }
10696            this.consume(']');
10697
10698            return extend(function (self, locals) {
10699                var array = [];
10700                for (var i = 0; i < elementFns.length; i++) {
10701                    array.push(elementFns[i](self, locals));
10702                }
10703                return array;
10704            }, {
10705                literal: true,
10706                constant: allConstant
10707            });
10708        },
10709
10710        object: function () {
10711            var keyValues = [];
10712            var allConstant = true;
10713            if (this.peekToken().text !== '}') {
10714                do {
10715                    if (this.peek('}')) {
10716                        // Support trailing commas per ES5.1.
10717                        break;
10718                    }
10719                    var token = this.expect(),
10720                        key = token.string || token.text;
10721                    this.consume(':');
10722                    var value = this.expression();
10723                    keyValues.push({key: key, value: value});
10724                    if (!value.constant) {
10725                        allConstant = false;
10726                    }
10727                } while (this.expect(','));
10728            }
10729            this.consume('}');
10730
10731            return extend(function (self, locals) {
10732                var object = {};
10733                for (var i = 0; i < keyValues.length; i++) {
10734                    var keyValue = keyValues[i];
10735                    object[keyValue.key] = keyValue.value(self, locals);
10736                }
10737                return object;
10738            }, {
10739                literal: true,
10740                constant: allConstant
10741            });
10742        }
10743    };
10744
10745
10746//////////////////////////////////////////////////
10747// Parser helper functions
10748//////////////////////////////////////////////////
10749
10750    function setter(obj, path, setValue, fullExp, options) {
10751        //needed?
10752        options = options || {};
10753
10754        var element = path.split('.'), key;
10755        for (var i = 0; element.length > 1; i++) {
10756            key = ensureSafeMemberName(element.shift(), fullExp);
10757            var propertyObj = obj[key];
10758            if (!propertyObj) {
10759                propertyObj = {};
10760                obj[key] = propertyObj;
10761            }
10762            obj = propertyObj;
10763            if (obj.then && options.unwrapPromises) {
10764                promiseWarning(fullExp);
10765                if (!("$$v" in obj)) {
10766                    (function (promise) {
10767                        promise.then(function (val) {
10768                            promise.$$v = val;
10769                        });
10770                    })(obj);
10771                }
10772                if (obj.$$v === undefined) {
10773                    obj.$$v = {};
10774                }
10775                obj = obj.$$v;
10776            }
10777        }
10778        key = ensureSafeMemberName(element.shift(), fullExp);
10779        obj[key] = setValue;
10780        return setValue;
10781    }
10782
10783    var getterFnCache = {};
10784
10785    /**
10786     * Implementation of the "Black Hole" variant from:
10787     * - http://jsperf.com/angularjs-parse-getter/4
10788     * - http://jsperf.com/path-evaluation-simplified/7
10789     */
10790    function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
10791        ensureSafeMemberName(key0, fullExp);
10792        ensureSafeMemberName(key1, fullExp);
10793        ensureSafeMemberName(key2, fullExp);
10794        ensureSafeMemberName(key3, fullExp);
10795        ensureSafeMemberName(key4, fullExp);
10796
10797        return !options.unwrapPromises
10798            ? function cspSafeGetter(scope, locals) {
10799            var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
10800
10801            if (pathVal == null) return pathVal;
10802            pathVal = pathVal[key0];
10803
10804            if (!key1) return pathVal;
10805            if (pathVal == null) return undefined;
10806            pathVal = pathVal[key1];
10807
10808            if (!key2) return pathVal;
10809            if (pathVal == null) return undefined;
10810            pathVal = pathVal[key2];
10811
10812            if (!key3) return pathVal;
10813            if (pathVal == null) return undefined;
10814            pathVal = pathVal[key3];
10815
10816            if (!key4) return pathVal;
10817            if (pathVal == null) return undefined;
10818            pathVal = pathVal[key4];
10819
10820            return pathVal;
10821        }
10822            : function cspSafePromiseEnabledGetter(scope, locals) {
10823            var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
10824                promise;
10825
10826            if (pathVal == null) return pathVal;
10827
10828            pathVal = pathVal[key0];
10829            if (pathVal && pathVal.then) {
10830                promiseWarning(fullExp);
10831                if (!("$$v" in pathVal)) {
10832                    promise = pathVal;
10833                    promise.$$v = undefined;
10834                    promise.then(function (val) {
10835                        promise.$$v = val;
10836                    });
10837                }
10838                pathVal = pathVal.$$v;
10839            }
10840
10841            if (!key1) return pathVal;
10842            if (pathVal == null) return undefined;
10843            pathVal = pathVal[key1];
10844            if (pathVal && pathVal.then) {
10845                promiseWarning(fullExp);
10846                if (!("$$v" in pathVal)) {
10847                    promise = pathVal;
10848                    promise.$$v = undefined;
10849                    promise.then(function (val) {
10850                        promise.$$v = val;
10851                    });
10852                }
10853                pathVal = pathVal.$$v;
10854            }
10855
10856            if (!key2) return pathVal;
10857            if (pathVal == null) return undefined;
10858            pathVal = pathVal[key2];
10859            if (pathVal && pathVal.then) {
10860                promiseWarning(fullExp);
10861                if (!("$$v" in pathVal)) {
10862                    promise = pathVal;
10863                    promise.$$v = undefined;
10864                    promise.then(function (val) {
10865                        promise.$$v = val;
10866                    });
10867                }
10868                pathVal = pathVal.$$v;
10869            }
10870
10871            if (!key3) return pathVal;
10872            if (pathVal == null) return undefined;
10873            pathVal = pathVal[key3];
10874            if (pathVal && pathVal.then) {
10875                promiseWarning(fullExp);
10876                if (!("$$v" in pathVal)) {
10877                    promise = pathVal;
10878                    promise.$$v = undefined;
10879                    promise.then(function (val) {
10880                        promise.$$v = val;
10881                    });
10882                }
10883                pathVal = pathVal.$$v;
10884            }
10885
10886            if (!key4) return pathVal;
10887            if (pathVal == null) return undefined;
10888            pathVal = pathVal[key4];
10889            if (pathVal && pathVal.then) {
10890                promiseWarning(fullExp);
10891                if (!("$$v" in pathVal)) {
10892                    promise = pathVal;
10893                    promise.$$v = undefined;
10894                    promise.then(function (val) {
10895                        promise.$$v = val;
10896                    });
10897                }
10898                pathVal = pathVal.$$v;
10899            }
10900            return pathVal;
10901        };
10902    }
10903
10904    function simpleGetterFn1(key0, fullExp) {
10905        ensureSafeMemberName(key0, fullExp);
10906
10907        return function simpleGetterFn1(scope, locals) {
10908            if (scope == null) return undefined;
10909            return ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10910        };
10911    }
10912
10913    function simpleGetterFn2(key0, key1, fullExp) {
10914        ensureSafeMemberName(key0, fullExp);
10915        ensureSafeMemberName(key1, fullExp);
10916
10917        return function simpleGetterFn2(scope, locals) {
10918            if (scope == null) return undefined;
10919            scope = ((locals && locals.hasOwnProperty(key0)) ? locals : scope)[key0];
10920            return scope == null ? undefined : scope[key1];
10921        };
10922    }
10923
10924    function getterFn(path, options, fullExp) {
10925        // Check whether the cache has this getter already.
10926        // We can use hasOwnProperty directly on the cache because we ensure,
10927        // see below, that the cache never stores a path called 'hasOwnProperty'
10928        if (getterFnCache.hasOwnProperty(path)) {
10929            return getterFnCache[path];
10930        }
10931
10932        var pathKeys = path.split('.'),
10933            pathKeysLength = pathKeys.length,
10934            fn;
10935
10936        // When we have only 1 or 2 tokens, use optimized special case closures.
10937        // http://jsperf.com/angularjs-parse-getter/6
10938        if (!options.unwrapPromises && pathKeysLength === 1) {
10939            fn = simpleGetterFn1(pathKeys[0], fullExp);
10940        } else if (!options.unwrapPromises && pathKeysLength === 2) {
10941            fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
10942        } else if (options.csp) {
10943            if (pathKeysLength < 6) {
10944                fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
10945                    options);
10946            } else {
10947                fn = function (scope, locals) {
10948                    var i = 0, val;
10949                    do {
10950                        val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
10951                            pathKeys[i++], fullExp, options)(scope, locals);
10952
10953                        locals = undefined; // clear after first iteration
10954                        scope = val;
10955                    } while (i < pathKeysLength);
10956                    return val;
10957                };
10958            }
10959        } else {
10960            var code = 'var p;\n';
10961            forEach(pathKeys, function (key, index) {
10962                ensureSafeMemberName(key, fullExp);
10963                code += 'if(s == null) return undefined;\n' +
10964                    's=' + (index
10965                    // we simply dereference 's' on any .dot notation
10966                    ? 's'
10967                    // but if we are first then we check locals first, and if so read it first
10968                    : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
10969                    (options.unwrapPromises
10970                        ? 'if (s && s.then) {\n' +
10971                        ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
10972                        ' if (!("$$v" in s)) {\n' +
10973                        ' p=s;\n' +
10974                        ' p.$$v = undefined;\n' +
10975                        ' p.then(function(v) {p.$$v=v;});\n' +
10976                        '}\n' +
10977                        ' s=s.$$v\n' +
10978                        '}\n'
10979                        : '');
10980            });
10981            code += 'return s;';
10982
10983            /* jshint -W054 */
10984            var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
10985            /* jshint +W054 */
10986            evaledFnGetter.toString = valueFn(code);
10987            fn = options.unwrapPromises ? function (scope, locals) {
10988                return evaledFnGetter(scope, locals, promiseWarning);
10989            } : evaledFnGetter;
10990        }
10991
10992        // Only cache the value if it's not going to mess up the cache object
10993        // This is more performant that using Object.prototype.hasOwnProperty.call
10994        if (path !== 'hasOwnProperty') {
10995            getterFnCache[path] = fn;
10996        }
10997        return fn;
10998    }
10999
11000///////////////////////////////////
11001
11002    /**
11003     * @ngdoc service
11004     * @name $parse
11005     * @kind function
11006     *
11007     * @description
11008     *
11009     * Converts Angular {@link guide/expression expression} into a function.
11010     *
11011     * ```js
11012     *   var getter = $parse('user.name');
11013     *   var setter = getter.assign;
11014     *   var context = {user:{name:'angular'}};
11015     *   var locals = {user:{name:'local'}};
11016     *
11017     *   expect(getter(context)).toEqual('angular');
11018     *   setter(context, 'newValue');
11019     *   expect(context.user.name).toEqual('newValue');
11020     *   expect(getter(context, locals)).toEqual('local');
11021     * ```
11022     *
11023     *
11024     * @param {string} expression String expression to compile.
11025     * @returns {function(context, locals)} a function which represents the compiled expression:
11026     *
11027     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
11028     *      are evaluated against (typically a scope object).
11029     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
11030     *      `context`.
11031     *
11032     *    The returned function also has the following properties:
11033     *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
11034     *        literal.
11035     *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
11036     *        constant literals.
11037     *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
11038     *        set to a function to change its value on the given context.
11039     *
11040     */
11041
11042
11043    /**
11044     * @ngdoc provider
11045     * @name $parseProvider
11046     * @function
11047     *
11048     * @description
11049     * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
11050     *  service.
11051     */
11052    function $ParseProvider() {
11053        var cache = {};
11054
11055        var $parseOptions = {
11056            csp: false,
11057            unwrapPromises: false,
11058            logPromiseWarnings: true
11059        };
11060
11061
11062        /**
11063         * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11064         *
11065         * @ngdoc method
11066         * @name $parseProvider#unwrapPromises
11067         * @description
11068         *
11069         * **This feature is deprecated, see deprecation notes below for more info**
11070         *
11071         * If set to true (default is false), $parse will unwrap promises automatically when a promise is
11072         * found at any part of the expression. In other words, if set to true, the expression will always
11073         * result in a non-promise value.
11074         *
11075         * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
11076         * the fulfillment value is used in place of the promise while evaluating the expression.
11077         *
11078         * **Deprecation notice**
11079         *
11080         * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
11081         * dichotomy between data access in templates (accessed as raw values) and controller code
11082         * (accessed as promises).
11083         *
11084         * In most code we ended up resolving promises manually in controllers anyway and thus unifying
11085         * the model access there.
11086         *
11087         * Other downsides of automatic promise unwrapping:
11088         *
11089         * - when building components it's often desirable to receive the raw promises
11090         * - adds complexity and slows down expression evaluation
11091         * - makes expression code pre-generation unattractive due to the amount of code that needs to be
11092         *   generated
11093         * - makes IDE auto-completion and tool support hard
11094         *
11095         * **Warning Logs**
11096         *
11097         * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
11098         * promise (to reduce the noise, each expression is logged only once). To disable this logging use
11099         * `$parseProvider.logPromiseWarnings(false)` api.
11100         *
11101         *
11102         * @param {boolean=} value New value.
11103         * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11104         *                         setter.
11105         */
11106        this.unwrapPromises = function (value) {
11107            if (isDefined(value)) {
11108                $parseOptions.unwrapPromises = !!value;
11109                return this;
11110            } else {
11111                return $parseOptions.unwrapPromises;
11112            }
11113        };
11114
11115
11116        /**
11117         * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
11118         *
11119         * @ngdoc method
11120         * @name $parseProvider#logPromiseWarnings
11121         * @description
11122         *
11123         * Controls whether Angular should log a warning on any encounter of a promise in an expression.
11124         *
11125         * The default is set to `true`.
11126         *
11127         * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
11128         *
11129         * @param {boolean=} value New value.
11130         * @returns {boolean|self} Returns the current setting when used as getter and self if used as
11131         *                         setter.
11132         */
11133        this.logPromiseWarnings = function (value) {
11134            if (isDefined(value)) {
11135                $parseOptions.logPromiseWarnings = value;
11136                return this;
11137            } else {
11138                return $parseOptions.logPromiseWarnings;
11139            }
11140        };
11141
11142
11143        this.$get = ['$filter', '$sniffer', '$log', function ($filter, $sniffer, $log) {
11144            $parseOptions.csp = $sniffer.csp;
11145
11146            promiseWarning = function promiseWarningFn(fullExp) {
11147                if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
11148                promiseWarningCache[fullExp] = true;
11149                $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
11150                    'Automatic unwrapping of promises in Angular expressions is deprecated.');
11151            };
11152
11153            return function (exp) {
11154                var parsedExpression;
11155
11156                switch (typeof exp) {
11157                    case 'string':
11158
11159                        if (cache.hasOwnProperty(exp)) {
11160                            return cache[exp];
11161                        }
11162
11163                        var lexer = new Lexer($parseOptions);
11164                        var parser = new Parser(lexer, $filter, $parseOptions);
11165                        parsedExpression = parser.parse(exp, false);
11166
11167                        if (exp !== 'hasOwnProperty') {
11168                            // Only cache the value if it's not going to mess up the cache object
11169                            // This is more performant that using Object.prototype.hasOwnProperty.call
11170                            cache[exp] = parsedExpression;
11171                        }
11172
11173                        return parsedExpression;
11174
11175                    case 'function':
11176                        return exp;
11177
11178                    default:
11179                        return noop;
11180                }
11181            };
11182        }];
11183    }
11184
11185    /**
11186     * @ngdoc service
11187     * @name $q
11188     * @requires $rootScope
11189     *
11190     * @description
11191     * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
11192     *
11193     * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
11194     * interface for interacting with an object that represents the result of an action that is
11195     * performed asynchronously, and may or may not be finished at any given point in time.
11196     *
11197     * From the perspective of dealing with error handling, deferred and promise APIs are to
11198     * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
11199     *
11200     * ```js
11201     *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
11202     *   // are available in the current lexical scope (they could have been injected or passed in).
11203     *
11204     *   function asyncGreet(name) {
11205 *     var deferred = $q.defer();
11206 *
11207 *     setTimeout(function() {
11208 *       // since this fn executes async in a future turn of the event loop, we need to wrap
11209 *       // our code into an $apply call so that the model changes are properly observed.
11210 *       scope.$apply(function() {
11211 *         deferred.notify('About to greet ' + name + '.');
11212 *
11213 *         if (okToGreet(name)) {
11214 *           deferred.resolve('Hello, ' + name + '!');
11215 *         } else {
11216 *           deferred.reject('Greeting ' + name + ' is not allowed.');
11217 *         }
11218 *       });
11219 *     }, 1000);
11220 *
11221 *     return deferred.promise;
11222 *   }
11223     *
11224     *   var promise = asyncGreet('Robin Hood');
11225     *   promise.then(function(greeting) {
11226 *     alert('Success: ' + greeting);
11227 *   }, function(reason) {
11228 *     alert('Failed: ' + reason);
11229 *   }, function(update) {
11230 *     alert('Got notification: ' + update);
11231 *   });
11232     * ```
11233     *
11234     * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
11235     * comes in the way of guarantees that promise and deferred APIs make, see
11236     * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
11237     *
11238     * Additionally the promise api allows for composition that is very hard to do with the
11239     * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
11240     * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
11241     * section on serial or parallel joining of promises.
11242     *
11243     *
11244     * # The Deferred API
11245     *
11246     * A new instance of deferred is constructed by calling `$q.defer()`.
11247     *
11248     * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
11249     * that can be used for signaling the successful or unsuccessful completion, as well as the status
11250     * of the task.
11251     *
11252     * **Methods**
11253     *
11254     * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
11255     *   constructed via `$q.reject`, the promise will be rejected instead.
11256     * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
11257     *   resolving it with a rejection constructed via `$q.reject`.
11258     * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
11259     *   multiple times before the promise is either resolved or rejected.
11260     *
11261     * **Properties**
11262     *
11263     * - promise – `{Promise}` – promise object associated with this deferred.
11264     *
11265     *
11266     * # The Promise API
11267     *
11268     * A new promise instance is created when a deferred instance is created and can be retrieved by
11269     * calling `deferred.promise`.
11270     *
11271     * The purpose of the promise object is to allow for interested parties to get access to the result
11272     * of the deferred task when it completes.
11273     *
11274     * **Methods**
11275     *
11276     * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
11277     *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
11278     *   as soon as the result is available. The callbacks are called with a single argument: the result
11279     *   or rejection reason. Additionally, the notify callback may be called zero or more times to
11280     *   provide a progress indication, before the promise is resolved or rejected.
11281     *
11282     *   This method *returns a new promise* which is resolved or rejected via the return value of the
11283     *   `successCallback`, `errorCallback`. It also notifies via the return value of the
11284     *   `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
11285     *   method.
11286     *
11287     * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
11288     *
11289     * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
11290     *   but to do so without modifying the final value. This is useful to release resources or do some
11291     *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
11292     *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
11293     *   more information.
11294     *
11295     *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
11296     *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
11297     *   make your code IE8 and Android 2.x compatible.
11298     *
11299     * # Chaining promises
11300     *
11301     * Because calling the `then` method of a promise returns a new derived promise, it is easily
11302     * possible to create a chain of promises:
11303     *
11304     * ```js
11305     *   promiseB = promiseA.then(function(result) {
11306 *     return result + 1;
11307 *   });
11308     *
11309     *   // promiseB will be resolved immediately after promiseA is resolved and its value
11310     *   // will be the result of promiseA incremented by 1
11311     * ```
11312     *
11313     * It is possible to create chains of any length and since a promise can be resolved with another
11314     * promise (which will defer its resolution further), it is possible to pause/defer resolution of
11315     * the promises at any point in the chain. This makes it possible to implement powerful APIs like
11316     * $http's response interceptors.
11317     *
11318     *
11319     * # Differences between Kris Kowal's Q and $q
11320     *
11321     *  There are two main differences:
11322     *
11323     * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
11324     *   mechanism in angular, which means faster propagation of resolution or rejection into your
11325     *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
11326     * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
11327     *   all the important functionality needed for common async tasks.
11328     *
11329     *  # Testing
11330     *
11331     *  ```js
11332     *    it('should simulate promise', inject(function($q, $rootScope) {
11333 *      var deferred = $q.defer();
11334 *      var promise = deferred.promise;
11335 *      var resolvedValue;
11336 *
11337 *      promise.then(function(value) { resolvedValue = value; });
11338 *      expect(resolvedValue).toBeUndefined();
11339 *
11340 *      // Simulate resolving of promise
11341 *      deferred.resolve(123);
11342 *      // Note that the 'then' function does not get called synchronously.
11343 *      // This is because we want the promise API to always be async, whether or not
11344 *      // it got called synchronously or asynchronously.
11345 *      expect(resolvedValue).toBeUndefined();
11346 *
11347 *      // Propagate promise resolution to 'then' functions using $apply().
11348 *      $rootScope.$apply();
11349 *      expect(resolvedValue).toEqual(123);
11350 *    }));
11351     *  ```
11352     */
11353    function $QProvider() {
11354
11355        this.$get = ['$rootScope', '$exceptionHandler', function ($rootScope, $exceptionHandler) {
11356            return qFactory(function (callback) {
11357                $rootScope.$evalAsync(callback);
11358            }, $exceptionHandler);
11359        }];
11360    }
11361
11362
11363    /**
11364     * Constructs a promise manager.
11365     *
11366     * @param {function(Function)} nextTick Function for executing functions in the next turn.
11367     * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
11368     *     debugging purposes.
11369     * @returns {object} Promise manager.
11370     */
11371    function qFactory(nextTick, exceptionHandler) {
11372
11373        /**
11374         * @ngdoc method
11375         * @name $q#defer
11376         * @function
11377         *
11378         * @description
11379         * Creates a `Deferred` object which represents a task which will finish in the future.
11380         *
11381         * @returns {Deferred} Returns a new instance of deferred.
11382         */
11383        var defer = function () {
11384            var pending = [],
11385                value, deferred;
11386
11387            deferred = {
11388
11389                resolve: function (val) {
11390                    if (pending) {
11391                        var callbacks = pending;
11392                        pending = undefined;
11393                        value = ref(val);
11394
11395                        if (callbacks.length) {
11396                            nextTick(function () {
11397                                var callback;
11398                                for (var i = 0, ii = callbacks.length; i < ii; i++) {
11399                                    callback = callbacks[i];
11400                                    value.then(callback[0], callback[1], callback[2]);
11401                                }
11402                            });
11403                        }
11404                    }
11405                },
11406
11407
11408                reject: function (reason) {
11409                    deferred.resolve(createInternalRejectedPromise(reason));
11410                },
11411
11412
11413                notify: function (progress) {
11414                    if (pending) {
11415                        var callbacks = pending;
11416
11417                        if (pending.length) {
11418                            nextTick(function () {
11419                                var callback;
11420                                for (var i = 0, ii = callbacks.length; i < ii; i++) {
11421                                    callback = callbacks[i];
11422                                    callback[2](progress);
11423                                }
11424                            });
11425                        }
11426                    }
11427                },
11428
11429
11430                promise: {
11431                    then: function (callback, errback, progressback) {
11432                        var result = defer();
11433
11434                        var wrappedCallback = function (value) {
11435                            try {
11436                                result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
11437                            } catch (e) {
11438                                result.reject(e);
11439                                exceptionHandler(e);
11440                            }
11441                        };
11442
11443                        var wrappedErrback = function (reason) {
11444                            try {
11445                                result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11446                            } catch (e) {
11447                                result.reject(e);
11448                                exceptionHandler(e);
11449                            }
11450                        };
11451
11452                        var wrappedProgressback = function (progress) {
11453                            try {
11454                                result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
11455                            } catch (e) {
11456                                exceptionHandler(e);
11457                            }
11458                        };
11459
11460                        if (pending) {
11461                            pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
11462                        } else {
11463                            value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
11464                        }
11465
11466                        return result.promise;
11467                    },
11468
11469                    "catch": function (callback) {
11470                        return this.then(null, callback);
11471                    },
11472
11473                    "finally": function (callback) {
11474
11475                        function makePromise(value, resolved) {
11476                            var result = defer();
11477                            if (resolved) {
11478                                result.resolve(value);
11479                            } else {
11480                                result.reject(value);
11481                            }
11482                            return result.promise;
11483                        }
11484
11485                        function handleCallback(value, isResolved) {
11486                            var callbackOutput = null;
11487                            try {
11488                                callbackOutput = (callback || defaultCallback)();
11489                            } catch (e) {
11490                                return makePromise(e, false);
11491                            }
11492                            if (callbackOutput && isFunction(callbackOutput.then)) {
11493                                return callbackOutput.then(function () {
11494                                    return makePromise(value, isResolved);
11495                                }, function (error) {
11496                                    return makePromise(error, false);
11497                                });
11498                            } else {
11499                                return makePromise(value, isResolved);
11500                            }
11501                        }
11502
11503                        return this.then(function (value) {
11504                            return handleCallback(value, true);
11505                        }, function (error) {
11506                            return handleCallback(error, false);
11507                        });
11508                    }
11509                }
11510            };
11511
11512            return deferred;
11513        };
11514
11515
11516        var ref = function (value) {
11517            if (value && isFunction(value.then)) return value;
11518            return {
11519                then: function (callback) {
11520                    var result = defer();
11521                    nextTick(function () {
11522                        result.resolve(callback(value));
11523                    });
11524                    return result.promise;
11525                }
11526            };
11527        };
11528
11529
11530        /**
11531         * @ngdoc method
11532         * @name $q#reject
11533         * @function
11534         *
11535         * @description
11536         * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
11537         * used to forward rejection in a chain of promises. If you are dealing with the last promise in
11538         * a promise chain, you don't need to worry about it.
11539         *
11540         * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
11541         * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
11542         * a promise error callback and you want to forward the error to the promise derived from the
11543         * current promise, you have to "rethrow" the error by returning a rejection constructed via
11544         * `reject`.
11545         *
11546         * ```js
11547         *   promiseB = promiseA.then(function(result) {
11548   *     // success: do something and resolve promiseB
11549   *     //          with the old or a new result
11550   *     return result;
11551   *   }, function(reason) {
11552   *     // error: handle the error if possible and
11553   *     //        resolve promiseB with newPromiseOrValue,
11554   *     //        otherwise forward the rejection to promiseB
11555   *     if (canHandle(reason)) {
11556   *      // handle the error and recover
11557   *      return newPromiseOrValue;
11558   *     }
11559   *     return $q.reject(reason);
11560   *   });
11561         * ```
11562         *
11563         * @param {*} reason Constant, message, exception or an object representing the rejection reason.
11564         * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
11565         */
11566        var reject = function (reason) {
11567            var result = defer();
11568            result.reject(reason);
11569            return result.promise;
11570        };
11571
11572        var createInternalRejectedPromise = function (reason) {
11573            return {
11574                then: function (callback, errback) {
11575                    var result = defer();
11576                    nextTick(function () {
11577                        try {
11578                            result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
11579                        } catch (e) {
11580                            result.reject(e);
11581                            exceptionHandler(e);
11582                        }
11583                    });
11584                    return result.promise;
11585                }
11586            };
11587        };
11588
11589
11590        /**
11591         * @ngdoc method
11592         * @name $q#when
11593         * @function
11594         *
11595         * @description
11596         * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
11597         * This is useful when you are dealing with an object that might or might not be a promise, or if
11598         * the promise comes from a source that can't be trusted.
11599         *
11600         * @param {*} value Value or a promise
11601         * @returns {Promise} Returns a promise of the passed value or promise
11602         */
11603        var when = function (value, callback, errback, progressback) {
11604            var result = defer(),
11605                done;
11606
11607            var wrappedCallback = function (value) {
11608                try {
11609                    return (isFunction(callback) ? callback : defaultCallback)(value);
11610                } catch (e) {
11611                    exceptionHandler(e);
11612                    return reject(e);
11613                }
11614            };
11615
11616            var wrappedErrback = function (reason) {
11617                try {
11618                    return (isFunction(errback) ? errback : defaultErrback)(reason);
11619                } catch (e) {
11620                    exceptionHandler(e);
11621                    return reject(e);
11622                }
11623            };
11624
11625            var wrappedProgressback = function (progress) {
11626                try {
11627                    return (isFunction(progressback) ? progressback : defaultCallback)(progress);
11628                } catch (e) {
11629                    exceptionHandler(e);
11630                }
11631            };
11632
11633            nextTick(function () {
11634                ref(value).then(function (value) {
11635                    if (done) return;
11636                    done = true;
11637                    result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
11638                }, function (reason) {
11639                    if (done) return;
11640                    done = true;
11641                    result.resolve(wrappedErrback(reason));
11642                }, function (progress) {
11643                    if (done) return;
11644                    result.notify(wrappedProgressback(progress));
11645                });
11646            });
11647
11648            return result.promise;
11649        };
11650
11651
11652        function defaultCallback(value) {
11653            return value;
11654        }
11655
11656
11657        function defaultErrback(reason) {
11658            return reject(reason);
11659        }
11660
11661
11662        /**
11663         * @ngdoc method
11664         * @name $q#all
11665         * @function
11666         *
11667         * @description
11668         * Combines multiple promises into a single promise that is resolved when all of the input
11669         * promises are resolved.
11670         *
11671         * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
11672         * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
11673         *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
11674         *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
11675         *   with the same rejection value.
11676         */
11677        function all(promises) {
11678            var deferred = defer(),
11679                counter = 0,
11680                results = isArray(promises) ? [] : {};
11681
11682            forEach(promises, function (promise, key) {
11683                counter++;
11684                ref(promise).then(function (value) {
11685                    if (results.hasOwnProperty(key)) return;
11686                    results[key] = value;
11687                    if (!(--counter)) deferred.resolve(results);
11688                }, function (reason) {
11689                    if (results.hasOwnProperty(key)) return;
11690                    deferred.reject(reason);
11691                });
11692            });
11693
11694            if (counter === 0) {
11695                deferred.resolve(results);
11696            }
11697
11698            return deferred.promise;
11699        }
11700
11701        return {
11702            defer: defer,
11703            reject: reject,
11704            when: when,
11705            all: all
11706        };
11707    }
11708
11709    function $$RAFProvider() { //rAF
11710        this.$get = ['$window', '$timeout', function ($window, $timeout) {
11711            var requestAnimationFrame = $window.requestAnimationFrame ||
11712                $window.webkitRequestAnimationFrame ||
11713                $window.mozRequestAnimationFrame;
11714
11715            var cancelAnimationFrame = $window.cancelAnimationFrame ||
11716                $window.webkitCancelAnimationFrame ||
11717                $window.mozCancelAnimationFrame ||
11718                $window.webkitCancelRequestAnimationFrame;
11719
11720            var rafSupported = !!requestAnimationFrame;
11721            var raf = rafSupported
11722                ? function (fn) {
11723                var id = requestAnimationFrame(fn);
11724                return function () {
11725                    cancelAnimationFrame(id);
11726                };
11727            }
11728                : function (fn) {
11729                var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
11730                return function () {
11731                    $timeout.cancel(timer);
11732                };
11733            };
11734
11735            raf.supported = rafSupported;
11736
11737            return raf;
11738        }];
11739    }
11740
11741    /**
11742     * DESIGN NOTES
11743     *
11744     * The design decisions behind the scope are heavily favored for speed and memory consumption.
11745     *
11746     * The typical use of scope is to watch the expressions, which most of the time return the same
11747     * value as last time so we optimize the operation.
11748     *
11749     * Closures construction is expensive in terms of speed as well as memory:
11750     *   - No closures, instead use prototypical inheritance for API
11751     *   - Internal state needs to be stored on scope directly, which means that private state is
11752     *     exposed as $$____ properties
11753     *
11754     * Loop operations are optimized by using while(count--) { ... }
11755     *   - this means that in order to keep the same order of execution as addition we have to add
11756     *     items to the array at the beginning (shift) instead of at the end (push)
11757     *
11758     * Child scopes are created and removed often
11759     *   - Using an array would be slow since inserts in middle are expensive so we use linked list
11760     *
11761     * There are few watches then a lot of observers. This is why you don't want the observer to be
11762     * implemented in the same way as watch. Watch requires return of initialization function which
11763     * are expensive to construct.
11764     */
11765
11766
11767    /**
11768     * @ngdoc provider
11769     * @name $rootScopeProvider
11770     * @description
11771     *
11772     * Provider for the $rootScope service.
11773     */
11774
11775    /**
11776     * @ngdoc method
11777     * @name $rootScopeProvider#digestTtl
11778     * @description
11779     *
11780     * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
11781     * assuming that the model is unstable.
11782     *
11783     * The current default is 10 iterations.
11784     *
11785     * In complex applications it's possible that the dependencies between `$watch`s will result in
11786     * several digest iterations. However if an application needs more than the default 10 digest
11787     * iterations for its model to stabilize then you should investigate what is causing the model to
11788     * continuously change during the digest.
11789     *
11790     * Increasing the TTL could have performance implications, so you should not change it without
11791     * proper justification.
11792     *
11793     * @param {number} limit The number of digest iterations.
11794     */
11795
11796
11797    /**
11798     * @ngdoc service
11799     * @name $rootScope
11800     * @description
11801     *
11802     * Every application has a single root {@link ng.$rootScope.Scope scope}.
11803     * All other scopes are descendant scopes of the root scope. Scopes provide separation
11804     * between the model and the view, via a mechanism for watching the model for changes.
11805     * They also provide an event emission/broadcast and subscription facility. See the
11806     * {@link guide/scope developer guide on scopes}.
11807     */
11808    function $RootScopeProvider() {
11809        var TTL = 10;
11810        var $rootScopeMinErr = minErr('$rootScope');
11811        var lastDirtyWatch = null;
11812
11813        this.digestTtl = function (value) {
11814            if (arguments.length) {
11815                TTL = value;
11816            }
11817            return TTL;
11818        };
11819
11820        this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
11821            function ($injector, $exceptionHandler, $parse, $browser) {
11822
11823                /**
11824                 * @ngdoc type
11825                 * @name $rootScope.Scope
11826                 *
11827                 * @description
11828                 * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
11829                 * {@link auto.$injector $injector}. Child scopes are created using the
11830                 * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
11831                 * compiled HTML template is executed.)
11832                 *
11833                 * Here is a simple scope snippet to show how you can interact with the scope.
11834                 * ```html
11835                 * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
11836                 * ```
11837                 *
11838                 * # Inheritance
11839                 * A scope can inherit from a parent scope, as in this example:
11840                 * ```js
11841                 var parent = $rootScope;
11842                 var child = parent.$new();
11843
11844                 parent.salutation = "Hello";
11845                 child.name = "World";
11846                 expect(child.salutation).toEqual('Hello');
11847
11848                 child.salutation = "Welcome";
11849                 expect(child.salutation).toEqual('Welcome');
11850                 expect(parent.salutation).toEqual('Hello');
11851                 * ```
11852                 *
11853                 *
11854                 * @param {Object.<string, function()>=} providers Map of service factory which need to be
11855                 *                                       provided for the current scope. Defaults to {@link ng}.
11856                 * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
11857                 *                              append/override services provided by `providers`. This is handy
11858                 *                              when unit-testing and having the need to override a default
11859                 *                              service.
11860                 * @returns {Object} Newly created scope.
11861                 *
11862                 */
11863                function Scope() {
11864                    this.$id = nextUid();
11865                    this.$$phase = this.$parent = this.$$watchers =
11866                        this.$$nextSibling = this.$$prevSibling =
11867                            this.$$childHead = this.$$childTail = null;
11868                    this['this'] = this.$root = this;
11869                    this.$$destroyed = false;
11870                    this.$$asyncQueue = [];
11871                    this.$$postDigestQueue = [];
11872                    this.$$listeners = {};
11873                    this.$$listenerCount = {};
11874                    this.$$isolateBindings = {};
11875                }
11876
11877                /**
11878                 * @ngdoc property
11879                 * @name $rootScope.Scope#$id
11880                 * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11881                 *   debugging.
11882                 */
11883
11884
11885                Scope.prototype = {
11886                    constructor: Scope,
11887                    /**
11888                     * @ngdoc method
11889                     * @name $rootScope.Scope#$new
11890                     * @function
11891                     *
11892                     * @description
11893                     * Creates a new child {@link ng.$rootScope.Scope scope}.
11894                     *
11895                     * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
11896                     * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
11897                     * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
11898                     *
11899                     * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
11900                     * desired for the scope and its child scopes to be permanently detached from the parent and
11901                     * thus stop participating in model change detection and listener notification by invoking.
11902                     *
11903                     * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
11904                     *         parent scope. The scope is isolated, as it can not see parent scope properties.
11905                     *         When creating widgets, it is useful for the widget to not accidentally read parent
11906                     *         state.
11907                     *
11908                     * @returns {Object} The newly created child scope.
11909                     *
11910                     */
11911                    $new: function (isolate) {
11912                        var ChildScope,
11913                            child;
11914
11915                        if (isolate) {
11916                            child = new Scope();
11917                            child.$root = this.$root;
11918                            // ensure that there is just one async queue per $rootScope and its children
11919                            child.$$asyncQueue = this.$$asyncQueue;
11920                            child.$$postDigestQueue = this.$$postDigestQueue;
11921                        } else {
11922                            ChildScope = function () {
11923                            }; // should be anonymous; This is so that when the minifier munges
11924                            // the name it does not become random set of chars. This will then show up as class
11925                            // name in the web inspector.
11926                            ChildScope.prototype = this;
11927                            child = new ChildScope();
11928                            child.$id = nextUid();
11929                        }
11930                        child['this'] = child;
11931                        child.$$listeners = {};
11932                        child.$$listenerCount = {};
11933                        child.$parent = this;
11934                        child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
11935                        child.$$prevSibling = this.$$childTail;
11936                        if (this.$$childHead) {
11937                            this.$$childTail.$$nextSibling = child;
11938                            this.$$childTail = child;
11939                        } else {
11940                            this.$$childHead = this.$$childTail = child;
11941                        }
11942                        return child;
11943                    },
11944
11945                    /**
11946                     * @ngdoc method
11947                     * @name $rootScope.Scope#$watch
11948                     * @function
11949                     *
11950                     * @description
11951                     * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
11952                     *
11953                     * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
11954       *   $digest()} and should return the value that will be watched. (Since
11955                     *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
11956                     *   `watchExpression` can execute multiple times per
11957                     *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
11958                     * - The `listener` is called only when the value from the current `watchExpression` and the
11959                     *   previous call to `watchExpression` are not equal (with the exception of the initial run,
11960                     *   see below). The inequality is determined according to
11961                     *   {@link angular.equals} function. To save the value of the object for later comparison,
11962                     *   the {@link angular.copy} function is used. It also means that watching complex options
11963                     *   will have adverse memory and performance implications.
11964                     * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
11965                     *   This is achieved by rerunning the watchers until no changes are detected. The rerun
11966                     *   iteration limit is 10 to prevent an infinite loop deadlock.
11967                     *
11968                     *
11969                     * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
11970                     * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
11971                     * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
11972                     * change is detected, be prepared for multiple calls to your listener.)
11973                     *
11974                     * After a watcher is registered with the scope, the `listener` fn is called asynchronously
11975                     * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
11976                     * watcher. In rare cases, this is undesirable because the listener is called when the result
11977                     * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
11978                     * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
11979                     * listener was called due to initialization.
11980                     *
11981                     * The example below contains an illustration of using a function as your $watch listener
11982                     *
11983                     *
11984                     * # Example
11985                     * ```js
11986                     // let's assume that scope was dependency injected as the $rootScope
11987                     var scope = $rootScope;
11988                     scope.name = 'misko';
11989                     scope.counter = 0;
11990
11991                     expect(scope.counter).toEqual(0);
11992                     scope.$watch('name', function(newValue, oldValue) {
11993             scope.counter = scope.counter + 1;
11994           });
11995                     expect(scope.counter).toEqual(0);
11996
11997                     scope.$digest();
11998                     // no variable change
11999                     expect(scope.counter).toEqual(0);
12000
12001                     scope.name = 'adam';
12002                     scope.$digest();
12003                     expect(scope.counter).toEqual(1);
12004
12005
12006
12007                     // Using a listener function
12008                     var food;
12009                     scope.foodCounter = 0;
12010                     expect(scope.foodCounter).toEqual(0);
12011                     scope.$watch(
12012                     // This is the listener function
12013                     function() { return food; },
12014                     // This is the change handler
12015                     function(newValue, oldValue) {
12016               if ( newValue !== oldValue ) {
12017                 // Only increment the counter if the value changed
12018                 scope.foodCounter = scope.foodCounter + 1;
12019               }
12020             }
12021                     );
12022                     // No digest has been run so the counter will be zero
12023                     expect(scope.foodCounter).toEqual(0);
12024
12025                     // Run the digest but since food has not changed count will still be zero
12026                     scope.$digest();
12027                     expect(scope.foodCounter).toEqual(0);
12028
12029                     // Update food and run digest.  Now the counter will increment
12030                     food = 'cheeseburger';
12031                     scope.$digest();
12032                     expect(scope.foodCounter).toEqual(1);
12033
12034                     * ```
12035                     *
12036                     *
12037                     *
12038                     * @param {(function()|string)} watchExpression Expression that is evaluated on each
12039                     *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
12040                     *    a call to the `listener`.
12041                     *
12042                     *    - `string`: Evaluated as {@link guide/expression expression}
12043                     *    - `function(scope)`: called with current `scope` as a parameter.
12044                     * @param {(function()|string)=} listener Callback called whenever the return value of
12045                     *   the `watchExpression` changes.
12046                     *
12047                     *    - `string`: Evaluated as {@link guide/expression expression}
12048                     *    - `function(newValue, oldValue, scope)`: called with current and previous values as
12049                     *      parameters.
12050                     *
12051                     * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
12052                     *     comparing for reference equality.
12053                     * @returns {function()} Returns a deregistration function for this listener.
12054                     */
12055                    $watch: function (watchExp, listener, objectEquality) {
12056                        var scope = this,
12057                            get = compileToFn(watchExp, 'watch'),
12058                            array = scope.$$watchers,
12059                            watcher = {
12060                                fn: listener,
12061                                last: initWatchVal,
12062                                get: get,
12063                                exp: watchExp,
12064                                eq: !!objectEquality
12065                            };
12066
12067                        lastDirtyWatch = null;
12068
12069                        // in the case user pass string, we need to compile it, do we really need this ?
12070                        if (!isFunction(listener)) {
12071                            var listenFn = compileToFn(listener || noop, 'listener');
12072                            watcher.fn = function (newVal, oldVal, scope) {
12073                                listenFn(scope);
12074                            };
12075                        }
12076
12077                        if (typeof watchExp == 'string' && get.constant) {
12078                            var originalFn = watcher.fn;
12079                            watcher.fn = function (newVal, oldVal, scope) {
12080                                originalFn.call(this, newVal, oldVal, scope);
12081                                arrayRemove(array, watcher);
12082                            };
12083                        }
12084
12085                        if (!array) {
12086                            array = scope.$$watchers = [];
12087                        }
12088                        // we use unshift since we use a while loop in $digest for speed.
12089                        // the while loop reads in reverse order.
12090                        array.unshift(watcher);
12091
12092                        return function () {
12093                            arrayRemove(array, watcher);
12094                            lastDirtyWatch = null;
12095                        };
12096                    },
12097
12098
12099                    /**
12100                     * @ngdoc method
12101                     * @name $rootScope.Scope#$watchCollection
12102                     * @function
12103                     *
12104                     * @description
12105                     * Shallow watches the properties of an object and fires whenever any of the properties change
12106                     * (for arrays, this implies watching the array items; for object maps, this implies watching
12107                     * the properties). If a change is detected, the `listener` callback is fired.
12108                     *
12109                     * - The `obj` collection is observed via standard $watch operation and is examined on every
12110                     *   call to $digest() to see if any items have been added, removed, or moved.
12111                     * - The `listener` is called whenever anything within the `obj` has changed. Examples include
12112                     *   adding, removing, and moving items belonging to an object or array.
12113                     *
12114                     *
12115                     * # Example
12116                     * ```js
12117                     $scope.names = ['igor', 'matias', 'misko', 'james'];
12118                     $scope.dataCount = 4;
12119
12120                     $scope.$watchCollection('names', function(newNames, oldNames) {
12121            $scope.dataCount = newNames.length;
12122          });
12123
12124                     expect($scope.dataCount).toEqual(4);
12125                     $scope.$digest();
12126
12127                     //still at 4 ... no changes
12128                     expect($scope.dataCount).toEqual(4);
12129
12130                     $scope.names.pop();
12131                     $scope.$digest();
12132
12133                     //now there's been a change
12134                     expect($scope.dataCount).toEqual(3);
12135                     * ```
12136                     *
12137                     *
12138                     * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
12139                     *    expression value should evaluate to an object or an array which is observed on each
12140                     *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
12141                     *    collection will trigger a call to the `listener`.
12142                     *
12143                     * @param {function(newCollection, oldCollection, scope)} listener a callback function called
12144                     *    when a change is detected.
12145                     *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
12146                     *    - The `oldCollection` object is a copy of the former collection data.
12147                     *      Due to performance considerations, the`oldCollection` value is computed only if the
12148                     *      `listener` function declares two or more arguments.
12149                     *    - The `scope` argument refers to the current scope.
12150                     *
12151                     * @returns {function()} Returns a de-registration function for this listener. When the
12152                     *    de-registration function is executed, the internal watch operation is terminated.
12153                     */
12154                    $watchCollection: function (obj, listener) {
12155                        var self = this;
12156                        // the current value, updated on each dirty-check run
12157                        var newValue;
12158                        // a shallow copy of the newValue from the last dirty-check run,
12159                        // updated to match newValue during dirty-check run
12160                        var oldValue;
12161                        // a shallow copy of the newValue from when the last change happened
12162                        var veryOldValue;
12163                        // only track veryOldValue if the listener is asking for it
12164                        var trackVeryOldValue = (listener.length > 1);
12165                        var changeDetected = 0;
12166                        var objGetter = $parse(obj);
12167                        var internalArray = [];
12168                        var internalObject = {};
12169                        var initRun = true;
12170                        var oldLength = 0;
12171
12172                        function $watchCollectionWatch() {
12173                            newValue = objGetter(self);
12174                            var newLength, key;
12175
12176                            if (!isObject(newValue)) { // if primitive
12177                                if (oldValue !== newValue) {
12178                                    oldValue = newValue;
12179                                    changeDetected++;
12180                                }
12181                            } else if (isArrayLike(newValue)) {
12182                                if (oldValue !== internalArray) {
12183                                    // we are transitioning from something which was not an array into array.
12184                                    oldValue = internalArray;
12185                                    oldLength = oldValue.length = 0;
12186                                    changeDetected++;
12187                                }
12188
12189                                newLength = newValue.length;
12190
12191                                if (oldLength !== newLength) {
12192                                    // if lengths do not match we need to trigger change notification
12193                                    changeDetected++;
12194                                    oldValue.length = oldLength = newLength;
12195                                }
12196                                // copy the items to oldValue and look for changes.
12197                                for (var i = 0; i < newLength; i++) {
12198                                    var bothNaN = (oldValue[i] !== oldValue[i]) &&
12199                                        (newValue[i] !== newValue[i]);
12200                                    if (!bothNaN && (oldValue[i] !== newValue[i])) {
12201                                        changeDetected++;
12202                                        oldValue[i] = newValue[i];
12203                                    }
12204                                }
12205                            } else {
12206                                if (oldValue !== internalObject) {
12207                                    // we are transitioning from something which was not an object into object.
12208                                    oldValue = internalObject = {};
12209                                    oldLength = 0;
12210                                    changeDetected++;
12211                                }
12212                                // copy the items to oldValue and look for changes.
12213                                newLength = 0;
12214                                for (key in newValue) {
12215                                    if (newValue.hasOwnProperty(key)) {
12216                                        newLength++;
12217                                        if (oldValue.hasOwnProperty(key)) {
12218                                            if (oldValue[key] !== newValue[key]) {
12219                                                changeDetected++;
12220                                                oldValue[key] = newValue[key];
12221                                            }
12222                                        } else {
12223                                            oldLength++;
12224                                            oldValue[key] = newValue[key];
12225                                            changeDetected++;
12226                                        }
12227                                    }
12228                                }
12229                                if (oldLength > newLength) {
12230                                    // we used to have more keys, need to find them and destroy them.
12231                                    changeDetected++;
12232                                    for (key in oldValue) {
12233                                        if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
12234                                            oldLength--;
12235                                            delete oldValue[key];
12236                                        }
12237                                    }
12238                                }
12239                            }
12240                            return changeDetected;
12241                        }
12242
12243                        function $watchCollectionAction() {
12244                            if (initRun) {
12245                                initRun = false;
12246                                listener(newValue, newValue, self);
12247                            } else {
12248                                listener(newValue, veryOldValue, self);
12249                            }
12250
12251                            // make a copy for the next time a collection is changed
12252                            if (trackVeryOldValue) {
12253                                if (!isObject(newValue)) {
12254                                    //primitive
12255                                    veryOldValue = newValue;
12256                                } else if (isArrayLike(newValue)) {
12257                                    veryOldValue = new Array(newValue.length);
12258                                    for (var i = 0; i < newValue.length; i++) {
12259                                        veryOldValue[i] = newValue[i];
12260                                    }
12261                                } else { // if object
12262                                    veryOldValue = {};
12263                                    for (var key in newValue) {
12264                                        if (hasOwnProperty.call(newValue, key)) {
12265                                            veryOldValue[key] = newValue[key];
12266                                        }
12267                                    }
12268                                }
12269                            }
12270                        }
12271
12272                        return this.$watch($watchCollectionWatch, $watchCollectionAction);
12273                    },
12274
12275                    /**
12276                     * @ngdoc method
12277                     * @name $rootScope.Scope#$digest
12278                     * @function
12279                     *
12280                     * @description
12281                     * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
12282                     * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
12283                     * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
12284                     * until no more listeners are firing. This means that it is possible to get into an infinite
12285                     * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
12286                     * iterations exceeds 10.
12287                     *
12288                     * Usually, you don't call `$digest()` directly in
12289                     * {@link ng.directive:ngController controllers} or in
12290                     * {@link ng.$compileProvider#directive directives}.
12291                     * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
12292                     * a {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
12293                     *
12294                     * If you want to be notified whenever `$digest()` is called,
12295                     * you can register a `watchExpression` function with
12296                     * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
12297                     *
12298                     * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
12299                     *
12300                     * # Example
12301                     * ```js
12302                     var scope = ...;
12303                     scope.name = 'misko';
12304                     scope.counter = 0;
12305
12306                     expect(scope.counter).toEqual(0);
12307                     scope.$watch('name', function(newValue, oldValue) {
12308             scope.counter = scope.counter + 1;
12309           });
12310                     expect(scope.counter).toEqual(0);
12311
12312                     scope.$digest();
12313                     // no variable change
12314                     expect(scope.counter).toEqual(0);
12315
12316                     scope.name = 'adam';
12317                     scope.$digest();
12318                     expect(scope.counter).toEqual(1);
12319                     * ```
12320                     *
12321                     */
12322                    $digest: function () {
12323                        var watch, value, last,
12324                            watchers,
12325                            asyncQueue = this.$$asyncQueue,
12326                            postDigestQueue = this.$$postDigestQueue,
12327                            length,
12328                            dirty, ttl = TTL,
12329                            next, current, target = this,
12330                            watchLog = [],
12331                            logIdx, logMsg, asyncTask;
12332
12333                        beginPhase('$digest');
12334
12335                        lastDirtyWatch = null;
12336
12337                        do { // "while dirty" loop
12338                            dirty = false;
12339                            current = target;
12340
12341                            while (asyncQueue.length) {
12342                                try {
12343                                    asyncTask = asyncQueue.shift();
12344                                    asyncTask.scope.$eval(asyncTask.expression);
12345                                } catch (e) {
12346                                    clearPhase();
12347                                    $exceptionHandler(e);
12348                                }
12349                                lastDirtyWatch = null;
12350                            }
12351
12352                            traverseScopesLoop:
12353                                do { // "traverse the scopes" loop
12354                                    if ((watchers = current.$$watchers)) {
12355                                        // process our watches
12356                                        length = watchers.length;
12357                                        while (length--) {
12358                                            try {
12359                                                watch = watchers[length];
12360                                                // Most common watches are on primitives, in which case we can short
12361                                                // circuit it with === operator, only when === fail
12361s do we use .equals
12362                                                if (watch) {
12363                                                    if ((value = watch.get(current)) !== (last = watch.last) && !(watch.eq
12364                                                        ? equals(value, last)
12365                                                        : (typeof value == 'number' && typeof last == 'number'
12366                                                        && isNaN(value) && isNaN(last)))) {
12367                                                        dirty = true;
12368                                                        lastDirtyWatch = watch;
12369                                                        watch.last = watch.eq ? copy(value) : value;
12370                                                        watch.fn(value, ((last === initWatchVal) ? value : last), current);
12371                                                        if (ttl < 5) {
12372                                                            logIdx = 4 - ttl;
12373                                                            if (!watchLog[logIdx]) watchLog[logIdx] = [];
12374                                                            logMsg = (isFunction(watch.exp))
12375                                                                ? 'fn: ' + (watch.exp.name || watch.exp.toString())
12376                                                                : watch.exp;
12377                                                            logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
12378                                                            watchLog[logIdx].push(logMsg);
12379                                                        }
12380                                                    } else if (watch === lastDirtyWatch) {
12381                                                        // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
12382                                                        // have already been tested.
12383                                                        dirty = false;
12384                                                        break traverseScopesLoop;
12385                                                    }
12386                                                }
12387                                            } catch (e) {
12388                                                clearPhase();
12389                                                $exceptionHandler(e);
12390                                            }
12391                                        }
12392                                    }
12393
12394                                    // Insanity Warning: scope depth-first traversal
12395                                    // yes, this code is a bit crazy, but it works and we have tests to prove it!
12396                                    // this piece should be kept in sync with the traversal in $broadcast
12397                                    if (!(next = (current.$$childHead ||
12398                                        (current !== target && current.$$nextSibling)))) {
12399                                        while (current !== target && !(next = current.$$nextSibling)) {
12400                                            current = current.$parent;
12401                                        }
12402                                    }
12403                                } while ((current = next));
12404
12405                            // `break traverseScopesLoop;` takes us to here
12406
12407                            if ((dirty || asyncQueue.length) && !(ttl--)) {
12408                                clearPhase();
12409                                throw $rootScopeMinErr('infdig',
12410                                    '{0} $digest() iterations reached. Aborting!\n' +
12411                                        'Watchers fired in the last 5 iterations: {1}',
12412                                    TTL, toJson(watchLog));
12413                            }
12414
12415                        } while (dirty || asyncQueue.length);
12416
12417                        clearPhase();
12418
12419                        while (postDigestQueue.length) {
12420                            try {
12421                                postDigestQueue.shift()();
12422                            } catch (e) {
12423                                $exceptionHandler(e);
12424                            }
12425                        }
12426                    },
12427
12428
12429                    /**
12430                     * @ngdoc event
12431                     * @name $rootScope.Scope#$destroy
12432                     * @eventType broadcast on scope being destroyed
12433                     *
12434                     * @description
12435                     * Broadcasted when a scope and its children are being destroyed.
12436                     *
12437                     * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12438                     * clean up DOM bindings before an element is removed from the DOM.
12439                     */
12440
12441                    /**
12442                     * @ngdoc method
12443                     * @name $rootScope.Scope#$destroy
12444                     * @function
12445                     *
12446                     * @description
12447                     * Removes the current scope (and all of its children) from the parent scope. Removal implies
12448                     * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
12449                     * propagate to the current scope and its children. Removal also implies that the current
12450                     * scope is eligible for garbage collection.
12451                     *
12452                     * The `$destroy()` is usually used by directives such as
12453                     * {@link ng.directive:ngRepeat ngRepeat} for managing the
12454                     * unrolling of the loop.
12455                     *
12456                     * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
12457                     * Application code can register a `$destroy` event handler that will give it a chance to
12458                     * perform any necessary cleanup.
12459                     *
12460                     * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
12461                     * clean up DOM bindings before an element is removed from the DOM.
12462                     */
12463                    $destroy: function () {
12464                        // we can't destroy the root scope or a scope that has been already destroyed
12465                        if (this.$$destroyed) return;
12466                        var parent = this.$parent;
12467
12468                        this.$broadcast('$destroy');
12469                        this.$$destroyed = true;
12470                        if (this === $rootScope) return;
12471
12472                        forEach(this.$$listenerCount, bind(null, decrementListenerCount, this));
12473
12474                        // sever all the references to parent scopes (after this cleanup, the current scope should
12475                        // not be retained by any of our references and should be eligible for garbage collection)
12476                        if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
12477                        if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
12478                        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
12479                        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
12480
12481
12482                        // All of the code below is bogus code that works around V8's memory leak via optimized code
12483                        // and inline caches.
12484                        //
12485                        // see:
12486                        // - https://code.google.com/p/v8/issues/detail?id=2073#c26
12487                        // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
12488                        // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
12489
12490                        this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
12491                            this.$$childTail = this.$root = null;
12492
12493                        // don't reset these to null in case some async task tries to register a listener/watch/task
12494                        this.$$listeners = {};
12495                        this.$$watchers = this.$$asyncQueue = this.$$postDigestQueue = [];
12496
12497                        // prevent NPEs since these methods have references to properties we nulled out
12498                        this.$destroy = this.$digest = this.$apply = noop;
12499                        this.$on = this.$watch = function () {
12500                            return noop;
12501                        };
12502                    },
12503
12504                    /**
12505                     * @ngdoc method
12506                     * @name $rootScope.Scope#$eval
12507                     * @function
12508                     *
12509                     * @description
12510                     * Executes the `expression` on the current scope and returns the result. Any exceptions in
12511                     * the expression are propagated (uncaught). This is useful when evaluating Angular
12512                     * expressions.
12513                     *
12514                     * # Example
12515                     * ```js
12516                     var scope = ng.$rootScope.Scope();
12517                     scope.a = 1;
12518                     scope.b = 2;
12519
12520                     expect(scope.$eval('a+b')).toEqual(3);
12521                     expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
12522                     * ```
12523                     *
12524                     * @param {(string|function())=} expression An angular expression to be executed.
12525                     *
12526                     *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
12527                     *    - `function(scope)`: execute the function with the current `scope` parameter.
12528                     *
12529                     * @param {(object)=} locals Local variables object, useful for overriding values in scope.
12530                     * @returns {*} The result of evaluating the expression.
12531                     */
12532                    $eval: function (expr, locals) {
12533                        return $parse(expr)(this, locals);
12534                    },
12535
12536                    /**
12537                     * @ngdoc method
12538                     * @name $rootScope.Scope#$evalAsync
12539                     * @function
12540                     *
12541                     * @description
12542                     * Executes the expression on the current scope at a later point in time.
12543                     *
12544                     * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
12545                     * that:
12546                     *
12547                     *   - it will execute after the function that scheduled the evaluation (preferably before DOM
12548                     *     rendering).
12549                     *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
12550                     *     `expression` execution.
12551                     *
12552                     * Any exceptions from the execution of the expression are forwarded to the
12553                     * {@link ng.$exceptionHandler $exceptionHandler} service.
12554                     *
12555                     * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
12556                     * will be scheduled. However, it is encouraged to always call code that changes the model
12557                     * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
12558                     *
12559                     * @param {(string|function())=} expression An angular expression to be executed.
12560                     *
12561                     *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12562                     *    - `function(scope)`: execute the function with the current `scope` parameter.
12563                     *
12564                     */
12565                    $evalAsync: function (expr) {
12566                        // if we are outside of an $digest loop and this is the first time we are scheduling async
12567                        // task also schedule async auto-flush
12568                        if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
12569                            $browser.defer(function () {
12570                                if ($rootScope.$$asyncQueue.length) {
12571                                    $rootScope.$digest();
12572                                }
12573                            });
12574                        }
12575
12576                        this.$$asyncQueue.push({scope: this, expression: expr});
12577                    },
12578
12579                    $$postDigest: function (fn) {
12580                        this.$$postDigestQueue.push(fn);
12581                    },
12582
12583                    /**
12584                     * @ngdoc method
12585                     * @name $rootScope.Scope#$apply
12586                     * @function
12587                     *
12588                     * @description
12589                     * `$apply()` is used to execute an expression in angular from outside of the angular
12590                     * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
12591                     * Because we are calling into the angular framework we need to perform proper scope life
12592                     * cycle of {@link ng.$exceptionHandler exception handling},
12593                     * {@link ng.$rootScope.Scope#$digest executing watches}.
12594                     *
12595                     * ## Life cycle
12596                     *
12597                     * # Pseudo-Code of `$apply()`
12598                     * ```js
12599                     function $apply(expr) {
12600             try {
12601               return $eval(expr);
12602             } catch (e) {
12603               $exceptionHandler(e);
12604             } finally {
12605               $root.$digest();
12606             }
12607           }
12608                     * ```
12609                     *
12610                     *
12611                     * Scope's `$apply()` method transitions through the following stages:
12612                     *
12613                     * 1. The {@link guide/expression expression} is executed using the
12614                     *    {@link ng.$rootScope.Scope#$eval $eval()} method.
12615                     * 2. Any exceptions from the execution of the expression are forwarded to the
12616                     *    {@link ng.$exceptionHandler $exceptionHandler} service.
12617                     * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
12618                     *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
12619                     *
12620                     *
12621                     * @param {(string|function())=} exp An angular expression to be executed.
12622                     *
12623                     *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
12624                     *    - `function(scope)`: execute the function with current `scope` parameter.
12625                     *
12626                     * @returns {*} The result of evaluating the expression.
12627                     */
12628                    $apply: function (expr) {
12629                        try {
12630                            beginPhase('$apply');
12631                            return this.$eval(expr);
12632                        } catch (e) {
12633                            $exceptionHandler(e);
12634                        } finally {
12635                            clearPhase();
12636                            try {
12637                                $rootScope.$digest();
12638                            } catch (e) {
12639                                $exceptionHandler(e);
12640                                throw e;
12641                            }
12642                        }
12643                    },
12644
12645                    /**
12646                     * @ngdoc method
12647                     * @name $rootScope.Scope#$on
12648                     * @function
12649                     *
12650                     * @description
12651                     * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
12652                     * discussion of event life cycle.
12653                     *
12654                     * The event listener function format is: `function(event, args...)`. The `event` object
12655                     * passed into the listener has the following attributes:
12656                     *
12657                     *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
12658                     *     `$broadcast`-ed.
12659                     *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
12660                     *   - `name` - `{string}`: name of the event.
12661                     *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
12662                     *     further event propagation (available only for events that were `$emit`-ed).
12663                     *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
12664                     *     to true.
12665                     *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
12666                     *
12667                     * @param {string} name Event name to listen on.
12668                     * @param {function(event, ...args)} listener Function to call when the event is emitted.
12669                     * @returns {function()} Returns a deregistration function for this listener.
12670                     */
12671                    $on: function (name, listener) {
12672                        var namedListeners = this.$$listeners[name];
12673                        if (!namedListeners) {
12674                            this.$$listeners[name] = namedListeners = [];
12675                        }
12676                        namedListeners.push(listener);
12677
12678                        var current = this;
12679                        do {
12680                            if (!current.$$listenerCount[name]) {
12681                                current.$$listenerCount[name] = 0;
12682                            }
12683                            current.$$listenerCount[name]++;
12684                        } while ((current = current.$parent));
12685
12686                        var self = this;
12687                        return function () {
12688                            namedListeners[indexOf(namedListeners, listener)] = null;
12689                            decrementListenerCount(self, 1, name);
12690                        };
12691                    },
12692
12693
12694                    /**
12695                     * @ngdoc method
12696                     * @name $rootScope.Scope#$emit
12697                     * @function
12698                     *
12699                     * @description
12700                     * Dispatches an event `name` upwards through the scope hierarchy notifying the
12701                     * registered {@link ng.$rootScope.Scope#$on} listeners.
12702                     *
12703                     * The event life cycle starts at the scope on which `$emit` was called. All
12704                     * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12705                     * notified. Afterwards, the event traverses upwards toward the root scope and calls all
12706                     * registered listeners along the way. The event will stop propagating if one of the listeners
12707                     * cancels it.
12708                     *
12709                     * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12710                     * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12711                     *
12712                     * @param {string} name Event name to emit.
12713                     * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12714                     * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
12715                     */
12716                    $emit: function (name, args) {
12717                        var empty = [],
12718                            namedListeners,
12719                            scope = this,
12720                            stopPropagation = false,
12721                            event = {
12722                                name: name,
12723                                targetScope: scope,
12724                                stopPropagation: function () {
12725                                    stopPropagation = true;
12726                                },
12727                                preventDefault: function () {
12728                                    event.defaultPrevented = true;
12729                                },
12730                                defaultPrevented: false
12731                            },
12732                            listenerArgs = concat([event], arguments, 1),
12733                            i, length;
12734
12735                        do {
12736                            namedListeners = scope.$$listeners[name] || empty;
12737                            event.currentScope = scope;
12738                            for (i = 0, length = namedListeners.length; i < length; i++) {
12739
12740                                // if listeners were deregistered, defragment the array
12741                                if (!namedListeners[i]) {
12742                                    namedListeners.splice(i, 1);
12743                                    i--;
12744                                    length--;
12745                                    continue;
12746                                }
12747                                try {
12748                                    //allow all listeners attached to the current scope to run
12749                                    namedListeners[i].apply(null, listenerArgs);
12750                                } catch (e) {
12751                                    $exceptionHandler(e);
12752                                }
12753                            }
12754                            //if any listener on the current scope stops propagation, prevent bubbling
12755                            if (stopPropagation) return event;
12756                            //traverse upwards
12757                            scope = scope.$parent;
12758                        } while (scope);
12759
12760                        return event;
12761                    },
12762
12763
12764                    /**
12765                     * @ngdoc method
12766                     * @name $rootScope.Scope#$broadcast
12767                     * @function
12768                     *
12769                     * @description
12770                     * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
12771                     * registered {@link ng.$rootScope.Scope#$on} listeners.
12772                     *
12773                     * The event life cycle starts at the scope on which `$broadcast` was called. All
12774                     * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
12775                     * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
12776                     * scope and calls all registered listeners along the way. The event cannot be canceled.
12777                     *
12778                     * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
12779                     * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
12780                     *
12781                     * @param {string} name Event name to broadcast.
12782                     * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
12783                     * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
12784                     */
12785                    $broadcast: function (name, args) {
12786                        var target = this,
12787                            current = target,
12788                            next = target,
12789                            event = {
12790                                name: name,
12791                                targetScope: target,
12792                                preventDefault: function () {
12793                                    event.defaultPrevented = true;
12794                                },
12795                                defaultPrevented: false
12796                            },
12797                            listenerArgs = concat([event], arguments, 1),
12798                            listeners, i, length;
12799
12800                        //down while you can, then up and next sibling or up and next sibling until back at root
12801                        while ((current = next)) {
12802                            event.currentScope = current;
12803                            listeners = current.$$listeners[name] || [];
12804                            for (i = 0, length = listeners.length; i < length; i++) {
12805                                // if listeners were deregistered, defragment the array
12806                                if (!listeners[i]) {
12807                                    listeners.splice(i, 1);
12808                                    i--;
12809                                    length--;
12810                                    continue;
12811                                }
12812
12813                                try {
12814                                    listeners[i].apply(null, listenerArgs);
12815                                } catch (e) {
12816                                    $exceptionHandler(e);
12817                                }
12818                            }
12819
12820                            // Insanity Warning: scope depth-first traversal
12821                            // yes, this code is a bit crazy, but it works and we have tests to prove it!
12822                            // this piece should be kept in sync with the traversal in $digest
12823                            // (though it differs due to having the extra check for $$listenerCount)
12824                            if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
12825                                (current !== target && current.$$nextSibling)))) {
12826                                while (current !== target && !(next = current.$$nextSibling)) {
12827                                    current = current.$parent;
12828                                }
12829                            }
12830                        }
12831
12832                        return event;
12833                    }
12834                };
12835
12836                var $rootScope = new Scope();
12837
12838                return $rootScope;
12839
12840
12841                function beginPhase(phase) {
12842                    if ($rootScope.$$phase) {
12843                        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
12844                    }
12845
12846                    $rootScope.$$phase = phase;
12847                }
12848
12849                function clearPhase() {
12850                    $rootScope.$$phase = null;
12851                }
12852
12853                function compileToFn(exp, name) {
12854                    var fn = $parse(exp);
12855                    assertArgFn(fn, name);
12856                    return fn;
12857                }
12858
12859                function decrementListenerCount(current, count, name) {
12860                    do {
12861                        current.$$listenerCount[name] -= count;
12862
12863                        if (current.$$listenerCount[name] === 0) {
12864                            delete current.$$listenerCount[name];
12865                        }
12866                    } while ((current = current.$parent));
12867                }
12868
12869                /**
12870                 * function used as an initial value for watchers.
12871                 * because it's unique we can easily tell it apart from other values
12872                 */
12873                function initWatchVal() {
12874                }
12875            }];
12876    }
12877
12878    /**
12879     * @description
12880     * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
12881     */
12882    function $$SanitizeUriProvider() {
12883        var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
12884            imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
12885
12886        /**
12887         * @description
12888         * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12889         * urls during a[href] sanitization.
12890         *
12891         * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12892         *
12893         * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
12894         * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
12895         * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12896         * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12897         *
12898         * @param {RegExp=} regexp New regexp to whitelist urls with.
12899         * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12900         *    chaining otherwise.
12901         */
12902        this.aHrefSanitizationWhitelist = function (regexp) {
12903            if (isDefined(regexp)) {
12904                aHrefSanitizationWhitelist = regexp;
12905                return this;
12906            }
12907            return aHrefSanitizationWhitelist;
12908        };
12909
12910
12911        /**
12912         * @description
12913         * Retrieves or overrides the default regular expression that is used for whitelisting of safe
12914         * urls during img[src] sanitization.
12915         *
12916         * The sanitization is a security measure aimed at prevent XSS attacks via html links.
12917         *
12918         * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
12919         * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
12920         * regular expression. If a match is found, the original url is written into the dom. Otherwise,
12921         * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
12922         *
12923         * @param {RegExp=} regexp New regexp to whitelist urls with.
12924         * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
12925         *    chaining otherwise.
12926         */
12927        this.imgSrcSanitizationWhitelist = function (regexp) {
12928            if (isDefined(regexp)) {
12929                imgSrcSanitizationWhitelist = regexp;
12930                return this;
12931            }
12932            return imgSrcSanitizationWhitelist;
12933        };
12934
12935        this.$get = function () {
12936            return function sanitizeUri(uri, isImage) {
12937                var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
12938                var normalizedVal;
12939                // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
12940                if (!msie || msie >= 8) {
12941                    normalizedVal = urlResolve(uri).href;
12942                    if (normalizedVal !== '' && !normalizedVal.match(regex)) {
12943                        return 'unsafe:' + normalizedVal;
12944                    }
12945                }
12946                return uri;
12947            };
12948        };
12949    }
12950
12951    var $sceMinErr = minErr('$sce');
12952
12953    var SCE_CONTEXTS = {
12954        HTML: 'html',
12955        CSS: 'css',
12956        URL: 'url',
12957        // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
12958        // url.  (e.g. ng-include, script src, templateUrl)
12959        RESOURCE_URL: 'resourceUrl',
12960        JS: 'js'
12961    };
12962
12963// Helper functions follow.
12964
12965// Copied from:
12966// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
12967// Prereq: s is a string.
12968    function escapeForRegexp(s) {
12969        return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
12970            replace(/\x08/g, '\\x08');
12971    }
12972
12973
12974    function adjustMatcher(matcher) {
12975        if (matcher === 'self') {
12976            return matcher;
12977        } else if (isString(matcher)) {
12978            // Strings match exactly except for 2 wildcards - '*' and '**'.
12979            // '*' matches any character except those from the set ':/.?&'.
12980            // '**' matches any character (like .* in a RegExp).
12981            // More than 2 *'s raises an error as it's ill defined.
12982            if (matcher.indexOf('***') > -1) {
12983                throw $sceMinErr('iwcard',
12984                    'Illegal sequence *** in string matcher.  String: {0}', matcher);
12985            }
12986            matcher = escapeForRegexp(matcher).
12987                replace('\\*\\*', '.*').
12988                replace('\\*', '[^:/.?&;]*');
12989            return new RegExp('^' + matcher + '$');
12990        } else if (isRegExp(matcher)) {
12991            // The only other type of matcher allowed is a Regexp.
12992            // Match entire URL / disallow partial matches.
12993            // Flags are reset (i.e. no global, ignoreCase or multiline)
12994            return new RegExp('^' + matcher.source + '$');
12995        } else {
12996            throw $sceMinErr('imatcher',
12997                'Matchers may only be "self", string patterns or RegExp objects');
12998        }
12999    }
13000
13001
13002    function adjustMatchers(matchers) {
13003        var adjustedMatchers = [];
13004        if (isDefined(matchers)) {
13005            forEach(matchers, function (matcher) {
13006                adjustedMatchers.push(adjustMatcher(matcher));
13007            });
13008        }
13009        return adjustedMatchers;
13010    }
13011
13012
13013    /**
13014     * @ngdoc service
13015     * @name $sceDelegate
13016     * @function
13017     *
13018     * @description
13019     *
13020     * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
13021 * Contextual Escaping (SCE)} services to AngularJS.
13022     *
13023     * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
13024     * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
13025     * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
13026     * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
13027     * work because `$sce` delegates to `$sceDelegate` for these operations.
13028     *
13029     * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
13030     *
13031     * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
13032     * can override it completely to change the behavior of `$sce`, the common case would
13033     * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
13034     * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
13035     * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
13036 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
13037        * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13038     */
13039
13040    /**
13041     * @ngdoc provider
13042     * @name $sceDelegateProvider
13043     * @description
13044     *
13045     * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
13046 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
13047     * that the URLs used for sourcing Angular templates are safe.  Refer {@link
13048        * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
13049     * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
13050     *
13051     * For the general details about this service in Angular, read the main page for {@link ng.$sce
13052 * Strict Contextual Escaping (SCE)}.
13053     *
13054     * **Example**:  Consider the following case. <a name="example"></a>
13055     *
13056     * - your app is hosted at url `http://myapp.example.com/`
13057     * - but some of your templates are hosted on other domains you control such as
13058     *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
13059     * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
13060     *
13061     * Here is what a secure configuration for this scenario might look like:
13062     *
13063     * <pre class="prettyprint">
13064     *    angular.module('myApp', []).config(function($sceDelegateProvider) {
13065 *      $sceDelegateProvider.resourceUrlWhitelist([
13066 *        // Allow same origin resource loads.
13067 *        'self',
13068 *        // Allow loading from our assets domain.  Notice the difference between * and **.
13069 *        'http://srv*.assets.example.com/**']);
13070 *
13071 *      // The blacklist overrides the whitelist so the open redirect here is blocked.
13072 *      $sceDelegateProvider.resourceUrlBlacklist([
13073 *        'http://myapp.example.com/clickThru**']);
13074 *      });
13075     * </pre>
13076     */
13077
13078    function $SceDelegateProvider() {
13079        this.SCE_CONTEXTS = SCE_CONTEXTS;
13080
13081        // Resource URLs can also be trusted by policy.
13082        var resourceUrlWhitelist = ['self'],
13083            resourceUrlBlacklist = [];
13084
13085        /**
13086         * @ngdoc method
13087         * @name $sceDelegateProvider#resourceUrlWhitelist
13088         * @function
13089         *
13090         * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
13091         *     provided.  This must be an array or null.  A snapshot of this array is used so further
13092         *     changes to the array are ignored.
13093         *
13094         *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13095         *     allowed in this array.
vendor: 5,113 bytes, lines 13096-13220
13096         *
13097         *     Note: **an empty whitelist array will block all URLs**!
13098         *
13099         * @return {Array} the currently set whitelist array.
13100         *
13101         * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
13102         * same origin resource requests.
13103         *
13104         * @description
13105         * Sets/Gets the whitelist of trusted resource URLs.
13106         */
13107        this.resourceUrlWhitelist = function (value) {
13108            if (arguments.length) {
13109                resourceUrlWhitelist = adjustMatchers(value);
13110            }
13111            return resourceUrlWhitelist;
13112        };
13113
13114        /**
13115         * @ngdoc method
13116         * @name $sceDelegateProvider#resourceUrlBlacklist
13117         * @function
13118         *
13119         * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
13120         *     provided.  This must be an array or null.  A snapshot of this array is used so further
13121         *     changes to the array are ignored.
13122         *
13123         *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
13124         *     allowed in this array.
13125         *
13126         *     The typical usage for the blacklist is to **block
13127         *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
13128         *     these would otherwise be trusted but actually return content from the redirected domain.
13129         *
13130         *     Finally, **the blacklist overrides the whitelist** and has the final say.
13131         *
13132         * @return {Array} the currently set blacklist array.
13133         *
13134         * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
13135         * is no blacklist.)
13136         *
13137         * @description
13138         * Sets/Gets the blacklist of trusted resource URLs.
13139         */
13140
13141        this.resourceUrlBlacklist = function (value) {
13142            if (arguments.length) {
13143                resourceUrlBlacklist = adjustMatchers(value);
13144            }
13145            return resourceUrlBlacklist;
13146        };
13147
13148        this.$get = ['$injector', function ($injector) {
13149
13150            var htmlSanitizer = function htmlSanitizer(html) {
13151                throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13152            };
13153
13154            if ($injector.has('$sanitize')) {
13155                htmlSanitizer = $injector.get('$sanitize');
13156            }
13157
13158
13159            function matchUrl(matcher, parsedUrl) {
13160                if (matcher === 'self') {
13161                    return urlIsSameOrigin(parsedUrl);
13162                } else {
13163                    // definitely a regex.  See adjustMatchers()
13164                    return !!matcher.exec(parsedUrl.href);
13165                }
13166            }
13167
13168            function isResourceUrlAllowedByPolicy(url) {
13169                var parsedUrl = urlResolve(url.toString());
13170                var i, n, allowed = false;
13171                // Ensure that at least one item from the whitelist allows this url.
13172                for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
13173                    if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
13174                        allowed = true;
13175                        break;
13176                    }
13177                }
13178                if (allowed) {
13179                    // Ensure that no item from the blacklist blocked this url.
13180                    for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
13181                        if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
13182                            allowed = false;
13183                            break;
13184                        }
13185                    }
13186                }
13187                return allowed;
13188            }
13189
13190            function generateHolderType(Base) {
13191                var holderType = function TrustedValueHolderType(trustedValue) {
13192                    this.$$unwrapTrustedValue = function () {
13193                        return trustedValue;
13194                    };
13195                };
13196                if (Base) {
13197                    holderType.prototype = new Base();
13198                }
13199                holderType.prototype.valueOf = function sceValueOf() {
13200                    return this.$$unwrapTrustedValue();
13201                };
13202                holderType.prototype.toString = function sceToString() {
13203                    return this.$$unwrapTrustedValue().toString();
13204                };
13205                return holderType;
13206            }
13207
13208            var trustedValueHolderBase = generateHolderType(),
13209                byType = {};
13210
13211            byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
13212            byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
13213            byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
13214            byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
13215            byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
13216
13217            /**
13218             * @ngdoc method
13219             * @name $sceDelegate#trustAs
13220             *
13221             * @description
13222             * Returns an object that is trusted by angular for use in specified strict
13223             * contextual escaping contexts (such as ng-bind-html, ng-include, any src
13224             * attribute interpolation, any dom event binding attribute interpolation
13225             * such as for onclick,  etc.) that uses the provided value.
13226             * See {@link ng.$sce $sce} for enabling strict contextual escaping.
13227             *
13228             * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13229             *   resourceUrl, html, js and css.
13230             * @param {*} value The value that that should be considered trusted/safe.
13231             * @returns {*} A value that can be used to stand in for the provided `value` in places
13232             * where Angular expects a $sce.trustAs() return value.
13233             */
13234            function trustAs(type, trustedValue) {
13235                var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13236                if (!Constructor) {
13237                    throw $sceMinErr('icontext',
13238                        'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
13239                        type, trustedValue);
13240                }
13241                if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
13242                    return trustedValue;
13243                }
13244                // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
13245                // mutable objects, we ensure here that the value passed in is actually a string.
13246                if (typeof trustedValue !== 'string') {
13247                    throw $sceMinErr('itype',
13248                        'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
13249                        type);
13250                }
13251                return new Constructor(trustedValue);
13252            }
13253
13254            /**
13255             * @ngdoc method
13256             * @name $sceDelegate#valueOf
13257             *
13258             * @description
13259             * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
13260     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
13261                * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
13262             *
13263             * If the passed parameter is not a value that had been returned by {@link
13264                * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
13265             *
13266             * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
13267             *      call or anything else.
13268             * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
13269     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
13270             *     `value` unchanged.
13271             */
13272            function valueOf(maybeTrusted) {
13273                if (maybeTrusted instanceof trustedValueHolderBase) {
13274                    return maybeTrusted.$$unwrapTrustedValue();
13275                } else {
13276                    return maybeTrusted;
13277                }
13278            }
13279
13280            /**
13281             * @ngdoc method
13282             * @name $sceDelegate#getTrusted
13283             *
13284             * @description
13285             * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
13286             * returns the originally supplied value if the queried context type is a supertype of the
13287             * created type.  If this condition isn't satisfied, throws an exception.
13288             *
13289             * @param {string} type The kind of context in which this value is to be used.
13290             * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
13291     *     `$sceDelegate.trustAs`} call.
13292             * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
13293     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
13294             */
13295            function getTrusted(type, maybeTrusted) {
13296                if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
13297                    return maybeTrusted;
13298                }
13299                var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
13300                if (constructor && maybeTrusted instanceof constructor) {
13301                    return maybeTrusted.$$unwrapTrustedValue();
13302                }
13303                // If we get here, then we may only take one of two actions.
13304                // 1. sanitize the value for the requested type, or
13305                // 2. throw an exception.
13306                if (type === SCE_CONTEXTS.RESOURCE_URL) {
13307                    if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
13308                        return maybeTrusted;
13309                    } else {
13310                        throw $sceMinErr('insecurl',
13311                            'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
13312                            maybeTrusted.toString());
13313                    }
13314                } else if (type === SCE_CONTEXTS.HTML) {
13315                    return htmlSanitizer(maybeTrusted);
13316                }
13317                throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
13318            }
13319
13320            return { trustAs: trustAs,
13321                getTrusted: getTrusted,
13322                valueOf: valueOf };
13323        }];
13324    }
13325
13326
13327    /**
13328     * @ngdoc provider
13329     * @name $sceProvider
13330     * @description
13331     *
13332     * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
13333     * -   enable/disable Strict Contextual Escaping (SCE) in a module
13334     * -   override the default implementation with a custom delegate
13335     *
13336     * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
13337     */
13338
13339    /* jshint maxlen: false*/
13340
13341    /**
13342     * @ngdoc service
13343     * @name $sce
13344     * @function
13345     *
13346     * @description
13347     *
13348     * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
13349     *
13350     * # Strict Contextual Escaping
13351     *
13352     * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
13353     * contexts to result in a value that is marked as safe to use for that context.  One example of
13354     * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
13355     * to these contexts as privileged or SCE contexts.
13356     *
13357     * As of version 1.2, Angular ships with SCE enabled by default.
13358     *
13359     * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
13360     * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
13361     * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
13362     * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
13363     * to the top of your HTML document.
13364     *
13365     * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
13366     * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
13367     *
13368     * Here's an example of a binding in a privileged context:
13369     *
13370     * <pre class="prettyprint">
13371     *     <input ng-model="userHtml">
13372     *     <div ng-bind-html="userHtml">
13373     * </pre>
13374     *
13375     * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
13376     * disabled, this application allows the user to render arbitrary HTML into the DIV.
13377     * In a more realistic example, one may be rendering user comments, blog articles, etc. via
13378     * bindings.  (HTML is just one example of a context where rendering user controlled input creates
13379     * security vulnerabilities.)
13380     *
13381     * For the case of HTML, you might use a library, either on the client side, or on the server side,
13382     * to sanitize unsafe HTML before binding to the value and rendering it in the document.
13383     *
13384     * How would you ensure that every place that used these types of bindings was bound to a value that
13385     * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
13386     * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
13387     * properties/fields and forgot to update the binding to the sanitized value?
13388     *
13389     * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
13390     * determine that something explicitly says it's safe to use a value for binding in that
13391     * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
13392     * for those values that you can easily tell are safe - because they were received from your server,
13393     * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
13394     * allowing only the files in a specific directory to do this.  Ensuring that the internal API
13395     * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
13396     *
13397     * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
13398     * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
13399     * obtain values that will be accepted by SCE / privileged contexts.
13400     *
13401     *
13402     * ## How does it work?
13403     *
13404     * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
13405 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
13406        * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
13407     * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
13408     *
13409     * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
13410        * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
13411     * simplified):
13412     *
13413     * <pre class="prettyprint">
13414     *   var ngBindHtmlDirective = ['$sce', function($sce) {
13415 *     return function(scope, element, attr) {
13416 *       scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
13417 *         element.html(value || '');
13418 *       });
13419 *     };
13420 *   }];
13421     * </pre>
13422     *
13423     * ## Impact on loading templates
13424     *
13425     * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
13426     * `templateUrl`'s specified by {@link guide/directive directives}.
13427     *
13428     * By default, Angular only loads templates from the same domain and protocol as the application
13429     * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
13430 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
13431     * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
13432 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
13433     *
13434     * *Please note*:
13435     * The browser's
13436     * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
13437     * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
13438     * policy apply in addition to this and may further restrict whether the template is successfully
13439     * loaded.  This means that without the right CORS policy, loading templates from a different domain
13440     * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
13441     * browsers.
13442     *
13443     * ## This feels like too much overhead for the developer?
13444     *
13445     * It's important to remember that SCE only applies to interpolation expressions.
13446     *
13447     * If your expressions are constant literals, they're automatically trusted and you don't need to
13448     * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
13449     * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
13450     *
13451     * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
13452     * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
13453     *
13454     * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
13455     * templates in `ng-include` from your application's domain without having to even know about SCE.
13456     * It blocks loading templates from other domains or loading templates over http from an https
13457     * served document.  You can change these by setting your own custom {@link
13458        * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
13459        * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
13460     *
13461     * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
13462     * application that's secure and can be audited to verify that with much more ease than bolting
13463     * security onto an application later.
13464     *
13465     * <a name="contexts"></a>
13466     * ## What trusted context types are supported?
13467     *
13468     * | Context             | Notes          |
13469     * |---------------------|----------------|
13470     * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
13471     * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
13472     * | `$sce.URL`          | For URLs that are safe to follow as links.  Currently unused (`<a href=` and `<img src=` sanitize their urls and don't constitute an SCE context. |
13473     * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
13474     * | `$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. |
13475     *
13476     * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
13477     *
13478     *  Each element in these arrays must be one of the following:
13479     *
13480     *  - **'self'**
13481     *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
13482     *      domain** as the application document using the **same protocol**.
13483     *  - **String** (except the special value `'self'`)
13484     *    - The string is matched against the full *normalized / absolute URL* of the resource
13485     *      being tested (substring matches are not good enough.)
13486     *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
13487     *      match themselves.
13488     *    - `*`: matches zero or more occurrences of any character other than one of the following 6
13489     *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
13490     *      in a whitelist.
13491     *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
13492     *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
13493     *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
13494     *      not have been the intention.)  It's usage at the very end of the path is ok.  (e.g.
13495     *      http://foo.example.com/templates/**).
13496     *  - **RegExp** (*see caveat below*)
13497     *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
13498     *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
13499     *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
13500     *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
13501     *      small number of cases.  A `.` character in the regex used when matching the scheme or a
13502     *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
13503     *      is highly recommended to use the string patterns and only fall back to regular expressions
13504     *      if they as a last resort.
13505     *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
13506     *      matched against the **entire** *normalized / absolute URL* of the resource being tested
13507     *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
13508     *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
13509     *    - If you are generating your JavaScript from some other templating engine (not
13510     *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
13511     *      remember to escape your regular expression (and be aware that you might need more than
13512     *      one level of escaping depending on your templating engine and the way you interpolated
13513     *      the value.)  Do make use of your platform's escaping mechanism as it might be good
13514     *      enough before coding your own.  e.g. Ruby has
13515     *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
13516     *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
13517     *      Javascript lacks a similar built in function for escaping.  Take a look at Google
13518     *      Closure library's [goog.string.regExpEscape(s)](
13519     *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
13520     *
13521     * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
13522     *
13523     * ## Show me an example using SCE.
13524     *
13525     * @example
13526     <example module="mySceApp" deps="angular-sanitize.js">
13527     <file name="index.jsp">
13528     <div ng-controller="myAppController as myCtrl">
13529     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
13530     <b>User comments</b><br>
13531     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
13532     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
13533     exploit.
13534     <div class="well">
13535     <div ng-repeat="userComment in myCtrl.userComments">
13536     <b>
13536{{userComment.name}}</b>:
13537     <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
13538     <br>
13539     </div>
13540     </div>
13541     </div>
13542     </file>
13543
13544     <file name="script.js">
13545     var mySceApp = angular.module('mySceApp', ['ngSanitize']);
13546
13547     mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
13548    var self = this;
13549    $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
13550      self.userComments = userComments;
13551    });
13552    self.explicitlyTrustedHtml = $sce.trustAsHtml(
13553        '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13554        'sanitization.&quot;">Hover over this text.</span>');
13555  });
13556     </file>
13557
13558     <file name="test_data.json">
13559     [
13560     { "name": "Alice",
13561    "htmlComment":
13562        "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
13563  },
13564     { "name": "Bob",
13565    "htmlComment": "<i>Yes!</i>  Am I the only other one?"
13566  }
13567     ]
13568     </file>
13569
13570     <file name="protractor.js" type="protractor">
13571     describe('SCE doc demo', function() {
13572    it('should sanitize untrusted values', function() {
13573      expect(element(by.css('.htmlComment')).getInnerHtml())
13574          .toBe('<span>Is <i>anyone</i> reading this?</span>');
13575    });
13576
13577    it('should NOT sanitize explicitly trusted values', function() {
13578      expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
13579          '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
13580          'sanitization.&quot;">Hover over this text.</span>');
13581    });
13582  });
13583     </file>
13584     </example>
13585     *
13586     *
13587     *
13588     * ## Can I disable SCE completely?
13589     *
13590     * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
13591     * for little coding overhead.  It will be much harder to take an SCE disabled application and
13592     * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
13593     * for cases where you have a lot of existing code that was written before SCE was introduced and
13594     * you're migrating them a module at a time.
13595     *
13596     * That said, here's how you can completely disable SCE:
13597     *
13598     * <pre class="prettyprint">
13599     *   angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
13600 *     // Completely disable SCE.  For demonstration purposes only!
13601 *     // Do not use in new projects.
13602 *     $sceProvider.enabled(false);
13603 *   });
13604     * </pre>
13605     *
13606     */
13607    /* jshint maxlen: 100 */
13608
13609    function $SceProvider() {
13610        var enabled = true;
13611
13612        /**
13613         * @ngdoc method
13614         * @name $sceProvider#enabled
13615         * @function
13616         *
13617         * @param {boolean=} value If provided, then enables/disables SCE.
13618         * @return {boolean} true if SCE is enabled, false otherwise.
13619         *
13620         * @description
13621         * Enables/disables SCE and returns the current value.
13622         */
13623        this.enabled = function (value) {
13624            if (arguments.length) {
13625                enabled = !!value;
13626            }
13627            return enabled;
13628        };
13629
13630
13631        /* Design notes on the default implementation for SCE.
13632         *
13633         * The API contract for the SCE delegate
13634         * -------------------------------------
13635         * The SCE delegate object must provide the following 3 methods:
13636         *
13637         * - trustAs(contextEnum, value)
13638         *     This method is used to tell the SCE service that the provided value is OK to use in the
13639         *     contexts specified by contextEnum.  It must return an object that will be accepted by
13640         *     getTrusted() for a compatible contextEnum and return this value.
13641         *
13642         * - valueOf(value)
13643         *     For values that were not produced by trustAs(), return them as is.  For values that were
13644         *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
13645         *     trustAs is wrapping the given values into some type, this operation unwraps it when given
13646         *     such a value.
13647         *
13648         * - getTrusted(contextEnum, value)
13649         *     This function should return the a value that is safe to use in the context specified by
13650         *     contextEnum or throw and exception otherwise.
13651         *
13652         * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
13653         * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
13654         * instance, an implementation could maintain a registry of all trusted objects by context.  In
13655         * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
13656         * return the same object passed in if it was found in the registry under a compatible context or
13657         * throw an exception otherwise.  An implementation might only wrap values some of the time based
13658         * on some criteria.  getTrusted() might return a value and not throw an exception for special
13659         * constants or objects even if not wrapped.  All such implementations fulfill this contract.
13660         *
13661         *
13662         * A note on the inheritance model for SCE contexts
13663         * ------------------------------------------------
13664         * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
13665         * is purely an implementation details.
13666         *
13667         * The contract is simply this:
13668         *
13669         *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
13670         *     will also succeed.
13671         *
13672         * Inheritance happens to capture this in a natural way.  In some future, we
13673         * may not use inheritance anymore.  That is OK because no code outside of
13674         * sce.js and sceSpecs.js would need to be aware of this detail.
13675         */
13676
13677        this.$get = ['$parse', '$sniffer', '$sceDelegate', function ($parse, $sniffer, $sceDelegate) {
13678            // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
13679            // the "expression(javascript expression)" syntax which is insecure.
13680            if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
13681                throw $sceMinErr('iequirks',
13682                    'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
13683                        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
13684                        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
13685            }
13686
13687            var sce = copy(SCE_CONTEXTS);
13688
13689            /**
13690             * @ngdoc method
13691             * @name $sce#isEnabled
13692             * @function
13693             *
13694             * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
13695             * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
13696             *
13697             * @description
13698             * Returns a boolean indicating if SCE is enabled.
13699             */
13700            sce.isEnabled = function () {
13701                return enabled;
13702            };
13703            sce.trustAs = $sceDelegate.trustAs;
13704            sce.getTrusted = $sceDelegate.getTrusted;
13705            sce.valueOf = $sceDelegate.valueOf;
13706
13707            if (!enabled) {
13708                sce.trustAs = sce.getTrusted = function (type, value) {
13709                    return value;
13710                };
13711                sce.valueOf = identity;
13712            }
13713
13714            /**
13715             * @ngdoc method
13716             * @name $sce#parse
13717             *
13718             * @description
13719             * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
13720                * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
13721             * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
13722     * *result*)}
13723             *
13724             * @param {string} type The kind of SCE context in which this result will be used.
13725             * @param {string} expression String expression to compile.
13726             * @returns {function(context, locals)} a function which represents the compiled expression:
13727             *
13728             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13729             *      are evaluated against (typically a scope object).
13730             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13731             *      `context`.
13732             */
13733            sce.parseAs = function sceParseAs(type, expr) {
13734                var parsed = $parse(expr);
13735                if (parsed.literal && parsed.constant) {
13736                    return parsed;
13737                } else {
13738                    return function sceParseAsTrusted(self, locals) {
13739                        return sce.getTrusted(type, parsed(self, locals));
13740                    };
13741                }
13742            };
13743
13744            /**
13745             * @ngdoc method
13746             * @name $sce#trustAs
13747             *
13748             * @description
13749             * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
13750             * returns an object that is trusted by angular for use in specified strict contextual
13751             * escaping contexts (such as ng-bind-html, ng-include, any src attribute
13752             * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
13753             * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
13754             * escaping.
13755             *
13756             * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
13757             *   resource_url, html, js and css.
13758             * @param {*} value The value that that should be considered trusted/safe.
13759             * @returns {*} A value that can be used to stand in for the provided `value` in places
13760             * where Angular expects a $sce.trustAs() return value.
13761             */
13762
13763            /**
13764             * @ngdoc method
13765             * @name $sce#trustAsHtml
13766             *
13767             * @description
13768             * Shorthand method.  `$sce.trustAsHtml(value)` →
13769             *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
13770             *
13771             * @param {*} value The value to trustAs.
13772             * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
13773     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
13774             *     only accept expressions that are either literal constants or are the
13775             *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13776             */
13777
13778            /**
13779             * @ngdoc method
13780             * @name $sce#trustAsUrl
13781             *
13782             * @description
13783             * Shorthand method.  `$sce.trustAsUrl(value)` →
13784             *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
13785             *
13786             * @param {*} value The value to trustAs.
13787             * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
13788     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
13789             *     only accept expressions that are either literal constants or are the
13790             *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13791             */
13792
13793            /**
13794             * @ngdoc method
13795             * @name $sce#trustAsResourceUrl
13796             *
13797             * @description
13798             * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
13799             *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
13800             *
13801             * @param {*} value The value to trustAs.
13802             * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
13803     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
13804             *     only accept expressions that are either literal constants or are the return
13805             *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
13806             */
13807
13808            /**
13809             * @ngdoc method
13810             * @name $sce#trustAsJs
13811             *
13812             * @description
13813             * Shorthand method.  `$sce.trustAsJs(value)` →
13814             *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
13815             *
13816             * @param {*} value The value to trustAs.
13817             * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
13818     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
13819             *     only accept expressions that are either literal constants or are the
13820             *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
13821             */
13822
13823            /**
13824             * @ngdoc method
13825             * @name $sce#getTrusted
13826             *
13827             * @description
13828             * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
13829             * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
13830             * originally supplied value if the queried context type is a supertype of the created type.
13831             * If this condition isn't satisfied, throws an exception.
13832             *
13833             * @param {string} type The kind of context in which this value is to be used.
13834             * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
13835             *                         call.
13836             * @returns {*} The value the was originally provided to
13837             *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
13838             *              Otherwise, throws an exception.
13839             */
13840
13841            /**
13842             * @ngdoc method
13843             * @name $sce#getTrustedHtml
13844             *
13845             * @description
13846             * Shorthand method.  `$sce.getTrustedHtml(value)` →
13847             *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
13848             *
13849             * @param {*} value The value to pass to `$sce.getTrusted`.
13850             * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
13851             */
13852
13853            /**
13854             * @ngdoc method
13855             * @name $sce#getTrustedCss
13856             *
13857             * @description
13858             * Shorthand method.  `$sce.getTrustedCss(value)` →
13859             *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
13860             *
13861             * @param {*} value The value to pass to `$sce.getTrusted`.
13862             * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
13863             */
13864
13865            /**
13866             * @ngdoc method
13867             * @name $sce#getTrustedUrl
13868             *
13869             * @description
13870             * Shorthand method.  `$sce.getTrustedUrl(value)` →
13871             *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
13872             *
13873             * @param {*} value The value to pass to `$sce.getTrusted`.
13874             * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
13875             */
13876
13877            /**
13878             * @ngdoc method
13879             * @name $sce#getTrustedResourceUrl
13880             *
13881             * @description
13882             * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
13883             *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
13884             *
13885             * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
13886             * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
13887             */
13888
13889            /**
13890             * @ngdoc method
13891             * @name $sce#getTrustedJs
13892             *
13893             * @description
13894             * Shorthand method.  `$sce.getTrustedJs(value)` →
13895             *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
13896             *
13897             * @param {*} value The value to pass to `$sce.getTrusted`.
13898             * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
13899             */
13900
13901            /**
13902             * @ngdoc method
13903             * @name $sce#parseAsHtml
13904             *
13905             * @description
13906             * Shorthand method.  `$sce.parseAsHtml(expression string)` →
13907             *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
13908             *
13909             * @param {string} expression String expression to compile.
13910             * @returns {function(context, locals)} a function which represents the compiled expression:
13911             *
13912             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13913             *      are evaluated against (typically a scope object).
13914             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13915             *      `context`.
13916             */
13917
13918            /**
13919             * @ngdoc method
13920             * @name $sce#parseAsCss
13921             *
13922             * @description
13923             * Shorthand method.  `$sce.parseAsCss(value)` →
13924             *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
13925             *
13926             * @param {string} expression String expression to compile.
13927             * @returns {function(context, locals)} a function which represents the compiled expression:
13928             *
13929             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13930             *      are evaluated against (typically a scope object).
13931             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13932             *      `context`.
13933             */
13934
13935            /**
13936             * @ngdoc method
13937             * @name $sce#parseAsUrl
13938             *
13939             * @description
13940             * Shorthand method.  `$sce.parseAsUrl(value)` →
13941             *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
13942             *
13943             * @param {string} expression String expression to compile.
13944             * @returns {function(context, locals)} a function which represents the compiled expression:
13945             *
13946             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13947             *      are evaluated against (typically a scope object).
13948             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13949             *      `context`.
13950             */
13951
13952            /**
13953             * @ngdoc method
13954             * @name $sce#parseAsResourceUrl
13955             *
13956             * @description
13957             * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
13958             *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
13959             *
13960             * @param {string} expression String expression to compile.
13961             * @returns {function(context, locals)} a function which represents the compiled expression:
13962             *
13963             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13964             *      are evaluated against (typically a scope object).
13965             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13966             *      `context`.
13967             */
13968
13969            /**
13970             * @ngdoc method
13971             * @name $sce#parseAsJs
13972             *
13973             * @description
13974             * Shorthand method.  `$sce.parseAsJs(value)` →
13975             *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
13976             *
13977             * @param {string} expression String expression to compile.
13978             * @returns {function(context, locals)} a function which represents the compiled expression:
13979             *
13980             *    * `context` – `{object}` – an object against which any expressions embedded in the strings
13981             *      are evaluated against (typically a scope object).
13982             *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
13983             *      `context`.
13984             */
13985
13986            // Shorthand delegations.
13987            var parse = sce.parseAs,
13988                getTrusted = sce.getTrusted,
13989                trustAs = sce.trustAs;
13990
13991            forEach(SCE_CONTEXTS, function (enumValue, name) {
13992                var lName = lowercase(name);
13993                sce[camelCase("parse_as_" + lName)] = function (expr) {
13994                    return parse(enumValue, expr);
13995                };
13996                sce[camelCase("get_trusted_" + lName)] = function (value) {
13997                    return getTrusted(enumValue, value);
13998                };
13999                sce[camelCase("trust_as_" + lName)] = function (value) {
14000                    return trustAs(enumValue, value);
14001                };
14002            });
14003
14004            return sce;
14005        }];
14006    }
14007
14008    /**
14009     * !!! This is an undocumented "private" service !!!
14010     *
14011     * @name $sniffer
14012     * @requires $window
14013     * @requires $document
14014     *
14015     * @property {boolean} history Does the browser support html5 history api ?
14016     * @property {boolean} hashchange Does the browser support hashchange event ?
14017     * @property {boolean} transitions Does the browser support CSS transition events ?
14018     * @property {boolean} animations Does the browser support CSS animation events ?
14019     *
14020     * @description
14021     * This is very simple implementation of testing browser's features.
14022     */
14023    function $SnifferProvider() {
14024        this.$get = ['$window', '$document', function ($window, $document) {
14025            var eventSupport = {},
14026                android =
14027                    int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
14028                boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
14029                document = $document[0] || {},
14030                documentMode = document.documentMode,
14031                vendorPrefix,
14032                vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
14033                bodyStyle = document.body && document.body.style,
14034                transitions = false,
14035                animations = false,
14036                match;
14037
14038            if (bodyStyle) {
14039                for (var prop in bodyStyle) {
14040                    if (match = vendorRegex.exec(prop)) {
14041                        vendorPrefix = match[0];
14042                        vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
14043                        break;
14044                    }
14045                }
14046
14047                if (!vendorPrefix) {
14048                    vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
14049                }
14050
14051                transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
14052                animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
14053
14054                if (android && (!transitions || !animations)) {
14055                    transitions = isString(document.body.style.webkitTransition);
14056                    animations = isString(document.body.style.webkitAnimation);
14057                }
14058            }
14059
14060
14061            return {
14062                // Android has history.pushState, but it does not update location correctly
14063                // so let's not use the history API at all.
14064                // http://code.google.com/p/android/issues/detail?id=17471
14065                // https://github.com/angular/angular.js/issues/904
14066
14067                // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
14068                // so let's not use the history API also
14069                // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
14070                // jshint -W018
14071                history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
14072                // jshint +W018
14073                hashchange: 'onhashchange' in $window &&
14074                    // IE8 compatible mode lies
14075                    (!documentMode || documentMode > 7),
14076                hasEvent: function (event) {
14077                    // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
14078                    // it. In particular the event is not fired when backspace or delete key are pressed or
14079                    // when cut operation is performed.
14080                    if (event == 'input' && msie == 9) return false;
14081
14082                    if (isUndefined(eventSupport[event])) {
14083                        var divElm = document.createElement('div');
14084                        eventSupport[event] = 'on' + event in divElm;
14085                    }
14086
14087                    return eventSupport[event];
14088                },
14089                csp: csp(),
14090                vendorPrefix: vendorPrefix,
14091                transitions: transitions,
14092                animations: animations,
14093                android: android,
14094                msie: msie,
14095                msieDocumentMode: documentMode
14096            };
14097        }];
14098    }
14099
14100    function $TimeoutProvider() {
14101        this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14102            function ($rootScope, $browser, $q, $exceptionHandler) {
14103                var deferreds = {};
14104
14105
14106                /**
14107                 * @ngdoc service
14108                 * @name $timeout
14109                 *
14110                 * @description
14111                 * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
14112                 * block and delegates any exceptions to
14113                 * {@link ng.$exceptionHandler $exceptionHandler} service.
14114                 *
14115                 * The return value of registering a timeout function is a promise, which will be resolved when
14116                 * the timeout is reached and the timeout function is executed.
14117                 *
14118                 * To cancel a timeout request, call `$timeout.cancel(promise)`.
14119                 *
14120                 * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
14121                 * synchronously flush the queue of deferred functions.
14122                 *
14123                 * @param {function()} fn A function, whose execution should be delayed.
14124                 * @param {number=} [delay=0] Delay in milliseconds.
14125                 * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
14126                 *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
14127                 * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
14128                 *   promise will be resolved with is the return value of the `fn` function.
14129                 *
14130                 */
14131                function timeout(fn, delay, invokeApply) {
14132                    var deferred = $q.defer(),
14133                        promise = deferred.promise,
14134                        skipApply = (isDefined(invokeApply) && !invokeApply),
14135                        timeoutId;
14136
14137                    timeoutId = $browser.defer(function () {
14138                        try {
14139                            deferred.resolve(fn());
14140                        } catch (e) {
14141                            deferred.reject(e);
14142                            $exceptionHandler(e);
14143                        }
14144                        finally {
14145                            delete deferreds[promise.$$timeoutId];
14146                        }
14147
14148                        if (!skipApply) $rootScope.$apply();
14149                    }, delay);
14150
14151                    promise.$$timeoutId = timeoutId;
14152                    deferreds[timeoutId] = deferred;
14153
14154                    return promise;
14155                }
14156
14157
14158                /**
14159                 * @ngdoc method
14160                 * @name $timeout#cancel
14161                 *
14162                 * @description
14163                 * Cancels a task associated with the `promise`. As a result of this, the promise will be
14164                 * resolved with a rejection.
14165                 *
14166                 * @param {Promise=} promise Promise returned by the `$timeout` function.
14167                 * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
14168                 *   canceled.
14169                 */
14170                timeout.cancel = function (promise) {
14171                    if (promise && promise.$$timeoutId in deferreds) {
14172                        deferreds[promise.$$timeoutId].reject('canceled');
14173                        delete deferreds[promise.$$timeoutId];
14174                        return $browser.defer.cancel(promise.$$timeoutId);
14175                    }
14176                    return false;
vendor: 5,620 bytes, lines 14177-14289
14177                };
14178
14179                return timeout;
14180            }];
14181    }
14182
14183// NOTE:  The usage of window and document instead of $window and $document here is
14184// deliberate.  This service depends on the specific behavior of anchor nodes created by the
14185// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
14186// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
14187// doesn't know about mocked locations and resolves URLs to the real document - which is
14188// exactly the behavior needed here.  There is little value is mocking these out for this
14189// service.
14190    var urlParsingNode = document.createElement("a");
14191    var originUrl = urlResolve(window.location.href, true);
14192
14193
14194    /**
14195     *
14196     * Implementation Notes for non-IE browsers
14197     * ----------------------------------------
14198     * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
14199     * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
14200     * URL will be resolved into an absolute URL in the context of the application document.
14201     * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
14202     * properties are all populated to reflect the normalized URL.  This approach has wide
14203     * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
14204     * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14205     *
14206     * Implementation Notes for IE
14207     * ---------------------------
14208     * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
14209     * browsers.  However, the parsed components will not be set if the URL assigned did not specify
14210     * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
14211     * work around that by performing the parsing in a 2nd step by taking a previously normalized
14212     * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
14213     * properties such as protocol, hostname, port, etc.
14214     *
14215     * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
14216     * uses the inner HTML approach to assign the URL as part of an HTML snippet -
14217     * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
14218     * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
14219     * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
14220     * method and IE < 8 is unsupported.
14221     *
14222     * References:
14223     *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
14224     *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
14225     *   http://url.spec.whatwg.org/#urlutils
14226     *   https://github.com/angular/angular.js/pull/2902
14227     *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
14228     *
14229     * @function
14230     * @param {string} url The URL to be parsed.
14231     * @description Normalizes and parses a URL.
14232     * @returns {object} Returns the normalized URL as a dictionary.
14233     *
14234     *   | member name   | Description    |
14235     *   |---------------|----------------|
14236     *   | href          | A normalized version of the provided URL if it was not an absolute URL |
14237     *   | protocol      | The protocol including the trailing colon                              |
14238     *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
14239     *   | search        | The search params, minus the question mark                             |
14240     *   | hash          | The hash string, minus the hash symbol
14241     *   | hostname      | The hostname
14242     *   | port          | The port, without ":"
14243     *   | pathname      | The pathname, beginning with "/"
14244     *
14245     */
14246    function urlResolve(url, base) {
14247        var href = url;
14248
14249        if (msie) {
14250            // Normalize before parse.  Refer Implementation Notes on why this is
14251            // done in two steps on IE.
14252            urlParsingNode.setAttribute("href", href);
14253            href = urlParsingNode.href;
14254        }
14255
14256        urlParsingNode.setAttribute('href', href);
14257
14258        // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
14259        return {
14260            href: urlParsingNode.href,
14261            protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
14262            host: urlParsingNode.host,
14263            search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
14264            hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
14265            hostname: urlParsingNode.hostname,
14266            port: urlParsingNode.port,
14267            pathname: (urlParsingNode.pathname.charAt(0) === '/')
14268                ? urlParsingNode.pathname
14269                : '/' + urlParsingNode.pathname
14270        };
14271    }
14272
14273    /**
14274     * Parse a request URL and determine whether this is a same-origin request as the application document.
14275     *
14276     * @param {string|object} requestUrl The url of the request as a string that will be resolved
14277     * or a parsed URL object.
14278     * @returns {boolean} Whether the request is for the same origin as the application document.
14279     */
14280    function urlIsSameOrigin(requestUrl) {
14281        var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
14282        return (parsed.protocol === originUrl.protocol &&
14283            parsed.host === originUrl.host);
14284    }
14285
14286    /**
14287     * @ngdoc service
14288     * @name $window
14289     *
14290     * @description
14291     * A reference to the browser's `window` object. While `window`
14292     * is globally available in JavaScript, it causes testability problems, because
14293     * it is a global variable. In angular we always refer to it through the
14294     * `$window` service, so it may be overridden, removed or mocked for testing.
14295     *
14296     * Expressions, like the one defined for the `ngClick` directive in the example
14297     * below, are evaluated with respect to the current scope.  Therefore, there is
14298     * no risk of inadvertently coding in a dependency on a global value in such an
14299     * expression.
14300     *
14301     * @example
14302     <example>
14303     <file name="index.jsp">
14304     <script>
14305     function Ctrl($scope, $window) {
14306           $scope.greeting = 'Hello, World!';
14307           $scope.doGreeting = function(greeting) {
14308               $window.alert(greeting);
14309           };
14310         }
14311     </script>
14312     <div ng-controller="Ctrl">
14313     <input type="text" ng-model="greeting" />
14314     <button ng-click="doGreeting(greeting)">ALERT</button>
14315     </div>
14316     </file>
14317     <file name="protractor.js" type="protractor">
14318     it('should display the greeting in the input box', function() {
14319       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
14320       // If we click the button it will block the test runner
14321       // element(':button').click();
14322      });
14323     </file>
14324     </example>
14325     */
14326    function $WindowProvider() {
14327        this.$get = valueFn(window);
14328    }
14329
14330    /**
14331     * @ngdoc provider
14332     * @name $filterProvider
14333     * @description
14334     *
14335     * Filters are just functions which transform input to an output. However filters need to be
14336     * Dependency Injected. To achieve this a filter definition consists of a factory function which is
14337     * annotated with dependencies and is responsible for creating a filter function.
14338     *
14339     * ```js
14340     *   // Filter registration
14341     *   function MyModule($provide, $filterProvider) {
14342 *     // create a service to demonstrate injection (not always needed)
14343 *     $provide.value('greet', function(name){
14344 *       return 'Hello ' + name + '!';
14345 *     });
14346 *
14347 *     // register a filter factory which uses the
14348 *     // greet service to demonstrate DI.
14349 *     $filterProvider.register('greet', function(greet){
14350 *       // return the filter function which uses the greet service
14351 *       // to generate salutation
14352 *       return function(text) {
14353 *         // filters need to be forgiving so check input validity
14354 *         return text && greet(text) || text;
14355 *       };
14356 *     });
14357 *   }
14358     * ```
14359     *
14360     * The filter function is registered with the `$injector` under the filter name suffix with
14361     * `Filter`.
14362     *
14363     * ```js
14364     *   it('should be the same instance', inject(
14365     *     function($filterProvider) {
14366 *       $filterProvider.register('reverse', function(){
14367 *         return ...;
14368 *       });
14369 *     },
14370     *     function($filter, reverseFilter) {
14371 *       expect($filter('reverse')).toBe(reverseFilter);
14372 *     });
14373     * ```
14374     *
14375     *
14376     * For more information about how angular filters work, and how to create your own filters, see
14377     * {@link guide/filter Filters} in the Angular Developer Guide.
14378     */
14379    /**
14380     * @ngdoc method
14381     * @name $filterProvider#register
14382     * @description
14383     * Register filter factory function.
14384     *
14385     * @param {String} name Name of the filter.
14386     * @param {Function} fn The filter factory function which is injectable.
14387     */
14388
14389
14390    /**
14391     * @ngdoc service
14392     * @name $filter
14393     * @function
14394     * @description
14395     * Filters are used for formatting data displayed to the user.
14396     *
14397     * The general syntax in templates is as follows:
14398     *
14399     *         {{ expression [| filter_name[:parameter_value] ... ] }}
14400     *
14401     * @param {String} name Name of the filter function to retrieve
14402     * @return {Function} the filter function
14403     */
14404    $FilterProvider.$inject = ['$provide'];
14405    function $FilterProvider($provide) {
14406        var suffix = 'Filter';
14407
14408        /**
14409         * @ngdoc method
14410         * @name $controllerProvider#register
14411         * @param {string|Object} name Name of the filter function, or an object map of filters where
14412         *    the keys are the filter names and the values are the filter factories.
14413         * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
14414         *    of the registered filter instances.
14415         */
14416        function register(name, factory) {
14417            if (isObject(name)) {
14418                var filters = {};
14419                forEach(name, function (filter, key) {
14420                    filters[key] = register(key, filter);
14421                });
14422                return filters;
14423            } else {
14424                return $provide.factory(name + suffix, factory);
14425            }
14426        }
14427
14428        this.register = register;
14429
14430        this.$get = ['$injector', function ($injector) {
14431            return function (name) {
14432                return $injector.get(name + suffix);
14433            };
14434        }];
14435
14436        ////////////////////////////////////////
14437
14438        /* global
14439         currencyFilter: false,
14440         dateFilter: false,
14441         filterFilter: false,
14442         jsonFilter: false,
14443         limitToFilter: false,
14444         lowercaseFilter: false,
14445         numberFilter: false,
14446         orderByFilter: false,
14447         uppercaseFilter: false,
14448         */
14449
14450        register('currency', currencyFilter);
14451        register('date', dateFilter);
14452        register('filter', filterFilter);
14453        register('json', jsonFilter);
14454        register('limitTo', limitToFilter);
14455        register('lowercase', lowercaseFilter);
14456        register('number', numberFilter);
14457        register('orderBy', orderByFilter);
14458        register('uppercase', uppercaseFilter);
14459    }
14460
14461    /**
14462     * @ngdoc filter
14463     * @name filter
14464     * @function
14465     *
14466     * @description
14467     * Selects a subset of items from `array` and returns it as a new array.
14468     *
14469     * @param {Array} array The source array.
14470     * @param {string|Object|function()} expression The predicate to be used for selecting items from
14471     *   `array`.
14472     *
14473     *   Can be one of:
14474     *
14475     *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
14476     *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
14477     *     will be returned. The predicate can be negated by prefixing the string with `!`.
14478     *
14479     *   - `Object`: A pattern object can be used to filter specific properties on objects contained
14480     *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
14481     *     which have property `name` containing "M" and property `phone` containing "1". A special
14482     *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14483     *     property of the object. That's equivalent to the simple substring match with a `string`
14484     *     as described above.
14485     *
14486     *   - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14487     *     called for each element of `array`. The final result is an array of those elements that
14488     *     the predicate returned true for.
14489     *
14490     * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
14491     *     determining if the expected value (from the filter expression) and actual value (from
14492     *     the object in the array) should be considered a match.
14493     *
14494     *   Can be one of:
14495     *
14496     *     - `function(actual, expected)`:
14497     *       The function will be given the object value and the predicate value to compare and
14498     *       should return true if the item should be included in filtered result.
14499     *
14500     *     - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
14501     *       this is essentially strict comparison of expected and actual.
14502     *
14503     *     - `false|undefined`: A short hand for a function which will look for a substring match in case
14504     *       insensitive way.
14505     *
14506     * @example
14507     <example>
14508     <file name="index.jsp">
14509     <div ng-init="friends = [{name:'John', phone:'555-1276'},
14510     {name:'Mary', phone:'800-BIG-MARY'},
14511     {name:'Mike', phone:'555-4321'},
14512     {name:'Adam', phone:'555-5678'},
14513     {name:'Julie', phone:'555-8765'},
14514     {name:'Juliette', phone:'555-5678'}]"></div>
14515
14516     Search: <input ng-model="searchText">
14517     <table id="searchTextResults">
14518     <tr><th>Name</th><th>Phone</th></tr>
14519     <tr ng-repeat="friend in friends | filter:searchText">
14520     <td>{{friend.name}}</td>
14521     <td>{{friend.phone}}</td>
14522     </tr>
14523     </table>
14524     <hr>
14525     Any: <input ng-model="search.$"> <br>
14526     Name only <input ng-model="search.name"><br>
14527     Phone only <input ng-model="search.phone"><br>
14528     Equality <input type="checkbox" ng-model="strict"><br>
14529     <table id="searchObjResults">
14530     <tr><th>
14530Name</th><th>Phone</th></tr>
14531     <tr ng-repeat="friendObj in friends | filter:search:strict">
14532     <td>{{friendObj.name}}</td>
14533     <td>{{friendObj.phone}}</td>
14534     </tr>
14535     </table>
14536     </file>
14537     <file name="protractor.js" type="protractor">
14538     var expectFriendNames = function(expectedNames, key) {
14539         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
14540           arr.forEach(function(wd, i) {
14541             expect(wd.getText()).toMatch(expectedNames[i]);
14542           });
14543         });
14544       };
14545
14546     it('should search across all fields when filtering with a string', function() {
14547         var searchText = element(by.model('searchText'));
14548         searchText.clear();
14549         searchText.sendKeys('m');
14550         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
14551
14552         searchText.clear();
14553         searchText.sendKeys('76');
14554         expectFriendNames(['John', 'Julie'], 'friend');
14555       });
14556
14557     it('should search in specific fields when filtering with a predicate object', function() {
14558         var searchAny = element(by.model('search.$'));
14559         searchAny.clear();
14560         searchAny.sendKeys('i');
14561         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
14562       });
14563     it('should use a equal comparison when comparator is true', function() {
14564         var searchName = element(by.model('search.name'));
14565         var strict = element(by.model('strict'));
14566         searchName.clear();
14567         searchName.sendKeys('Julie');
14568         strict.click();
14569         expectFriendNames(['Julie'], 'friendObj');
14570       });
14571     </file>
14572     </example>
14573     */
14574    function filterFilter() {
14575        return function (array, expression, comparator) {
14576            if (!isArray(array)) return array;
14577
14578            var comparatorType = typeof(comparator),
14579                predicates = [];
14580
14581            predicates.check = function (value) {
14582                for (var j = 0; j < predicates.length; j++) {
14583                    if (!predicates[j](value)) {
14584                        return false;
14585                    }
14586                }
14587                return true;
14588            };
14589
14590            if (comparatorType !== 'function') {
14591                if (comparatorType === 'boolean' && comparator) {
14592                    comparator = function (obj, text) {
14593                        return angular.equals(obj, text);
14594                    };
14595                } else {
14596                    comparator = function (obj, text) {
14597                        if (obj && text && typeof obj === 'object' && typeof text === 'object') {
14598                            for (var objKey in obj) {
14599                                if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
14600                                    comparator(obj[objKey], text[objKey])) {
14601                                    return true;
14602                                }
14603                            }
14604                            return false;
14605                        }
14606                        text = ('' + text).toLowerCase();
14607                        return ('' + obj).toLowerCase().indexOf(text) > -1;
14608                    };
14609                }
14610            }
14611
14612            var search = function (obj, text) {
14613                if (typeof text == 'string' && text.charAt(0) === '!') {
14614                    return !search(obj, text.substr(1));
14615                }
14616                switch (typeof obj) {
14617                    case "boolean":
14618                    case "number":
14619                    case "string":
14620                        return comparator(obj, text);
14621                    case "object":
14622                        switch (typeof text) {
14623                            case "object":
14624                                return comparator(obj, text);
14625                            default:
14626                                for (var objKey in obj) {
14627                                    if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
14628                                        return true;
14629                                    }
14630                                }
14631                                break;
14632                        }
14633                        return false;
14634                    case "array":
14635                        for (var i = 0; i < obj.length; i++) {
14636                            if (search(obj[i], text)) {
14637                                return true;
14638                            }
14639                        }
14640                        return false;
14641                    default:
14642                        return false;
14643                }
14644            };
14645            switch (typeof expression) {
14646                case "boolean":
14647                case "number":
14648                case "string":
14649                    // Set up expression object and fall through
14650                    expression = {$: expression};
14651                // jshint -W086
14652                case "object":
14653                    // jshint +W086
14654                    for (var key in expression) {
14655                        (function (path) {
14656                            if (typeof expression[path] == 'undefined') return;
14657                            predicates.push(function (value) {
14658                                return search(path == '$' ? value : (value && value[path]), expression[path]);
14659                            });
14660                        })(key);
14661                    }
14662                    break;
14663                case 'function':
14664                    predicates.push(expression);
14665                    break;
14666                default:
14667                    return array;
14668            }
14669            var filtered = [];
14670            for (var j = 0; j < array.length; j++) {
14671                var value = array[j];
14672                if (predicates.check(value)) {
14673                    filtered.push(value);
14674                }
14675            }
14676            return filtered;
14677        };
14678    }
14679
14680    /**
14681     * @ngdoc filter
14682     * @name currency
14683     * @function
14684     *
14685     * @description
14686     * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
14687     * symbol for current locale is used.
14688     *
14689     * @param {number} amount Input to filter.
14690     * @param {string=} symbol Currency symbol or identifier to be displayed.
14691     * @returns {string} Formatted number.
14692     *
14693     *
14694     * @example
14695     <example>
14696     <file name="index.jsp">
14697     <script>
14698     function Ctrl($scope) {
14699           $scope.amount = 1234.56;
14700         }
14701     </script>
14702     <div ng-controller="Ctrl">
14703     <input type="number" ng-model="amount"> <br>
14704     default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
14705     custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
14706     </div>
14707     </file>
14708     <file name="protractor.js" type="protractor">
14709     it('should init with 1234.56', function() {
14710         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
14711         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
14712       });
14713     it('should update', function() {
14714         if (browser.params.browser == 'safari') {
14715           // Safari does not understand the minus key. See
14716           // https://github.com/angular/protractor/issues/481
14717           return;
14718         }
14719         element(by.model('amount')).clear();
14720         element(by.model('amount')).sendKeys('-1234');
14721         expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
14722         expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
14723       });
14724     </file>
14725     </example>
14726     */
14727    currencyFilter.$inject = ['$locale'];
14728    function currencyFilter($locale) {
14729        var formats = $locale.NUMBER_FORMATS;
14730        return function (amount, currencySymbol) {
14731            if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
14732            return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
14733                replace(/\u00A4/g, currencySymbol);
14734        };
14735    }
14736
14737    /**
14738     * @ngdoc filter
14739     * @name number
14740     * @function
14741     *
14742     * @description
14743     * Formats a number as text.
14744     *
14745     * If the input is not a number an empty string is returned.
14746     *
14747     * @param {number|string} number Number to format.
14748     * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
14749     * If this is not provided then the fraction size is computed from the current locale's number
14750     * formatting pattern. In the case of the default locale, it will be 3.
14751     * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
14752     *
14753     * @example
14754     <example>
14755     <file name="index.jsp">
14756     <script>
14757     function Ctrl($scope) {
14758           $scope.val = 1234.56789;
14759         }
14760     </script>
14761     <div ng-controller="Ctrl">
14762     Enter number: <input ng-model='val'><br>
14763     Default formatting: <span id='number-default'>{{val | number}}</span><br>
14764     No fractions: <span>{{val | number:0}}</span><br>
14765     Negative number: <span>{{-val | number:4}}</span>
14766     </div>
14767     </file>
14768     <file name="protractor.js" type="protractor">
14769     it('should format numbers', function() {
14770         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
14771         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
14772         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
14773       });
14774
14775     it('should update', function() {
14776         element(by.model('val')).clear();
14777         element(by.model('val')).sendKeys('3374.333');
14778         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
14779         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
14780         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
14781      });
14782     </file>
14783     </example>
14784     */
14785
14786
14787    numberFilter.$inject = ['$locale'];
14788    function numberFilter($locale) {
14789        var formats = $locale.NUMBER_FORMATS;
14790        return function (number, fractionSize) {
14791            return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
14792                fractionSize);
14793        };
14794    }
14795
14796    var DECIMAL_SEP = '.';
14797
14798    function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14799        if (number == null || !isFinite(number) || isObject(number)) return '';
14800
14801        var isNegative = number < 0;
14802        number = Math.abs(number);
14803        var numStr = number + '',
14804            formatedText = '',
14805            parts = [];
14806
14807        var hasExponent = false;
14808        if (numStr.indexOf('e') !== -1) {
14809            var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14810            if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14811                numStr = '0';
14812            } else {
14813                formatedText = numStr;
14814                hasExponent = true;
14815            }
14816        }
14817
14818        if (!hasExponent) {
14819            var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
14820
14821            // determine fractionSize if it is not specified
14822            if (isUndefined(fractionSize)) {
14823                fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14824            }
14825
14826            var pow = Math.pow(10, fractionSize);
14827            number = Math.round(number * pow) / pow;
14828            var fraction = ('' + number).split(DECIMAL_SEP);
14829            var whole = fraction[0];
14830            fraction = fraction[1] || '';
14831
14832            var i, pos = 0,
14833                lgroup = pattern.lgSize,
14834                group = pattern.gSize;
14835
14836            if (whole.length >= (lgroup + group)) {
14837                pos = whole.length - lgroup;
14838                for (i = 0; i < pos; i++) {
14839                    if ((pos - i) % group === 0 && i !== 0) {
14840                        formatedText += groupSep;
14841                    }
14842                    formatedText += whole.charAt(i);
14843                }
14844            }
14845
14846            for (i = pos; i < whole.length; i++) {
14847                if ((whole.length - i) % lgroup === 0 && i !== 0) {
14848                    formatedText += groupSep;
14849                }
14850                formatedText += whole.charAt(i);
14851            }
14852
14853            // format fraction part.
14854            while (fraction.length < fractionSize) {
14855                fraction += '0';
14856            }
14857
14858            if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
14859        } else {
14860
14861            if (fractionSize > 0 && number > -1 && number < 1) {
14862                formatedText = number.toFixed(fractionSize);
14863            }
14864        }
14865
14866        parts.push(isNegative ? pattern.negPre : pattern.posPre);
14867        parts.push(formatedText);
14868        parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
14869        return parts.join('');
14870    }
14871
14872    function padNumber(num, digits, trim) {
14873        var neg = '';
14874        if (num < 0) {
14875            neg = '-';
14876            num = -num;
14877        }
14878        num = '' + num;
14879        while (num.length < digits) num = '0' + num;
14880        if (trim)
14881            num = num.substr(num.length - digits);
14882        return neg + num;
14883    }
14884
14885
14886    function dateGetter(name, size, offset, trim) {
14887        offset = offset || 0;
14888        return function (date) {
14889            var value = date['get' + name]();
14890            if (offset > 0 || value > -offset)
14891                value += offset;
14892            if (value === 0 && offset == -12) value = 12;
14893            return padNumber(value, size, trim);
14894        };
14895    }
14896
14897    function dateStrGetter(name, shortForm) {
14898        return function (date, formats) {
14899            var value = date['get' + name]();
14900            var get = uppercase(shortForm ? ('SHORT' + name) : name);
14901
14902            return formats[get][value];
14903        };
14904    }
14905
14906    function timeZoneGetter(date) {
14907        var zone = -1 * date.getTimezoneOffset();
14908        var paddedZone = (zone >= 0) ? "+" : "";
14909
14910        paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
14911            padNumber(Math.abs(zone % 60), 2);
14912
14913        return paddedZone;
14914    }
14915
14916    function ampmGetter(date, formats) {
14917        return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
14918    }
14919
14920    var DATE_FORMATS = {
14921        yyyy: dateGetter('FullYear', 4),
14922        yy: dateGetter('FullYear', 2, 0, true),
14923        y: dateGetter('FullYear', 1),
14924        MMMM: dateStrGetter('Month'),
vendor: 7,605 bytes, lines 14925-15095
14925        MMM: dateStrGetter('Month', true),
14926        MM: dateGetter('Month', 2, 1),
14927        M: dateGetter('Month', 1, 1),
14928        dd: dateGetter('Date', 2),
14929        d: dateGetter('Date', 1),
14930        HH: dateGetter('Hours', 2),
14931        H: dateGetter('Hours', 1),
14932        hh: dateGetter('Hours', 2, -12),
14933        h: dateGetter('Hours', 1, -12),
14934        mm: dateGetter('Minutes', 2),
14935        m: dateGetter('Minutes', 1),
14936        ss: dateGetter('Seconds', 2),
14937        s: dateGetter('Seconds', 1),
14938        // while ISO 8601 requires fractions to be prefixed with `.` or `,`
14939        // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
14940        sss: dateGetter('Milliseconds', 3),
14941        EEEE: dateStrGetter('Day'),
14942        EEE: dateStrGetter('Day', true),
14943        a: ampmGetter,
14944        Z: timeZoneGetter
14945    };
14946
14947    var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
14948        NUMBER_STRING = /^\-?\d+$/;
14949
14950    /**
14951     * @ngdoc filter
14952     * @name date
14953     * @function
14954     *
14955     * @description
14956     *   Formats `date` to a string based on the requested `format`.
14957     *
14958     *   `format` string can be composed of the following elements:
14959     *
14960     *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
14961     *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
14962     *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
14963     *   * `'MMMM'`: Month in year (January-December)
14964     *   * `'MMM'`: Month in year (Jan-Dec)
14965     *   * `'MM'`: Month in year, padded (01-12)
14966     *   * `'M'`: Month in year (1-12)
14967     *   * `'dd'`: Day in month, padded (01-31)
14968     *   * `'d'`: Day in month (1-31)
14969     *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
14970     *   * `'EEE'`: Day in Week, (Sun-Sat)
14971     *   * `'HH'`: Hour in day, padded (00-23)
14972     *   * `'H'`: Hour in day (0-23)
14973     *   * `'hh'`: Hour in am/pm, padded (01-12)
14974     *   * `'h'`: Hour in am/pm, (1-12)
14975     *   * `'mm'`: Minute in hour, padded (00-59)
14976     *   * `'m'`: Minute in hour (0-59)
14977     *   * `'ss'`: Second in minute, padded (00-59)
14978     *   * `'s'`: Second in minute (0-59)
14979     *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
14980     *   * `'a'`: am/pm marker
14981     *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
14982     *
14983     *   `format` string can also be one of the following predefined
14984     *   {@link guide/i18n localizable formats}:
14985     *
14986     *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
14987     *     (e.g. Sep 3, 2010 12:05:08 pm)
14988     *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
14989     *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
14990     *     (e.g. Friday, September 3, 2010)
14991     *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
14992     *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
14993     *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
14994     *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
14995     *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
14996     *
14997     *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
14998     *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
14999     *   (e.g. `"h 'o''clock'"`).
15000     *
15001     * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
15002     *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
15003     *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
15004     *    specified in the string input, the time is considered to be in the local timezone.
15005     * @param {string=} format Formatting rules (see Description). If not specified,
15006     *    `mediumDate` is used.
15007     * @returns {string} Formatted string or the input if input is not recognized as date/millis.
15008     *
15009     * @example
15010     <example>
15011     <file name="index.jsp">
15012     <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
15013     <span>{{1288323623006 | date:'medium'}}</span><br>
15014     <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
15015     <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15016     <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15017     <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15018     </file>
15019     <file name="protractor.js" type="protractor">
15020     it('should format date', function() {
15021         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
15022            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
15023         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
15024            toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15025         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15026     toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15027     });
15028     </file>
15029     </example>
15030     */
15031    dateFilter.$inject = ['$locale'];
15032    function dateFilter($locale) {
15033
15034
15035        var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
15036        // 1        2       3         4          5          6          7          8  9     10      11
15037        function jsonStringToDate(string) {
15038            var match;
15039            if (match = string.match(R_ISO8601_STR)) {
15040                var date = new Date(0),
15041                    tzHour = 0,
15042                    tzMin = 0,
15043                    dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
15044                    timeSetter = match[8] ? date.setUTCHours : date.setHours;
15045
15046                if (match[9]) {
15047                    tzHour = int(match[9] + match[10]);
15048                    tzMin = int(match[9] + match[11]);
15049                }
15050                dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
15051                var h = int(match[4] || 0) - tzHour;
15052                var m = int(match[5] || 0) - tzMin;
15053                var s = int(match[6] || 0);
15054                var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
15055                timeSetter.call(date, h, m, s, ms);
15056                return date;
15057            }
15058            return string;
15059        }
15060
15061
15062        return function (date, format) {
15063            var text = '',
15064                parts = [],
15065                fn, match;
15066
15067            format = format || 'mediumDate';
15068            format = $locale.DATETIME_FORMATS[format] || format;
15069            if (isString(date)) {
15070                if (NUMBER_STRING.test(date)) {
15071                    date = int(date);
15072                } else {
15073                    date = jsonStringToDate(date);
15074                }
15075            }
15076
15077            if (isNumber(date)) {
15078                date = new Date(date);
15079            }
15080
15081            if (!isDate(date)) {
15082                return date;
15083            }
15084
15085            while (format) {
15086                match = DATE_FORMATS_SPLIT.exec(format);
15087                if (match) {
15088                    parts = concat(parts, match, 1);
15089                    format = parts.pop();
15090                } else {
15091                    parts.push(format);
15092                    format = null;
15093                }
15094            }
15095
15096            forEach(parts, function (value) {
15097                fn = DATE_FORMATS[value];
15098                text += fn ? fn(date, $locale.DATETIME_FORMATS)
15099                    : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
15100            });
15101
15102            return text;
15103        };
15104    }
15105
15106
15107    /**
15108     * @ngdoc filter
15109     * @name json
15110     * @function
15111     *
15112     * @description
15113     *   Allows you to convert a JavaScript object into JSON string.
15114     *
15115     *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
15116     *   the binding is automatically converted to JSON.
15117     *
15118     * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
15119     * @returns {string} JSON string.
15120     *
15121     *
15122     * @example
15123     <example>
15124     <file name="index.jsp">
15125     <pre>{{ {'name':'value'} | json }}</pre>
15126     </file>
15127     <file name="protractor.js" type="protractor">
15128     it('should jsonify filtered objects', function() {
15129         expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
15130       });
15131     </file>
15132     </example>
15133     *
15134     */
15135    function jsonFilter() {
15136        return function (object) {
15137            return toJson(object, true);
15138        };
15139    }
15140
15141
15142    /**
15143     * @ngdoc filter
15144     * @name lowercase
15145     * @function
15146     * @description
15147     * Converts string to lowercase.
15148     * @see angular.lowercase
15149     */
15150    var lowercaseFilter = valueFn(lowercase);
15151
15152
15153    /**
15154     * @ngdoc filter
15155     * @name uppercase
15156     * @function
15157     * @description
15158     * Converts string to uppercase.
15159     * @see angular.uppercase
15160     */
15161    var uppercaseFilter = valueFn(uppercase);
15162
15163    /**
15164     * @ngdoc filter
15165     * @name limitTo
15166     * @function
15167     *
15168     * @description
15169     * Creates a new array or string containing only a specified number of elements. The elements
15170     * are taken from either the beginning or the end of the source array or string, as specified by
15171     * the value and sign (positive or negative) of `limit`.
15172     *
15173     * @param {Array|string} input Source array or string to be limited.
15174     * @param {string|number} limit The length of the returned array or string. If the `limit` number
15175     *     is positive, `limit` number of items from the beginning of the source array/string are copied.
15176     *     If the number is negative, `limit` number  of items from the end of the source array/string
15177     *     are copied. The `limit` will be trimmed if it exceeds `array.length`
15178     * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
15179     *     had less than `limit` elements.
15180     *
15181     * @example
15182     <example>
15183     <file name="index.jsp">
15184     <script>
15185     function Ctrl($scope) {
15186           $scope.numbers = [1,2,3,4,5,6,7,8,9];
15187           $scope.letters = "abcdefghi";
15188           $scope.numLimit = 3;
15189           $scope.letterLimit = 3;
15190         }
15191     </script>
15192     <div ng-controller="Ctrl">
15193     Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
15194     <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
15195     Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
15196     <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
15197     </div>
15198     </file>
15199     <file name="protractor.js" type="protractor">
15200     var numLimitInput = element(by.model('numLimit'));
15201     var letterLimitInput = element(by.model('letterLimit'));
15202     var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
15203     var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
15204
15205     it('should limit the number array to first three items', function() {
15206         expect(numLimitInput.getAttribute('value')).toBe('3');
15207         expect(letterLimitInput.getAttribute('value')).toBe('3');
15208         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
15209         expect(limitedLetters.getText()).toEqual('Output letters: abc');
15210       });
15211
15212     it('should update the output when -3 is entered', function() {
15213         numLimitInput.clear();
15214         numLimitInput.sendKeys('-3');
15215         letterLimitInput.clear();
15216         letterLimitInput.sendKeys('-3');
15217         expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
15218         expect(limitedLetters.getText()).toEqual('Output letters: ghi');
15219       });
15220
15221     it('should not exceed the maximum size of input array', function() {
15222         numLimitInput.clear();
15223         numLimitInput.sendKeys('100');
15224         letterLimitInput.clear();
15225         letterLimitInput.sendKeys('100');
15226         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
15227         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
15228       });
15229     </file>
15230     </example>
15231     */
15232    function limitToFilter() {
15233        return function (input, limit) {
15234            if (!isArray(input) && !isString(input)) return input;
15235
15236            limit = int(limit);
15237
15238            if (isString(input)) {
15239                //NaN check on limit
15240                if (limit) {
15241                    return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
15242                } else {
15243                    return "";
15244                }
15245            }
15246
15247            var out = [],
15248                i, n;
15249
15250            // if abs(limit) exceeds maximum length, trim it
15251            if (limit > input.length)
15252                limit = input.length;
15253            else if (limit < -input.length)
15254                limit = -input.length;
15255
15256            if (limit > 0) {
15257                i = 0;
15258                n = limit;
15259            } else {
15260                i = input.length + limit;
15261                n = input.length;
15262            }
15263
15264            for (; i < n; i++) {
15265                out.push(input[i]);
15266            }
15267
15268            return out;
15269        };
15270    }
15271
15272    /**
15273     * @ngdoc filter
15274     * @name orderBy
15275     * @function
15276     *
15277     * @description
15278     * Orders a specified `array` by the `expression` predicate.
15279     *
15280     * @param {Array} array The array to sort.
15281     * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
15282     *    used by the comparator to determine the order of elements.
15283     *
15284     *    Can be one of:
15285     *
15286     *    - `function`: Getter function. The result of this function will be sorted using the
15287     *      `<`, `=`, `>` operator.
15288     *    - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
15289     *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
15290     *      ascending or descending sort order (for example, +name or -name).
15291     *    - `Array`: An array of function or string predicates. The first predicate in the array
15292     *      is used for sorting, but when two items are equivalent, the next predicate is used.
15293     *
15294     * @param {boolean=} reverse Reverse the order of the array.
15295     * @returns {Array} Sorted copy of the source array.
15296     *
15297     * @example
15298     <example>
15299     <file name="index.jsp">
15300     <script>
15301     function Ctrl($scope) {
15302           $scope.friends =
15303               [{name:'John', phone:'555-1212', age:10},
15304                {name:'Mary', phone:'555-9876', age:19},
15305                {name:'Mike', phone:'555-4321', age:21},
15306                {name:'Adam', phone:'555-5678', age:35},
15307                {name:'Julie', phone:'555-8765', age:29}]
15308           $scope.predicate = '-age';
15309         }
15310     </script>
15311     <div ng-controller="Ctrl">
15312     <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
15313     <hr/>
15314     [ <a href="" ng-click="predicate=''">unsorted</a> ]
15315     <table class="friend">
15316     <tr>
15317     <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
15318     (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
15319     <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
15320     <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
15321     </tr>
15322     <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
15323     <td>{{friend.name}}</td>
15324     <td>{{friend.phone}}</td>
15325     <td>{{friend.age}}</td>
15326     </tr>
15327     </table>
15328     </div>
15329     </file>
15330     </example>
15331     */
15332    orderByFilter.$inject = ['$parse'];
15333    function orderByFilter($parse) {
15334        return function (array, sortPredicate, reverseOrder) {
15335            if (!isArray(array)) return array;
15336            if (!sortPredicate) return array;
15337            sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
15338            sortPredicate = map(sortPredicate, function (predicate) {
15339                var descending = false, get = predicate || identity;
15340                if (isString(predicate)) {
15341                    if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
15342                        descending = predicate.charAt(0) == '-';
15343                        predicate = predicate.substring(1);
15344                    }
15345                    get = $parse(predicate);
15346                    if (get.constant) {
15347                        var key = get();
15348                        return reverseComparator(function (a, b) {
15349                            return compare(a[key], b[key]);
15350                        }, descending);
15351                    }
15352                }
15353                return reverseComparator(function (a, b) {
15354                    return compare(get(a), get(b));
15355                }, descending);
15356            });
15357            var arrayCopy = [];
15358            for (var i = 0; i < array.length; i++) {
15359                arrayCopy.push(array[i]);
15360            }
15361            return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
15362
15363            function comparator(o1, o2) {
15364                for (var i = 0; i < sortPredicate.length; i++) {
15365                    var comp = sortPredicate[i](o1, o2);
15366                    if (comp !== 0) return comp;
15367                }
15368                return 0;
15369            }
15370
15371            function reverseComparator(comp, descending) {
15372                return toBoolean(descending)
15373                    ? function (a, b) {
15374                    return comp(b, a);
15375                }
15376                    : comp;
15377            }
15378
15379            function compare(v1, v2) {
15380                var t1 = typeof v1;
15381                var t2 = typeof v2;
15382                if (t1 == t2) {
15383                    if (t1 == "string") {
15384                        v1 = v1.toLowerCase();
15385                        v2 = v2.toLowerCase();
15386                    }
15387                    if (v1 === v2) return 0;
15388                    return v1 < v2 ? -1 : 1;
15389                } else {
15390                    return t1 < t2 ? -1 : 1;
15391                }
15392            }
15393        };
15394    }
15395
15396    function ngDirective(directive) {
15397        if (isFunction(directive)) {
15398            directive = {
15399                link: directive
15400            };
15401        }
15402        directive.restrict = directive.restrict || 'AC';
15403        return valueFn(directive);
15404    }
15405
15406    /**
15407     * @ngdoc directive
15408     * @name a
15409     * @restrict E
15410     *
15411     * @description
15412     * Modifies the default behavior of the html A tag so that the default action is prevented when
15413     * the href attribute is empty.
15414     *
15415     * This change permits the easy creation of action links with the `ngClick` directive
15416     * without changing the location or causing page reloads, e.g.:
15417     * `<a href="" ng-click="list.addItem()">Add Item</a>`
15418     */
15419    var htmlAnchorDirective = valueFn({
15420        restrict: 'E',
15421        compile: function (element, attr) {
15422
15423            if (msie <= 8) {
15424
15425                // turn <a href ng-click="..">link</a> into a stylable link in IE
15426                // but only if it doesn't have name attribute, in which case it's an anchor
15427                if (!attr.href && !attr.name) {
15428                    attr.$set('href', '');
15429                }
15430
15431                // add a comment node to anchors to workaround IE bug that causes element content to be reset
15432                // to new attribute content if attribute is updated with value containing @ and element also
15433                // contains value with @
15434                // see issue #1949
15435                element.append(document.createComment('IE fix'));
15436            }
15437
15438            if (!attr.href && !attr.xlinkHref && !attr.name) {
15439                return function (scope, element) {
15440                    // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
15441                    var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
15442                        'xlink:href' : 'href';
15443                    element.on('click', function (event) {
15444                        // if we have no href url, then don't navigate anywhere.
15445                        if (!element.attr(href)) {
15446                            event.preventDefault();
15447                        }
15448                    });
15449                };
15450            }
15451        }
15452    });
15453
15454    /**
15455     * @ngdoc directive
15456     * @name ngHref
15457     * @restrict A
15458     * @priority 99
15459     *
15460     * @description
15461     * Using Angular markup like `{{hash}}` in an href attribute will
15462     * make the link go to the wrong URL if the user clicks it before
15463     * Angular has a chance to replace the `{{hash}}` markup with its
15464     * value. Until Angular replaces the markup the link will be broken
15465     * and will most likely return a 404 error.
15466     *
15467     * The `ngHref` directive solves this problem.
15468     *
15469     * The wrong way to write it:
15470     * ```html
15471     * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
15472     * ```
15473     *
15474     * The correct way to write it:
15475     * ```html
15476     * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
15477     * ```
15478     *
15479     * @element A
15480     * @param {template} ngHref any string which can contain `{{}}` markup.
15481     *
15482     * @example
15483     * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
15484     * in links and their different behaviors:
15485     <example>
15486     <file name="index.jsp">
15487     <input ng-model="value" /><br />
15488     <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
15489     <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
15490     <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
15491     <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
15492     <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
15493     <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
15494     </file>
15495     <file name="protractor.js" type="protractor">
15496     it('should execute ng-click but not reload when href without value', function() {
15497          element(by.id('link-1')).click();
15498          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
15499          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
15500        });
15501
15502     it('should execute ng-click but not reload when href empty string', function() {
15503          element(by.id('link-2')).click();
15504          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
15505          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
15506        });
15507
15508     it('should execute ng-click and change url when ng-href specified', function() {
15509          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
15510
15511          element(by.id('link-3')).click();
15512
15513          // At this point, we navigate away from an Angular page, so we need
15514          // to use browser.driver to get the base webdriver.
15515
15516          browser.wait(function() {
15517            return browser.driver.getCurrentUrl().then(function(url) {
15518              return url.match(/\/123$/);
15519            });
15520          }, 1000, 'page should navigate to /123');
15521        });
15522
15523     xit('should execute ng-click but not reload when href empty string and name specified', function() {
15524          element(by.id('link-4')).click();
15525          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
15526          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
15527        });
15528
15529     it('should execute ng-click but not reload when no href but name specified', function() {
15530          element(by.id('link-5')).click();
15531          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
15532          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
15533        });
15534
15535     it('should only change url when only ng-href', function() {
15536          element(by.model('value')).clear();
15537          element(by.model('value')).sendKeys('6');
15538          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
15539
15540          element(by.id('link-6')).click();
15541
15542          // At this point, we navigate away from an Angular page, so we need
15543          // to use browser.driver to get the base webdriver.
15544          browser.wait(function() {
15545            return browser.driver.getCurrentUrl().then(function(url) {
15546              return url.match(/\/6$/);
15547            });
15548          }, 1000, 'page should navigate to /6');
15549        });
15550     </file>
15551     </example>
15552     */
15553
15554    /**
15555     * @ngdoc directive
15556     * @name ngSrc
15557     * @restrict A
15558     * @priority 99
15559     *
15560     * @description
15561     * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
15562     * work right: The browser will fetch from the URL with the literal
15563     * text `{{hash}}` until Angular replaces the expression inside
15564     * `{{hash}}`. The `ngSrc` directive solves this problem.
15565     *
15566     * The buggy way to write it:
15567     * ```html
15568     * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
15569     * ```
15570     *
15571     * The correct way to write it:
15572     * ```html
15573     * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
15574     * ```
15575     *
15576     * @element IMG
15577     * @param {template} ngSrc any string which can contain `{{}}` markup.
15578     */
15579
15580    /**
15581     * @ngdoc directive
15582     * @name ngSrcset
15583     * @restrict A
15584     * @priority 99
15585     *
15586     * @description
15587     * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
15588     * work right: The browser will fetch from the URL with the literal
15589     * text `{{hash}}` until Angular replaces the expression inside
15590     * `{{hash}}`. The `ngSrcset` directive solves this problem.
15591     *
15592     * The buggy way to write it:
15593     * ```html
15594     * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15595     * ```
15596     *
15597     * The correct way to write it:
15598     * ```html
15599     * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
15600     * ```
15601     *
15602     * @element IMG
15603     * @param {template} ngSrcset any string which can contain `{{}}` markup.
15604     */
15605
15606    /**
15607     * @ngdoc directive
15608     * @name ngDisabled
15609     * @restrict A
15610     * @priority 100
15611     *
15612     * @description
15613     *
15614     * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15615     * ```html
15616     * <div ng-init="scope = { isDisabled: false }">
15617     *  <button disabled="{{scope.isDisabled}}">Disabled</button>
15618     * </div>
15619     * ```
15620     *
15621     * The HTML specification does not require browsers to preserve the values of boolean attributes
15622     * such as disabled. (Their presence means true and their absence means false.)
15623     * If we put an Angular interpolation expression into such an attribute then the
15624     * binding information would be lost when the browser removes the attribute.
15625     * The `ngDisabled` directive solves this problem for the `disabled` attribute.
15626     * This complementary directive is not removed by the browser and so provides
15627     * a permanent reliable place to store the binding information.
15628     *
15629     * @example
15630     <example>
15631     <file name="index.jsp">
15632     Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
15633     <button ng-model="button" ng-disabled="checked">Button</button>
15634     </file>
15635     <file name="protractor.js" type="protractor">
15636     it('should toggle button', function() {
15637          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
15638          element(by.model('checked')).click();
15639          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
15640        });
15641     </file>
15642     </example>
15643     *
15644     * @element INPUT
15645     * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
15646     *     then special attribute "disabled" will be set on the element
15647     */
15648
15649
15650    /**
15651     * @ngdoc directive
15652     * @name ngChecked
15653     * @restrict A
15654     * @priority 100
15655     *
15656     * @description
15657     * The HTML specification does not require browsers to preserve the values of boolean attributes
15658     * such as checked. (Their presence means true and their absence means false.)
15659     * If we put an Angular interpolation expression into such an attribute then the
15660     * binding information would be lost when the browser removes the attribute.
15661     * The `ngChecked` directive solves this problem for the `checked` attribute.
15662     * This complementary directive is not removed by the browser and so provides
15663     * a permanent reliable place to store the binding information.
15664     * @example
15665     <example>
15666     <file name="index.jsp">
15667     Check me to check both: <input type="checkbox" ng-model="master"><br/>
15668     <input id="checkSlave" type="checkbox" ng-checked="master">
15669     </file>
15670     <file name="protractor.js" type="protractor">
15671     it('should check both checkBoxes', function() {
15672          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
15673          element(by.model('master')).click();
15674          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
15675        });
15676     </file>
15677     </example>
15678     *
15679     * @element INPUT
15680     * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
15681     *     then special attribute "checked" will be set on the element
15682     */
15683
15684
15685    /**
15686     * @ngdoc directive
15687     * @name ngReadonly
15688     * @restrict A
15689     * @priority 100
15690     *
15691     * @description
15692     * The HTML specification does not require browsers to preserve the values of boolean attributes
15693     * such as readonly. (Their presence means true and their absence means false.)
15694     * If we put an Angular interpolation expression into such an attribute then the
15695     * binding information would be lost when the browser removes the attribute.
15696     * The `ngReadonly` directive solves this problem for the `readonly` attribute.
15697     * This complementary directive is not removed by the browser and so provides
15698     * a permanent reliable place to store the binding information.
15699     * @example
15700     <example>
15701     <file name="index.jsp">
15702     Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
15703     <input type="text" ng-readonly="checked" value="I'm Angular"/>
15704     </file>
15705     <file name="protractor.js" type="protractor">
15706     it('should toggle readonly attr', function() {
15707          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
15708          element(by.model('checked')).click();
15709          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
15710        });
15711     </file>
15712     </example>
15713     *
15714     * @element INPUT
15715     * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
15716     *     then special attribute "readonly" will be set on the element
15717     */
15718
15719
15720    /**
15721     * @ngdoc directive
15722     * @name ngSelected
15723     * @restrict A
15724     * @priority 100
15725     *
15726     * @description
15727     * The HTML specification does not require browsers to preserve the values of boolean attributes
15728     * such as selected. (Their presence means true and their absence means false.)
15729     * If we put an Angular interpolation expression into such an attribute then the
15730     * binding information would be lost when the browser removes the attribute.
15731     * The `ngSelected` directive solves this problem for the `selected` attribute.
15732     * This complementary directive is not removed by the browser and so provides
15733     * a permanent reliable place to store the binding information.
15734     *
15735     * @example
15736     <example>
15737     <file name="index.jsp">
15738     Check me to select: <input type="checkbox" ng-model="selected"><br/>
15739     <select>
15740     <option>Hello!</option>
15741     <option id="greet" ng-selected="selected">Greetings!</option>
15742     </select>
15743     </file>
15744     <file name="protractor.js" type="protractor">
15745     it('should select Greetings!', function() {
15746          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
15747          element(by.model('selected')).click();
15748          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
15749        });
15750     </file>
15751     </example>
15752     *
15753     * @element OPTION
15754     * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
15755     *     then special attribute "selected" will be set on the element
15756     */
15757
15758    /**
15759     * @ngdoc directive
15760     * @name ngOpen
15761     * @restrict A
15762     * @priority 100
15763     *
15764     * @description
15765     * The HTML specification does not require browsers to preserve the values of boolean attributes
15766     * such as open. (Their presence means true and their absence means false.)
15767     * If we put an Angular interpolation expression into such an attribute then the
15768     * binding information would be lost when the browser removes the attribute.
15769     * The `ngOpen` directive solves this problem for the `open` attribute.
15770     * This complementary directive is not removed by the browser and so provides
15771     * a permanent reliable place to store the binding information.
15772     * @example
15773     <example>
15774     <file name="index.jsp">
15775     Check me check multiple: <input type="checkbox" ng-model="open"><br/>
15776     <details id="details" ng-open="open">
15777     <summary>Show/Hide me</summary>
15778     </details>
15779     </file>
15780     <file name="protractor.js" type="protractor">
15781     it('should toggle open', function() {
15782           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
15783           element(by.model('open')).click();
15784           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
15785         });
15786     </file>
15787     </example>
15788     *
15789     * @element DETAILS
15790     * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
15791     *     then special attribute "open" will be set on the element
15792     */
15793
15794    var ngAttributeAliasDirectives = {};
15795
15796
15797// boolean attrs are evaluated
15798    forEach(BOOLEAN_ATTR, function (propName, attrName) {
15799        // binding to multiple is not supported
15800        if (propName == "multiple") return;
15801
15802        var normalized = directiveNormalize('ng-' + attrName);
15803        ngAttributeAliasDirectives[normalized] = function () {
15804            return {
15805                priority: 100,
15806                link: function (scope, element, attr) {
15807                    scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
15808                        attr.$set(attrName, !!value);
15809                    });
15810                }
15811            };
15812        };
15813    });
15814
15815
15816// ng-src, ng-srcset, ng-href are interpolated
15817    forEach(['src', 'srcset', 'href'], function (attrName) {
15818        var normalized = directiveNormalize('ng-' + attrName);
15819        ngAttributeAliasDirectives[normalized] = function () {
15820            return {
15821                priority: 99, // it needs to run after the attributes are interpolated
15822                link: function (scope, element, attr) {
15823                    var propName = attrName,
15824                        name = attrName;
15825
15826                    if (attrName === 'href' &&
15827                        toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
15828                        name = 'xlinkHref';
15829                        attr.$attr[name] = 'xlink:href';
15830                        propName = null;
15831                    }
15832
15833                    attr.$observe(normalized, function (value) {
15834                        if (!value)
15835                            return;
15836
15837                        attr.$set(name, value);
15838
15839                        // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
15840                        // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
15841                        // to set the property as well to achieve the desired effect.
15842                        // we use attr[attrName] value since $set can sanitize the url.
15843                        if (msie && propName) element.prop(propName, attr[name]);
15844                    });
15845                }
15846            };
15847        };
15848    });
15849
15850    /* global -nullFormCtrl */
15851    var nullFormCtrl = {
15852        $addControl: noop,
15853        $removeControl: noop,
15854        $setValidity: noop,
15855        $setDirty: noop,
15856        $setPristine: noop
15857    };
15858
15859    /**
15860     * @ngdoc type
15861     * @name form.FormController
15862     *
15863     * @property {boolean} $pristine True if user has not interacted with the form yet.
15864     * @property {boolean} $dirty True if user has already interacted with the form.
15865     * @property {boolean} $valid True if all of the containing forms and controls are valid.
15866     * @property {boolean} $invalid True if at least one containing control or form is invalid.
15867     *
15868     * @property {Object} $error Is an object hash, containing references to all invalid controls or
15869     *  forms, where:
15870     *
15871     *  - keys are validation tokens (error names),
15872     *  - values are arrays of controls or forms that are invalid for given error name.
15873     *
15874     *
15875     *  Built-in validation tokens:
15876     *
15877     *  - `email`
15878     *  - `max`
15879     *  - `maxlength`
15880     *  - `min`
15881     *  - `minlength`
15882     *  - `number`
15883     *  - `pattern`
15884     *  - `required`
15885     *  - `url`
15886     *
15887     * @description
15888     * `FormController` keeps track of all its controls and nested forms as well as state of them,
15889     * such as being valid/invalid or dirty/pristine.
15890     *
15891     * Each {@link ng.directive:form form} directive creates an instance
15892     * of `FormController`.
15893     *
15894     */
15895//asks for $scope to fool the BC controller module
15896    FormController.$inject = ['$element', '$attrs', '$scope', '$animate'];
15897    function FormController(element, attrs, $scope, $animate) {
15898        var form = this,
15899            parentForm = element.parent().controller('form') || nullFormCtrl,
15900            invalidCount = 0, // used to easily determine if we are valid
15901            errors = form.$error = {},
15902            controls = [];
15903
15904        // init state
15905        form.$name = attrs.name || attrs.ngForm;
15906        form.$dirty = false;
15907        form.$pristine = true;
15908        form.$valid = true;
15909        form.$invalid = false;
15910
15911        parentForm.$addControl(form);
15912
15913        // Setup initial state of the control
15914        element.addClass(PRISTINE_CLASS);
15915        toggleValidCss(true);
15916
15917        // convenience method for easy toggling of classes
15918        function toggleValidCss(isValid, validationErrorKey) {
15919            validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
15920            $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
15921            $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
15922        }
15923
15924        /**
15925         * @ngdoc method
15926         * @name form.FormController#$addControl
15927         *
15928         * @description
15929         * Register a control with the form.
15930         *
15931         * Input elements using ngModelController do this automatically when they are linked.
15932         */
15933        form.$addControl = function (control) {
15934            // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
15935            // and not added to the scope.  Now we throw an error.
15936            assertNotHasOwnProperty(control.$name, 'input');
15937            controls.push(control);
15938
15939            if (control.$name) {
15940                form[control.$name] = control;
15941            }
15942        };
15943
15944        /**
15945         * @ngdoc method
15946         * @name form.FormController#$removeControl
15947         *
15948         * @description
15949         * Deregister a control from the form.
15950         *
15951         * Input elements using ngModelController do this automatically when they are destroyed.
15952         */
15953        form.$removeControl = function (control) {
15954            if (control.$name && form[control.$name] === control) {
15955                delete form[control.$name];
15956            }
15957            forEach(errors, function (queue, validationToken) {
15958                form.$setValidity(validationToken, true, control);
15959            });
15960
15961            arrayRemove(controls, control);
15962        };
15963
15964        /**
15965         * @ngdoc method
15966         * @name form.FormController#$setValidity
15967         *
15968         * @description
15969         * Sets the validity of a form control.
15970         *
15971         * This method will also propagate to parent forms.
15972         */
15973        form.$setValidity = function (validationToken, isValid, control) {
15974            var queue = errors[validationToken];
15975
15976            if (isValid) {
15977                if (queue) {
15978                    arrayRemove(queue, control);
15979                    if (!queue.length) {
15980                        invalidCount--;
15981                        if (!invalidCount) {
15982                            toggleValidCss(isValid);
15983                            form.$valid = true;
15984                            form.$invalid = false;
15985                        }
15986                        errors[validationToken] = false;
15987                        toggleValidCss(true, validationToken);
15988                        parentForm.$setValidity(validationToken, true, form);
15989                    }
15990                }
15991
15992            } else {
15993                if (!invalidCount) {
15994                    toggleValidCss(isValid);
15995                }
15996                if (queue) {
15997                    if (includes(queue, control)) return;
15998                } else {
15999                    errors[validationToken] = queue = [];
16000                    invalidCount++;
16001                    toggleValidCss(false, validationToken);
16002                    parentForm.$setValidity(validationToken, false, form);
16003                }
16004                queue.push(control);
16005
16006                form.$valid = false;
16007                form.$invalid = true;
16008            }
16009        };
16010
16011        /**
16012         * @ngdoc method
16013         * @name form.FormController#$setDirty
16014         *
16015         * @description
16016         * Sets the form to a dirty state.
16017         *
16018         * This method can be called to add the 'ng-dirty' class and set the form to a dirty
16019         * state (ng-dirty class). This method will also propagate to parent forms.
16020         */
16021        form.$setDirty = function () {
16022            $animate.removeClass(element, PRISTINE_CLASS);
16023            $animate.addClass(element, DIRTY_CLASS);
16024            form.$dirty = true;
16025            form.$pristine = false;
16026            parentForm.$setDirty();
16027        };
16028
16029        /**
16030         * @ngdoc method
16031         * @name form.FormController#$setPristine
16032         *
16033         * @description
16034         * Sets the form to its pristine state.
16035         *
16036         * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
16037         * state (ng-pristine class). This method will also propagate to all the controls contained
16038         * in this form.
16039         *
16040         * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
16041         * saving or resetting it.
16042         */
16043        form.$setPristine = function () {
16044            $animate.removeClass(element, DIRTY_CLASS);
16045            $animate.addClass(element, PRISTINE_CLASS);
16046            form.$dirty = false;
16047            form.$pristine = true;
16048            forEach(controls, function (control) {
16049                control.$setPristine();
16050            });
16051        };
16052    }
16053
16054
16055    /**
16056     * @ngdoc directive
16057     * @name ngForm
16058     * @restrict EAC
16059     *
16060     * @description
16061     * Nestable alias of {@link ng.directive:form `form`} directive. HTML
16062     * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
16063     * sub-group of controls needs to be determined.
16064     *
16065     * Note: the purpose of `ngForm` is to group controls,
16066     * but not to be a replacement for the `<form>` tag with all of its capabilities
16067     * (e.g. posting to the server, ...).
16068     *
16069     * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
16070     *                       related scope, under this name.
16071     *
16072     */
16073
16074    /**
16075     * @ngdoc directive
16076     * @name form
16077     * @restrict E
16078     *
16079     * @description
16080     * Directive that instantiates
16081     * {@link form.FormController FormController}.
16082     *
16083     * If the `name` attribute is specified, the form controller is published onto the current scope under
16084     * this name.
16085     *
16086     * # Alias: {@link ng.directive:ngForm `ngForm`}
16087     *
16088     * In Angular forms can be nested. This means that the outer form is valid when all of the child
16089     * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
16090     * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
16091     * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
16092     * using Angular validation directives in forms that are dynamically generated using the
16093     * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
16094     * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
16095     * `ngForm` directive and nest these in an outer `form` element.
16096     *
16097     *
16098     * # CSS classes
16099     *  - `ng-valid` is set if the form is valid.
16100     *  - `ng-invalid` is set if the form is invalid.
16101     *  - `ng-pristine` is set if the form is pristine.
16102     *  - `ng-dirty` is set if the form is dirty.
16103     *
16104     * Keep in mind that ngAnimate can detect each of these classes when added and removed.
16105     *
16106     *
16107     * # Submitting a form and preventing the default action
16108     *
16109     * Since the role of forms in client-side Angular applications is different than in classical
16110     * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
16111     * page reload that sends the data to the server. Instead some javascript logic should be triggered
16112     * to handle the form submission in an application-specific way.
16113     *
16114     * For this reason, Angular prevents the default action (form submission to the server) unless the
16115     * `<form>` element has an `action` attribute specified.
16116     *
16117     * You can use one of the following two ways to specify what javascript method should be called when
16118     * a form is submitted:
16119     *
16120     * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
16121     * - {@link ng.directive:ngClick ngClick}
16121 directive on the first
16122     *  button or input field of type submit (input[type=submit])
16123     *
16124     * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
16125     * or {@link ng.directive:ngClick ngClick} directives.
16126     * This is because of the following form submission rules in the HTML specification:
16127     *
16128     * - If a form has only one input field then hitting enter in this field triggers form submit
16129     * (`ngSubmit`)
16130     * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
16131     * doesn't trigger submit
16132     * - if a form has one or more input fields and one or more buttons or input[type=submit] then
16133     * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16134     * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16135     *
16136     * @param {string=} name Name of the form. If specified, the form controller will be published into
16137     *                       related scope, under this name.
16138     *
16139     * ## Animation Hooks
16140     *
16141     * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
16142     * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
16143     * other validations that are performed within the form. Animations in ngForm are similar to how
16144     * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
16145     * as JS animations.
16146     *
16147     * The following example shows a simple way to utilize CSS transitions to style a form element
16148     * that has been rendered as invalid after it has been validated:
16149     *
16150     * <pre>
16151     * //be sure to include ngAnimate as a module to hook into more
16152     * //advanced animations
16153     * .my-form {
16154 *   transition:0.5s linear all;
16155 *   background: white;
16156 * }
16157     * .my-form.ng-invalid {
16158 *   background: red;
16159 *   color:white;
16160 * }
16161     * </pre>
16162     *
16163     * @example
16164     <example deps="angular-animate.js" animations="true" fixBase="true">
16165     <file name="index.jsp">
16166     <script>
16167     function Ctrl($scope) {
16168           $scope.userType = 'guest';
16169         }
16170     </script>
16171     <style>
16172     .my-form {
16173          -webkit-transition:all linear 0.5s;
16174          transition:all linear 0.5s;
16175          background: transparent;
16176        }
16177     .my-form.ng-invalid {
16178          background: red;
16179        }
16180     </style>
16181     <form name="myForm" ng-controller="Ctrl" class="my-form">
16182     userType: <input name="input" ng-model="userType" required>
16183     <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
16184     <tt>userType = {{userType}}</tt><br>
16185     <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
16186     <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
16187     <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
16188     <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
16189     </form>
16190     </file>
16191     <file name="protractor.js" type="protractor">
16192     it('should initialize to model', function() {
16193          var userType = element(by.binding('userType'));
16194          var valid = element(by.binding('myForm.input.$valid'));
16195
16196          expect(userType.getText()).toContain('guest');
16197          expect(valid.getText()).toContain('true');
16198        });
16199
16200     it('should be invalid if empty', function() {
16201          var userType = element(by.binding('userType'));
16202          var valid = element(by.binding('myForm.input.$valid'));
16203          var userInput = element(by.model('userType'));
16204
16205          userInput.clear();
16206          userInput.sendKeys('');
16207
16208          expect(userType.getText()).toEqual('userType =');
16209          expect(valid.getText()).toContain('false');
16210        });
16211     </file>
16212     </example>
16213     *
16214     */
16215    var formDirectiveFactory = function (isNgForm) {
16216        return ['$timeout', function ($timeout) {
16217            var formDirective = {
16218                name: 'form',
16219                restrict: isNgForm ? 'EAC' : 'E',
16220                controller: FormController,
16221                compile: function () {
16222                    return {
16223                        pre: function (scope, formElement, attr, controller) {
16224                            if (!attr.action) {
16225                                // we can't use jq events because if a form is destroyed during submission the default
16226                                // action is not prevented. see #1238
16227                                //
16228                                // IE 9 is not affected because it doesn't fire a submit event and try to do a full
16229                                // page reload if the form was destroyed by submission of the form via a click handler
16230                                // on a button in the form. Looks like an IE9 specific bug.
16231                                var preventDefaultListener = function (event) {
16232                                    event.preventDefault
16233                                        ? event.preventDefault()
16234                                        : event.returnValue = false; // IE
16235                                };
16236
16237                                addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16238
16239                                // unregister the preventDefault listener so that we don't not leak memory but in a
16240                                // way that will achieve the prevention of the default action.
16241                                formElement.on('$destroy', function () {
16242                                    $timeout(function () {
16243                                        removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
16244                                    }, 0, false);
16245                                });
16246                            }
16247
16248                            var parentFormCtrl = formElement.parent().controller('form'),
16249                                alias = attr.name || attr.ngForm;
16250
16251                            if (alias) {
16252                                setter(scope, alias, controller, alias);
16253                            }
16254                            if (parentFormCtrl) {
16255                                formElement.on('$destroy', function () {
16256                                    parentFormCtrl.$removeControl(controller);
16257                                    if (alias) {
16258                                        setter(scope, alias, undefined, alias);
16259                                    }
16260                                    extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
16261                                });
16262                            }
16263                        }
16264                    };
16265                }
16266            };
16267
16268            return formDirective;
16269        }];
16270    };
16271
16272    var formDirective = formDirectiveFactory();
16273    var ngFormDirective = formDirectiveFactory(true);
16274
16275    /* global
16276
16277     -VALID_CLASS,
16278     -INVALID_CLASS,
16279     -PRISTINE_CLASS,
16280     -DIRTY_CLASS
16281     */
16282
16283    var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16284    var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
16285    var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16286
16287    var inputType = {
16288
16289        /**
16290         * @ngdoc input
16291         * @name input[text]
16292         *
16293         * @description
16294         * Standard HTML text input with angular data binding.
16295         *
16296         * @param {string} ngModel Assignable angular expression to data-bind to.
16297         * @param {string=} name Property name of the form under which the control is published.
16298         * @param {string=} required Adds `required` validation error key if the value is not entered.
16299         * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16300         *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16301         *    `required` when you want to data-bind to the `required` attribute.
16302         * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16303         *    minlength.
16304         * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16305         *    maxlength.
16306         * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16307         *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16308         *    patterns defined as scope expressions.
16309         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16310         *    interaction with the input element.
16311         * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16312         *
16313         * @example
16314         <example name="text-input-directive">
16315         <file name="index.jsp">
16316         <script>
16317         function Ctrl($scope) {
16318             $scope.text = 'guest';
16319             $scope.word = /^\s*\w*\s*$/;
16320           }
16321         </script>
16322         <form name="myForm" ng-controller="Ctrl">
16323         Single word: <input type="text" name="input" ng-model="text"
16324         ng-pattern="word" required ng-trim="false">
16325         <span class="error" ng-show="myForm.input.$error.required">
16326         Required!</span>
16327         <span class="error" ng-show="myForm.input.$error.pattern">
16328         Single word only!</span>
16329
16330         <tt>text = {{text}}</tt><br/>
16331         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16332         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16333         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16334         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16335         </form>
16336         </file>
16337         <file name="protractor.js" type="protractor">
16338         var text = element(by.binding('text'));
16339         var valid = element(by.binding('myForm.input.$valid'));
16340         var input = element(by.model('text'));
16341
16342         it('should initialize to model', function() {
16343            expect(text.getText()).toContain('guest');
16344            expect(valid.getText()).toContain('true');
16345          });
16346
16347         it('should be invalid if empty', function() {
16348            input.clear();
16349            input.sendKeys('');
16350
16351            expect(text.getText()).toEqual('text =');
16352            expect(valid.getText()).toContain('false');
16353          });
16354
16355         it('should be invalid if multi word', function() {
16356            input.clear();
16357            input.sendKeys('hello world');
16358
16359            expect(valid.getText()).toContain('false');
16360          });
16361         </file>
16362         </example>
16363         */
16364        'text': textInputType,
16365
16366
16367        /**
16368         * @ngdoc input
16369         * @name input[number]
16370         *
16371         * @description
16372         * Text input with number validation and transformation. Sets the `number` validation
16373         * error if not a valid number.
16374         *
16375         * @param {string} ngModel Assignable angular expression to data-bind to.
16376         * @param {string=} name Property name of the form under which the control is published.
16377         * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
16378         * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
16379         * @param {string=} required Sets `required` validation error key if the value is not entered.
16380         * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16381         *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16382         *    `required` when you want to data-bind to the `required` attribute.
16383         * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16384         *    minlength.
16385         * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16386         *    maxlength.
16387         * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16388         *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16389         *    patterns defined as scope expressions.
16390         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16391         *    interaction with the input element.
16392         *
16393         * @example
16394         <example name="number-input-directive">
16395         <file name="index.jsp">
16396         <script>
16397         function Ctrl($scope) {
16398             $scope.value = 12;
16399           }
16400         </script>
16401         <form name="myForm" ng-controller="Ctrl">
16402         Number: <input type="number" name="input" ng-model="value"
16403         min="0" max="99" required>
16404         <span class="error" ng-show="myForm.input.$error.required">
16405         Required!</span>
16406         <span class="error" ng-show="myForm.input.$error.number">
16407         Not valid number!</span>
16408         <tt>value = {{value}}</tt><br/>
16409         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16410         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16411         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16412         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16413         </form>
16414         </file>
16415         <file name="protractor.js" type="protractor">
16416         var value = element(by.binding('value'));
16417         var valid = element(by.binding('myForm.input.$valid'));
16418         var input = element(by.model('value'));
16419
16420         it('should initialize to model', function() {
16421            expect(value.getText()).toContain('12');
16422            expect(valid.getText()).toContain('true');
16423          });
16424
16425         it('should be invalid if empty', function() {
16426            input.clear();
16427            input.sendKeys('');
16428            expect(value.getText()).toEqual('value =');
16429            expect(valid.getText()).toContain('false');
16430          });
16431
16432         it('should be invalid if over max', function() {
16433            input.clear();
16434            input.sendKeys('123');
16435            expect(value.getText()).toEqual('value =');
16436            expect(valid.getText()).toContain('false');
16437          });
16438         </file>
16439         </example>
16440         */
16441        'number': numberInputType,
16442
16443
16444        /**
16445         * @ngdoc input
16446         * @name input[url]
16447         *
16448         * @description
16449         * Text input with URL validation. Sets the `url` validation error key if the content is not a
16450         * valid URL.
16451         *
16452         * @param {string} ngModel Assignable angular expression to data-bind to.
16453         * @param {string=} name Property name of the form under which the control is published.
16454         * @param {string=} required Sets `required` validation error key if the value is not entered.
16455         * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16456         *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16457         *    `required` when you want to data-bind to the `required` attribute.
16458         * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16459         *    minlength.
16460         * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16461         *    maxlength.
16462         * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16463         *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16464         *    patterns defined as scope expressions.
16465         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16466         *    interaction with the input element.
16467         *
16468         * @example
16469         <example name="url-input-directive">
16470         <file name="index.jsp">
16471         <script>
16472         function Ctrl($scope) {
16473             $scope.text = 'http://google.com';
16474           }
16475         </script>
16476         <form name="myForm" ng-controller="Ctrl">
16477         URL: <input type="url" name="input" ng-model="text" required>
16478         <span class="error" ng-show="myForm.input.$error.required">
16479         Required!</span>
16480         <span class="error" ng-show="myForm.input.$error.url">
16481         Not valid url!</span>
16482         <tt>text = {{text}}</tt><br/>
16483         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16484         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16485         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16486         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16487         <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
16488         </form>
16489         </file>
16490         <file name="protractor.js" type="protractor">
16491         var text = element(by.binding('text'));
16492         var valid = element(by.binding('myForm.input.$valid'));
16493         var input = element(by.model('text'));
16494
16495         it('should initialize to model', function() {
16496            expect(text.getText()).toContain('http://google.com');
16497            expect(valid.getText()).toContain('true');
16498          });
16499
16500         it('should be invalid if empty', function() {
16501            input.clear();
16502            input.sendKeys('');
16503
16504            expect(text.getText()).toEqual('text =');
16505            expect(valid.getText()).toContain('false');
16506          });
16507
16508         it('should be invalid if not url', function() {
16509            input.clear();
16510            input.sendKeys('box');
16511
16512            expect(valid.getText()).toContain('false');
16513          });
16514         </file>
16515         </example>
16516         */
16517        'url': urlInputType,
16518
16519
16520        /**
16521         * @ngdoc input
16522         * @name input[email]
16523         *
16524         * @description
16525         * Text input with email validation. Sets the `email` validation error key if not a valid email
16526         * address.
16527         *
16528         * @param {string} ngModel Assignable angular expression to data-bind to.
16529         * @param {string=} name Property name of the form under which the control is published.
16530         * @param {string=} required Sets `required` validation error key if the value is not entered.
16531         * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
16532         *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
16533         *    `required` when you want to data-bind to the `required` attribute.
16534         * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
16535         *    minlength.
16536         * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
16537         *    maxlength.
16538         * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
16539         *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
16540         *    patterns defined as scope expressions.
16541         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16542         *    interaction with the input element.
16543         *
16544         * @example
16545         <example name="email-input-directive">
16546         <file name="index.jsp">
16547         <script>
16548         function Ctrl($scope) {
16549             $scope.text = '[email protected]';
16550         }
16551         </script>
16552         <form name="myForm" ng-controller="Ctrl">
16553         Email: <input type="email" name="input" ng-model="text" required>
16554         <span class="error" ng-show="myForm.input.$error.required">
16555         Required!</span>
16556         <span class="error" ng-show="myForm.input.$error.email">
16557         Not valid email!</span>
16558         <tt>text = {{text}}</tt><br/>
16559         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
16560         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
16561         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
16562         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
16563         <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
16564         </form>
16565         </file>
16566         <file name="protractor.js" type="protractor">
16567         var text = element(by.binding('text'));
16568         var valid = element(by.binding('myForm.input.$valid'));
16569         var input = element(by.model('text'));
16570
16571         it('should initialize to model', function() {
16572            expect(text.getText()).toContain('[email protected]');
16573         expect(valid.getText()).toContain('true');
16574         });
16575
16576         it('should be invalid if empty', function() {
16577            input.clear();
16578            input.sendKeys('');
16579            expect(text.getText()).toEqual('text =');
16580            expect(valid.getText()).toContain('false');
16581          });
16582
16583         it('should be invalid if not email', function() {
16584            input.clear();
16585            input.sendKeys('xxx');
16586
16587            expect(valid.getText()).toContain('false');
16588          });
16589         </file>
16590         </example>
16591         */
16592        'email': emailInputType,
16593
16594
16595        /**
16596         * @ngdoc input
16597         * @name input[radio]
16598         *
16599         * @description
16600         * HTML radio button.
16601         *
16602         * @param {string} ngModel Assignable angular expression to data-bind to.
16603         * @param {string} value The value to which the expression should be set when selected.
16604         * @param {string=} name Property name of the form under which the control is published.
16605         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16606         *    interaction with the input element.
16607         * @param {string} ngValue Angular expression which sets the value to which the expression should
16608         *    be set when selected.
16609         *
16610         * @example
16611         <example name="radio-input-directive">
16612         <file name="index.jsp">
16613         <script>
16614         function Ctrl($scope) {
16615             $scope.color = 'blue';
16616             $scope.specialValue = {
16617               "id": "12345",
16618               "value": "green"
16619             };
16620           }
16621         </script>
16622         <form name="myForm" ng-controller="Ctrl">
16623         <input type="radio" ng-model="color" value="red">  Red <br/>
16624         <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
16625         <input type="radio" ng-model="color" value="blue"> Blue <br/>
16626         <tt>color = {{color | json}}</tt><br/>
16627         </form>
16628         Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
16629         </file>
16630         <file name="protractor.js" type="protractor">
16631         it('should change state', function() {
16632            var color = element(by.binding('color'));
16633
16634            expect(color.getText()).toContain('blue');
16635
16636            element.all(by.model('color')).get(0).click();
16637
16638            expect(color.getText()).toContain('red');
16639          });
16640         </file>
16641         </example>
16642         */
16643        'radio': radioInputType,
16644
16645
16646        /**
16647         * @ngdoc input
16648         * @name input[checkbox]
16649         *
16650         * @description
16651         * HTML checkbox.
16652         *
16653         * @param {string} ngModel Assignable angular expression to data-bind to.
16654         * @param {string=} name Property name of the form under which the control is published.
16655         * @param {string=} ngTrueValue The value to which the expression should be set when selected.
16656         * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
16657         * @param {string=} ngChange Angular expression to be executed when input changes due to user
16658         *    interaction with the input element.
16659         *
16660         * @example
16661         <example name="checkbox-input-directive">
16662         <file name="index.jsp">
16663         <script>
16664         function Ctrl($scope) {
16665             $scope.value1 = true;
16666             $scope.value2 = 'YES'
16667           }
16668         </script>
16669         <form name="myForm" ng-controller="Ctrl">
16670         Value1: <input type="checkbox" ng-model="value1"> <br/>
16671         Value2: <input type="checkbox" ng-model="value2"
16672         ng-true-value="YES" ng-false-value="NO"> <br/>
16673         <tt>value1 = {{value1}}</tt><br/>
16674         <tt>value2 = {{value2}}</tt><br/>
16675         </form>
16676         </file>
16677         <file name="protractor.js" type="protractor">
16678         it('should change state', function() {
16679            var value1 = element(by.binding('value1'));
16680            var value2 = element(by.binding('value2'));
16681
16682            expect(value1.getText()).toContain('true');
16683            expect(value2.getText()).toContain('YES');
16684
16685            element(by.model('value1')).click();
16686            element(by.model('value2')).click();
16687
16688            expect(value1.getText()).toContain('false');
16689            expect(value2.getText()).toContain('NO');
16690          });
16691         </file>
16692         </example>
16693         */
16694        'checkbox': checkboxInputType,
16695
16696        'hidden': noop,
16697        'button': noop,
16698        'submit': noop,
16699        'reset': noop,
16700        'file': noop
16701    };
16702
16703// A helper function to call $setValidity and return the value / undefined,
16704// a pattern that is repeated a lot in the input validation logic.
16705    function validate(ctrl, validatorName, validity, value) {
16706        ctrl.$setValidity(validatorName, validity);
16707        return validity ? value : undefined;
16708    }
16709
16710
16711    function addNativeHtml5Validators(ctrl, validatorName, element) {
16712        var validity = element.prop('validity');
16713        if (isObject(validity)) {
16714            var validator = function (value) {
16715                // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
16716                // perform the required validation)
16717                if (!ctrl.$error[validatorName] && (validity.badInput || validity.customError ||
16718                    validity.typeMismatch) && !validity.valueMissing) {
16719                    ctrl.$setValidity(validatorName, false);
16720                    return;
16721                }
16722                return value;
16723            };
16724            ctrl.$parsers.push(validator);
16725        }
16726    }
16727
16728    function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16729        var validity = element.prop('validity');
16730        // In composition mode, users are still inputing intermediate text buffer,
16731        // hold the listener until composition is done.
16732        // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
16733        if (!$sniffer.android) {
16734            var composing = false;
16735
16736            element.on('compositionstart', function (data) {
16737                composing = true;
16738            });
16739
16740            element.on('compositionend', function () {
16741                composing = false;
16742                listener();
16743            });
16744        }
16745
16746        var listener = function () {
16747            if (composing) return;
16748            var value = element.val();
16749
16750            // By default we will trim the value
16751            // If the attribute ng-trim exists we will avoid trimming
16752            // e.g. <input ng-model="foo" ng-trim="false">
16753            if (toBoolean(attr.ngTrim || 'T')) {
16754                value = trim(value);
16755            }
16756
16757            if (ctrl.$viewValue !== value ||
16758                // If the value is still empty/falsy, and there is no `required` error, run validators
16759                // again. This enables HTML5 constraint validation errors to affect Angular val
16759idation
16760                // even when the first character entered causes an error.
16761                (validity && value === '' && !validity.valueMissing)) {
16762                if (scope.$$phase) {
16763                    ctrl.$setViewValue(value);
16764                } else {
16765                    scope.$apply(function () {
16766                        ctrl.$setViewValue(value);
16767                    });
16768                }
16769            }
16770        };
16771
16772        // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
16773        // input event on backspace, delete or cut
16774        if ($sniffer.hasEvent('input')) {
16775            element.on('input', listener);
16776        } else {
16777            var timeout;
16778
16779            var deferListener = function () {
16780                if (!timeout) {
16781                    timeout = $browser.defer(function () {
16782                        listener();
16783                        timeout = null;
16784                    });
16785                }
16786            };
16787
16788            element.on('keydown', function (event) {
16789                var key = event.keyCode;
16790
16791                // ignore
16792                //    command            modifiers                   arrows
16793                if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
16794
16795                deferListener();
16796            });
16797
16798            // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
16799            if ($sniffer.hasEvent('paste')) {
16800                element.on('paste cut', deferListener);
16801            }
16802        }
16803
16804        // if user paste into input using mouse on older browser
16805        // or form autocomplete on newer browser, we need "change" event to catch it
16806        element.on('change', listener);
16807
16808        ctrl.$render = function () {
16809            element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
16810        };
16811
16812        // pattern validator
16813        var pattern = attr.ngPattern,
16814            patternValidator,
16815            match;
16816
16817        if (pattern) {
16818            var validateRegex = function (regexp, value) {
16819                return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
16820            };
16821            match = pattern.match(/^\/(.*)\/([gim]*)$/);
16822            if (match) {
16823                pattern = new RegExp(match[1], match[2]);
16824                patternValidator = function (value) {
16825                    return validateRegex(pattern, value);
16826                };
16827            } else {
16828                patternValidator = function (value) {
16829                    var patternObj = scope.$eval(pattern);
16830
16831                    if (!patternObj || !patternObj.test) {
16832                        throw minErr('ngPattern')('noregexp',
16833                            'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
16834                            patternObj, startingTag(element));
16835                    }
16836                    return validateRegex(patternObj, value);
16837                };
16838            }
16839
16840            ctrl.$formatters.push(patternValidator);
16841            ctrl.$parsers.push(patternValidator);
16842        }
16843
16844        // min length validator
16845        if (attr.ngMinlength) {
16846            var minlength = int(attr.ngMinlength);
16847            var minLengthValidator = function (value) {
16848                return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
16849            };
16850
16851            ctrl.$parsers.push(minLengthValidator);
16852            ctrl.$formatters.push(minLengthValidator);
16853        }
16854
16855        // max length validator
16856        if (attr.ngMaxlength) {
16857            var maxlength = int(attr.ngMaxlength);
16858            var maxLengthValidator = function (value) {
16859                return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
16860            };
16861
16862            ctrl.$parsers.push(maxLengthValidator);
16863            ctrl.$formatters.push(maxLengthValidator);
16864        }
16865    }
16866
16867    function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16868        textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16869
16870        ctrl.$parsers.push(function (value) {
16871            var empty = ctrl.$isEmpty(value);
16872            if (empty || NUMBER_REGEXP.test(value)) {
16873                ctrl.$setValidity('number', true);
16874                return value === '' ? null : (empty ? value : parseFloat(value));
16875            } else {
16876                ctrl.$setValidity('number', false);
16877                return undefined;
16878            }
16879        });
16880
16881        addNativeHtml5Validators(ctrl, 'number', element);
16882
16883        ctrl.$formatters.push(function (value) {
16884            return ctrl.$isEmpty(value) ? '' : '' + value;
16885        });
16886
16887        if (attr.min) {
16888            var minValidator = function (value) {
16889                var min = parseFloat(attr.min);
16890                return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
16891            };
16892
16893            ctrl.$parsers.push(minValidator);
16894            ctrl.$formatters.push(minValidator);
16895        }
16896
16897        if (attr.max) {
16898            var maxValidator = function (value) {
16899                var max = parseFloat(attr.max);
16900                return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
16901            };
16902
16903            ctrl.$parsers.push(maxValidator);
16904            ctrl.$formatters.push(maxValidator);
16905        }
16906
16907        ctrl.$formatters.push(function (value) {
16908            return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
16909        });
16910    }
16911
16912    function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16913        textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16914
16915        var urlValidator = function (value) {
16916            return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
16917        };
16918
16919        ctrl.$formatters.push(urlValidator);
16920        ctrl.$parsers.push(urlValidator);
16921    }
16922
16923    function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16924        textInputType(scope, element, attr, ctrl, $sniffer, $browser);
16925
16926        var emailValidator = function (value) {
16927            return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
16928        };
16929
16930        ctrl.$formatters.push(emailValidator);
16931        ctrl.$parsers.push(emailValidator);
16932    }
16933
16934    function radioInputType(scope, element, attr, ctrl) {
16935        // make the name unique, if not defined
16936        if (isUndefined(attr.name)) {
16937            element.attr('name', nextUid());
16938        }
16939
16940        element.on('click', function () {
16941            if (element[0].checked) {
16942                scope.$apply(function () {
16943                    ctrl.$setViewValue(attr.value);
16944                });
16945            }
16946        });
16947
16948        ctrl.$render = function () {
16949            var value = attr.value;
16950            element[0].checked = (value == ctrl.$viewValue);
16951        };
16952
16953        attr.$observe('value', ctrl.$render);
16954    }
16955
16956    function checkboxInputType(scope, element, attr, ctrl) {
16957        var trueValue = attr.ngTrueValue,
16958            falseValue = attr.ngFalseValue;
16959
16960        if (!isString(trueValue)) trueValue = true;
16961        if (!isString(falseValue)) falseValue = false;
16962
16963        element.on('click', function () {
16964            scope.$apply(function () {
16965                ctrl.$setViewValue(element[0].checked);
16966            });
16967        });
16968
16969        ctrl.$render = function () {
16970            element[0].checked = ctrl.$viewValue;
16971        };
16972
16973        // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
16974        ctrl.$isEmpty = function (value) {
16975            return value !== trueValue;
16976        };
16977
16978        ctrl.$formatters.push(function (value) {
16979            return value === trueValue;
16980        });
16981
16982        ctrl.$parsers.push(function (value) {
16983            return value ? trueValue : falseValue;
16984        });
16985    }
16986
16987
16988    /**
16989     * @ngdoc directive
16990     * @name textarea
16991     * @restrict E
16992     *
16993     * @description
16994     * HTML textarea element control with angular data-binding. The data-binding and validation
16995     * properties of this element are exactly the same as those of the
16996     * {@link ng.directive:input input element}.
16997     *
16998     * @param {string} ngModel Assignable angular expression to data-bind to.
16999     * @param {string=} name Property name of the form under which the control is published.
17000     * @param {string=} required Sets `required` validation error key if the value is not entered.
17001     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
17002     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
17003     *    `required` when you want to data-bind to the `required` attribute.
17004     * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17005     *    minlength.
17006     * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17007     *    maxlength.
17008     * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17009     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17010     *    patterns defined as scope expressions.
17011     * @param {string=} ngChange Angular expression to be executed when input changes due to user
17012     *    interaction with the input element.
17013     */
17014
17015
17016    /**
17017     * @ngdoc directive
17018     * @name input
17019     * @restrict E
17020     *
17021     * @description
17022     * HTML input element control with angular data-binding. Input control follows HTML5 input types
17023     * and polyfills the HTML5 validation behavior for older browsers.
17024     *
17025     * @param {string} ngModel Assignable angular expression to data-bind to.
17026     * @param {string=} name Property name of the form under which the control is published.
17027     * @param {string=} required Sets `required` validation error key if the value is not entered.
17028     * @param {boolean=} ngRequired Sets `required` attribute if set to true
17029     * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
17030     *    minlength.
17031     * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
17032     *    maxlength.
17033     * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
17034     *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
17035     *    patterns defined as scope expressions.
17036     * @param {string=} ngChange Angular expression to be executed when input changes due to user
17037     *    interaction with the input element.
17038     *
17039     * @example
17040     <example name="input-directive">
17041     <file name="index.jsp">
17042     <script>
17043     function Ctrl($scope) {
17044           $scope.user = {name: 'guest', last: 'visitor'};
17045         }
17046     </script>
17047     <div ng-controller="Ctrl">
17048     <form name="myForm">
17049     User name: <input type="text" name="userName" ng-model="user.name" required>
17050     <span class="error" ng-show="myForm.userName.$error.required">
17051     Required!</span><br>
17052     Last name: <input type="text" name="lastName" ng-model="user.last"
17053     ng-minlength="3" ng-maxlength="10">
17054     <span class="error" ng-show="myForm.lastName.$error.minlength">
17055     Too short!</span>
17056     <span class="error" ng-show="myForm.lastName.$error.maxlength">
17057     Too long!</span><br>
17058     </form>
17059     <hr>
17060     <tt>user = {{user}}</tt><br/>
17061     <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
17062     <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
17063     <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
17064     <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
17065     <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
17066     <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
17067     <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
17068     <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
17069     </div>
17070     </file>
17071     <file name="protractor.js" type="protractor">
17072     var user = element(by.binding('{{user}}'));
17073     var userNameValid = element(by.binding('myForm.userName.$valid'));
17074     var lastNameValid = element(by.binding('myForm.lastName.$valid'));
17075     var lastNameError = element(by.binding('myForm.lastName.$error'));
17076     var formValid = element(by.binding('myForm.$valid'));
17077     var userNameInput = element(by.model('user.name'));
17078     var userLastInput = element(by.model('user.last'));
17079
17080     it('should initialize to model', function() {
17081          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
17082          expect(userNameValid.getText()).toContain('true');
17083          expect(formValid.getText()).toContain('true');
17084        });
17085
17086     it('should be invalid if empty when required', function() {
17087          userNameInput.clear();
17088          userNameInput.sendKeys('');
17089
17090          expect(user.getText()).toContain('{"last":"visitor"}');
17091          expect(userNameValid.getText()).toContain('false');
17092          expect(formValid.getText()).toContain('false');
17093        });
17094
17095     it('should be valid if empty when min length is set', function() {
17096          userLastInput.clear();
17097          userLastInput.sendKeys('');
17098
17099          expect(user.getText()).toContain('{"name":"guest","last":""}');
17100          expect(lastNameValid.getText()).toContain('true');
17101          expect(formValid.getText()).toContain('true');
17102        });
17103
17104     it('should be invalid if less than required min length', function() {
17105          userLastInput.clear();
17106          userLastInput.sendKeys('xx');
17107
17108          expect(user.getText()).toContain('{"name":"guest"}');
17109          expect(lastNameValid.getText()).toContain('false');
17110          expect(lastNameError.getText()).toContain('minlength');
17111          expect(formValid.getText()).toContain('false');
17112        });
17113
17114     it('should be invalid if longer than max length', function() {
17115          userLastInput.clear();
17116          userLastInput.sendKeys('some ridiculously long name');
17117
17118          expect(user.getText()).toContain('{"name":"guest"}');
17119          expect(lastNameValid.getText()).toContain('false');
17120          expect(lastNameError.getText()).toContain('maxlength');
17121          expect(formValid.getText()).toContain('false');
17122        });
17123     </file>
17124     </example>
17125     */
17126    var inputDirective = ['$browser', '$sniffer', function ($browser, $sniffer) {
17127        return {
17128            restrict: 'E',
17129            require: '?ngModel',
17130            link: function (scope, element, attr, ctrl) {
17131                if (ctrl) {
17132                    (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
17133                        $browser);
17134                }
17135            }
17136        };
17137    }];
17138
17139    var VALID_CLASS = 'ng-valid',
17140        INVALID_CLASS = 'ng-invalid',
17141        PRISTINE_CLASS = 'ng-pristine',
17142        DIRTY_CLASS = 'ng-dirty';
17143
17144    /**
17145     * @ngdoc type
17146     * @name ngModel.NgModelController
17147     *
17148     * @property {string} $viewValue Actual string value in the view.
17149     * @property {*} $modelValue The value in the model, that the control is bound to.
17150     * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
17151     the control reads value from the DOM.  Each function is called, in turn, passing the value
17152     through to the next. The last return value is used to populate the model.
17153     Used to sanitize / convert the value as well as validation. For validation,
17154     the parsers should update the validity state using
17155     {@link ngModel.NgModelController#$setValidity $setValidity()},
17156     and return `undefined` for invalid values.
17157
17158     *
17159     * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
17160     the model value changes. Each function is called, in turn, passing the value through to the
17161     next. Used to format / convert values for display in the control and validation.
17162     *      ```js
17163     *      function formatter(value) {
17164 *        if (value) {
17165 *          return value.toUpperCase();
17166 *        }
17167 *      }
17168     *      ngModel.$formatters.push(formatter);
17169     *      ```
17170     *
17171     * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
17172     *     view value has changed. It is called with no arguments, and its return value is ignored.
17173     *     This can be used in place of additional $watches against the model value.
17174     *
17175     * @property {Object} $error An object hash with all errors as keys.
17176     *
17177     * @property {boolean} $pristine True if user has not interacted with the control yet.
17178     * @property {boolean} $dirty True if user has already interacted with the control.
17179     * @property {boolean} $valid True if there is no error.
17180     * @property {boolean} $invalid True if at least one error on the control.
17181     *
17182     * @description
17183     *
17184     * `NgModelController` provides API for the `ng-model` directive. The controller contains
17185     * services for data-binding, validation, CSS updates, and value formatting and parsing. It
17186     * purposefully does not contain any logic which deals with DOM rendering or listening to
17187     * DOM events. Such DOM related logic should be provided by other directives which make use of
17188     * `NgModelController` for data-binding.
17189     *
17190     * ## Custom Control Example
17191     * This example shows how to use `NgModelController` with a custom control to achieve
17192     * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
17193     * collaborate together to achieve the desired result.
17194     *
17195     * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
17196     * contents be edited in place by the user.  This will not work on older browsers.
17197     *
17198     * <example name="NgModelController" module="customControl">
17199     <file name="style.css">
17200     [contenteditable] {
17201        border: 1px solid black;
17202        background-color: white;
17203        min-height: 20px;
17204      }
17205
17206     .ng-invalid {
17207        border: 1px solid red;
17208      }
17209
17210     </file>
17211     <file name="script.js">
17212     angular.module('customControl', []).
17213     directive('contenteditable', function() {
17214          return {
17215            restrict: 'A', // only activate on element attribute
17216            require: '?ngModel', // get a hold of NgModelController
17217            link: function(scope, element, attrs, ngModel) {
17218              if(!ngModel) return; // do nothing if no ng-model
17219
17220              // Specify how UI should be updated
17221              ngModel.$render = function() {
17222                element.html(ngModel.$viewValue || '');
17223              };
17224
17225              // Listen for change events to enable binding
17226              element.on('blur keyup change', function() {
17227                scope.$apply(read);
17228              });
17229              read(); // initialize
17230
17231              // Write data to the model
17232              function read() {
17233                var html = element.html();
17234                // When we clear the content editable the browser leaves a <br> behind
17235                // If strip-br attribute is provided then we strip this out
17236                if( attrs.stripBr && html == '<br>' ) {
17237                  html = '';
17238                }
17239                ngModel.$setViewValue(html);
17240              }
17241            }
17242          };
17243        });
17244     </file>
17245     <file name="index.jsp">
17246     <form name="myForm">
17247     <div contenteditable
17248     name="myWidget" ng-model="userContent"
17249     strip-br="true"
17250     required>Change me!</div>
17251     <span ng-show="myForm.myWidget.$error.required">Required!</span>
17252     <hr>
17253     <textarea ng-model="userContent"></textarea>
17254     </form>
17255     </file>
17256     <file name="protractor.js" type="protractor">
17257     it('should data-bind and become invalid', function() {
17258      if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
17259        // SafariDriver can't handle contenteditable
17260        // and Firefox driver can't clear contenteditables very well
17261        return;
17262      }
17263      var contentEditable = element(by.css('[contenteditable]'));
17264      var content = 'Change me!';
17265
17266      expect(contentEditable.getText()).toEqual(content);
17267
17268      contentEditable.clear();
17269      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
17270      expect(contentEditable.getText()).toEqual('');
17271      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
17272    });
17273     </file>
17274     * </example>
17275     *
17276     *
17277     */
17278    var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate',
17279        function ($scope, $exceptionHandler, $attr, $element, $parse, $animate) {
17280            this.$viewValue = Number.NaN;
17281            this.$modelValue = Number.NaN;
17282            this.$parsers = [];
17283            this.$formatters = [];
17284            this.$viewChangeListeners = [];
17285            this.$pristine = true;
17286            this.$dirty = false;
17287            this.$valid = true;
17288            this.$invalid = false;
17289            this.$name = $attr.name;
17290
17291            var ngModelGet = $parse($attr.ngModel),
17292                ngModelSet = ngModelGet.assign;
17293
17294            if (!ngModelSet) {
17295                throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
17296                    $attr.ngModel, startingTag($element));
17297            }
17298
17299            /**
17300             * @ngdoc method
17301             * @name ngModel.NgModelController#$render
17302             *
17303             * @description
17304             * Called when the view needs to be updated. It is expected that the user of the ng-model
17305             * directive will implement this method.
17306             */
17307            this.$render = noop;
17308
17309            /**
17310             * @ngdoc method
17311             * @name ngModel.NgModelController#$isEmpty
17312             *
17313             * @description
17314             * This is called when we need to determine if the value of the input is empty.
17315             *
17316             * For instance, the required directive does this to work out if the input has data or not.
17317             * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
17318             *
17319             * You can override this for input directives whose concept of being empty is different to the
17320             * default. The `checkboxInputType` directive does this because in 
17320its case a value of `false`
17321             * implies empty.
17322             *
17323             * @param {*} value Reference to check.
17324             * @returns {boolean} True if `value` is empty.
17325             */
17326            this.$isEmpty = function (value) {
17327                return isUndefined(value) || value === '' || value === null || value !== value;
17328            };
17329
17330            var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
17331                invalidCount = 0, // used to easily determine if we are valid
17332                $error = this.$error = {}; // keep invalid keys here
17333
17334
17335            // Setup initial state of the control
17336            $element.addClass(PRISTINE_CLASS);
17337            toggleValidCss(true);
17338
17339            // convenience method for easy toggling of classes
17340            function toggleValidCss(isValid, validationErrorKey) {
17341                validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
17342                $animate.removeClass($element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
17343                $animate.addClass($element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
17344            }
17345
17346            /**
17347             * @ngdoc method
17348             * @name ngModel.NgModelController#$setValidity
17349             *
17350             * @description
17351             * Change the validity state, and notifies the form when the control changes validity. (i.e. it
17352             * does not notify form if given validator is already marked as invalid).
17353             *
17354             * This method should be called by validators - i.e. the parser or formatter functions.
17355             *
17356             * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
17357             *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
17358             *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
17359             *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
17360             *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
17361             * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
17362             */
17363            this.$setValidity = function (validationErrorKey, isValid) {
17364                // Purposeful use of ! here to cast isValid to boolean in case it is undefined
17365                // jshint -W018
17366                if ($error[validationErrorKey] === !isValid) return;
17367                // jshint +W018
17368
17369                if (isValid) {
17370                    if ($error[validationErrorKey]) invalidCount--;
17371                    if (!invalidCount) {
17372                        toggleValidCss(true);
17373                        this.$valid = true;
17374                        this.$invalid = false;
17375                    }
17376                } else {
17377                    toggleValidCss(false);
17378                    this.$invalid = true;
17379                    this.$valid = false;
17380                    invalidCount++;
17381                }
17382
17383                $error[validationErrorKey] = !isValid;
17384                toggleValidCss(isValid, validationErrorKey);
17385
17386                parentForm.$setValidity(validationErrorKey, isValid, this);
17387            };
17388
17389            /**
17390             * @ngdoc method
17391             * @name ngModel.NgModelController#$setPristine
17392             *
17393             * @description
17394             * Sets the control to its pristine state.
17395             *
17396             * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
17397             * state (ng-pristine class).
17398             */
17399            this.$setPristine = function () {
17400                this.$dirty = false;
17401                this.$pristine = true;
17402                $animate.removeClass($element, DIRTY_CLASS);
17403                $animate.addClass($element, PRISTINE_CLASS);
17404            };
17405
17406            /**
17407             * @ngdoc method
17408             * @name ngModel.NgModelController#$setViewValue
17409             *
17410             * @description
17411             * Update the view value.
17412             *
17413             * This method should be called when the view value changes, typically from within a DOM event handler.
17414             * For example {@link ng.directive:input input} and
17415             * {@link ng.directive:select select} directives call it.
17416             *
17417             * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
17418             * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
17419             * `$modelValue` and the **expression** specified in the `ng-model` attribute.
17420             *
17421             * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
17422             *
17423             * Note that calling this function does not trigger a `$digest`.
17424             *
17425             * @param {string} value Value from the view.
17426             */
17427            this.$setViewValue = function (value) {
17428                this.$viewValue = value;
17429
17430                // change to dirty
17431                if (this.$pristine) {
17432                    this.$dirty = true;
17433                    this.$pristine = false;
17434                    $animate.removeClass($element, PRISTINE_CLASS);
17435                    $animate.addClass($element, DIRTY_CLASS);
17436                    parentForm.$setDirty();
17437                }
17438
17439                forEach(this.$parsers, function (fn) {
17440                    value = fn(value);
17441                });
17442
17443                if (this.$modelValue !== value) {
17444                    this.$modelValue = value;
17445                    ngModelSet($scope, value);
17446                    forEach(this.$viewChangeListeners, function (listener) {
17447                        try {
17448                            listener();
17449                        } catch (e) {
17450                            $exceptionHandler(e);
17451                        }
17452                    });
17453                }
17454            };
17455
17456            // model -> value
17457            var ctrl = this;
17458
17459            $scope.$watch(function ngModelWatch() {
17460                var value = ngModelGet($scope);
17461
17462                // if scope model value and ngModel value are out of sync
17463                if (ctrl.$modelValue !== value) {
17464
17465                    var formatters = ctrl.$formatters,
17466                        idx = formatters.length;
17467
17468                    ctrl.$modelValue = value;
17469                    while (idx--) {
17470                        value = formatters[idx](value);
17471                    }
17472
17473                    if (ctrl.$viewValue !== value) {
17474                        ctrl.$viewValue = value;
17475                        ctrl.$render();
17476                    }
17477                }
17478
17479                return value;
17480            });
17481        }];
17482
17483
17484    /**
17485     * @ngdoc directive
17486     * @name ngModel
17487     *
17488     * @element input
17489     *
17490     * @description
17491     * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
17492     * property on the scope using {@link ngModel.NgModelController NgModelController},
17493     * which is created and exposed by this directive.
17494     *
17495     * `ngModel` is responsible for:
17496     *
17497     * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
17498     *   require.
17499     * - Providing validation behavior (i.e. required, number, email, url).
17500     * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
17501     * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`) including animations.
17502     * - Registering the control with its parent {@link ng.directive:form form}.
17503     *
17504     * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
17505     * current scope. If the property doesn't already exist on this scope, it will be created
17506     * implicitly and added to the scope.
17507     *
17508     * For best practices on using `ngModel`, see:
17509     *
17510     *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
17511     *
17512     * For basic examples, how to use `ngModel`, see:
17513     *
17514     *  - {@link ng.directive:input input}
17515     *    - {@link input[text] text}
17516     *    - {@link input[checkbox] checkbox}
17517     *    - {@link input[radio] radio}
17518     *    - {@link input[number] number}
17519     *    - {@link input[email] email}
17520     *    - {@link input[url] url}
17521     *  - {@link ng.directive:select select}
17522     *  - {@link ng.directive:textarea textarea}
17523     *
17524     * # CSS classes
17525     * The following CSS classes are added and removed on the associated input/select/textarea element
17526     * depending on the validity of the model.
17527     *
17528     *  - `ng-valid` is set if the model is valid.
17529     *  - `ng-invalid` is set if the model is invalid.
17530     *  - `ng-pristine` is set if the model is pristine.
17531     *  - `ng-dirty` is set if the model is dirty.
17532     *
17533     * Keep in mind that ngAnimate can detect each of these classes when added and removed.
17534     *
17535     * ## Animation Hooks
17536     *
17537     * Animations within models are triggered when any of the associated CSS classes are added and removed
17538     * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
17539     * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
17540     * The animations that are triggered within ngModel are similar to how they work in ngClass and
17541     * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
17542     *
17543     * The following example shows a simple way to utilize CSS transitions to style an input element
17544     * that has been rendered as invalid after it has been validated:
17545     *
17546     * <pre>
17547     * //be sure to include ngAnimate as a module to hook into more
17548     * //advanced animations
17549     * .my-input {
17550 *   transition:0.5s linear all;
17551 *   background: white;
17552 * }
17553     * .my-input.ng-invalid {
17554 *   background: red;
17555 *   color:white;
17556 * }
17557     * </pre>
17558     *
17559     * @example
17560     * <example deps="angular-animate.js" animations="true" fixBase="true">
17561     <file name="index.jsp">
17562     <script>
17563     function Ctrl($scope) {
17564          $scope.val = '1';
17565        }
17566     </script>
17567     <style>
17568     .my-input {
17569           -webkit-transition:all linear 0.5s;
17570           transition:all linear 0.5s;
17571           background: transparent;
17572         }
17573     .my-input.ng-invalid {
17574           color:white;
17575           background: red;
17576         }
17577     </style>
17578     Update input to see transitions when valid/invalid.
17579     Integer is a valid value.
17580     <form name="testForm" ng-controller="Ctrl">
17581     <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
17582     </form>
17583     </file>
17584     * </example>
17585     */
17586    var ngModelDirective = function () {
17587        return {
17588            require: ['ngModel', '^?form'],
17589            controller: NgModelController,
17590            link: function (scope, element, attr, ctrls) {
17591                // notify others, especially parent forms
17592
17593                var modelCtrl = ctrls[0],
17594                    formCtrl = ctrls[1] || nullFormCtrl;
17595
17596                formCtrl.$addControl(modelCtrl);
17597
17598                scope.$on('$destroy', function () {
17599                    formCtrl.$removeControl(modelCtrl);
17600                });
17601            }
17602        };
17603    };
17604
17605
17606    /**
17607     * @ngdoc directive
17608     * @name ngChange
17609     *
17610     * @description
17611     * Evaluate the given expression when the user changes the input.
17612     * The expression is evaluated immediately, unlike the JavaScript onchange event
17613     * which only triggers at the end of a change (usually, when the user leaves the
17614     * form element or presses the return key).
17615     * The expression is not evaluated when the value change is coming from the model.
17616     *
17617     * Note, this directive requires `ngModel` to be present.
17618     *
17619     * @element input
17620     * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
17621     * in input value.
17622     *
17623     * @example
17624     * <example name="ngChange-directive">
17625     *   <file name="index.jsp">
17626     *     <script>
17627     *       function Controller($scope) {
17628 *         $scope.counter = 0;
17629 *         $scope.change = function() {
17630 *           $scope.counter++;
17631 *         };
17632 *       }
17633     *     </script>
17634     *     <div ng-controller="Controller">
17635     *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
17636     *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
17637     *       <label for="ng-change-example2">Confirmed</label><br />
17638     *       <tt>debug = {{confirmed}}</tt><br/>
17639     *       <tt>counter = {{counter}}</tt><br/>
17640     *     </div>
17641     *   </file>
17642     *   <file name="protractor.js" type="protractor">
17643     *     var counter = element(by.binding('counter'));
17644     *     var debug = element(by.binding('confirmed'));
17645     *
17646     *     it('should evaluate the expression if changing from view', function() {
17647 *       expect(counter.getText()).toContain('0');
17648 *
17649 *       element(by.id('ng-change-example1')).click();
17650 *
17651 *       expect(counter.getText()).toContain('1');
17652 *       expect(debug.getText()).toContain('true');
17653 *     });
17654     *
17655     *     it('should not evaluate the expression if changing from model', function() {
17656 *       element(by.id('ng-change-example2')).click();
17657
17658 *       expect(counter.getText()).toContain('0');
17659 *       expect(debug.getText()).toContain('true');
17660 *     });
17661     *   </file>
17662     * </example>
17663     */
17664    var ngChangeDirective = valueFn({
17665        require: 'ngModel',
17666        link: function (scope, element, attr, ctrl) {
17667            ctrl.$viewChangeListeners.push(function () {
17668                scope.$eval(attr.ngChange);
17669            });
17670        }
17671    });
17672
17673
17674    var requiredDirective = function () {
17675        return {
17676            require: '?ngModel',
17677            link: function (scope, elm, attr, ctrl) {
17678                if (!ctrl) return;
17679                attr.required = true; // force truthy in case we are on non input element
17680
17681                var validator = function (value) {
17682                    if (attr.required && ctrl.$isEmpty(value)) {
17683                        ctrl.$setValidity('required', false);
17684                        return;
17685                    } else {
17686                        ctrl.$setValidity('required', true);
17687                        return value;
17688                    }
17689                };
17690
17691                ctrl.$formatters.push(validator);
17692                ctrl.$parsers.unshift(validator);
17693
17694                attr.$observe('required', function () {
17695                    validator(ctrl.$viewValue);
17696                });
17697            }
17698        };
17699    };
17700
17701
17702    /**
17703     * @ngdoc directive
17704     * @name ngList
17705     *
17706     * @description
17707     * Text input that converts between a delimited string and an array of strings. The delimiter
17708     * can be a fixed string (by default a comma) or a regular expression.
17709     *
17710     * @element input
17711     * @param {string=} ngList optional delimiter that should be used to split the value. If
17712     *   specified in form `/something/` then the value will be converted into a regular expression.
17713     *
17714     * @example
17715     <example name="ngList-directive">
17716     <file name="index.jsp">
17717     <script>
17718     function Ctrl($scope) {
17719           $scope.names = ['igor', 'misko', 'vojta'];
17720         }
17721     </script>
17722     <form name="myForm" ng-controller="Ctrl">
17723     List: <input name="namesInput" ng-model="names" ng-list required>
17724     <span class="error" ng-show="myForm.namesInput.$error.required">
17725     Required!</span>
17726     <br>
17727     <tt>names = {{names}}</tt><br/>
17728     <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
17729     <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
17730     <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
17731     <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
17732     </form>
17733     </file>
17734     <file name="protractor.js" type="protractor">
17735     var listInput = element(by.model('names'));
17736     var names = element(by.binding('{{names}}'));
17737     var valid = element(by.binding('myForm.namesInput.$valid'));
17738     var error = element(by.css('span.error'));
17739
17740     it('should initialize to model', function() {
17741          expect(names.getText()).toContain('["igor","misko","vojta"]');
17742          expect(valid.getText()).toContain('true');
17743          expect(error.getCssValue('display')).toBe('none');
17744        });
17745
17746     it('should be invalid if empty', function() {
17747          listInput.clear();
17748          listInput.sendKeys('');
17749
17750          expect(names.getText()).toContain('');
17751          expect(valid.getText()).toContain('false');
17752          expect(error.getCssValue('display')).not.toBe('none');        });
17753     </file>
17754     </example>
17755     */
17756    var ngListDirective = function () {
17757        return {
17758            require: 'ngModel',
17759            link: function (scope, element, attr, ctrl) {
17760                var match = /\/(.*)\//.exec(attr.ngList),
17761                    separator = match && new RegExp(match[1]) || attr.ngList || ',';
17762
17763                var parse = function (viewValue) {
vendor: 4,267 bytes, lines 17764-17884
17764                    // If the viewValue is invalid (say required but empty) it will be `undefined`
17765                    if (isUndefined(viewValue)) return;
17766
17767                    var list = [];
17768
17769                    if (viewValue) {
17770                        forEach(viewValue.split(separator), function (value) {
17771                            if (value) list.push(trim(value));
17772                        });
17773                    }
17774
17775                    return list;
17776                };
17777
17778                ctrl.$parsers.push(parse);
17779                ctrl.$formatters.push(function (value) {
17780                    if (isArray(value)) {
17781                        return value.join(', ');
17782                    }
17783
17784                    return undefined;
17785                });
17786
17787                // Override the standard $isEmpty because an empty array means the input is empty.
17788                ctrl.$isEmpty = function (value) {
17789                    return !value || !value.length;
17790                };
17791            }
17792        };
17793    };
17794
17795
17796    var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
17797    /**
17798     * @ngdoc directive
17799     * @name ngValue
17800     *
17801     * @description
17802     * Binds the given expression to the value of `input[select]` or `input[radio]`, so
17803     * that when the element is selected, the `ngModel` of that element is set to the
17804     * bound value.
17805     *
17806     * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
17807     * shown below.
17808     *
17809     * @element input
17810     * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
17811     *   of the `input` element
17812     *
17813     * @example
17814     <example name="ngValue-directive">
17815     <file name="index.jsp">
17816     <script>
17817     function Ctrl($scope) {
17818            $scope.names = ['pizza', 'unicorns', 'robots'];
17819            $scope.my = { favorite: 'unicorns' };
17820          }
17821     </script>
17822     <form ng-controller="Ctrl">
17823     <h2>Which is your favorite?</h2>
17824     <label ng-repeat="name in names" for="{{name}}">
17825     {{name}}
17826     <input type="radio"
17827     ng-model="my.favorite"
17828     ng-value="name"
17829     id="{{name}}"
17830     name="favorite">
17831     </label>
17832     <div>You chose {{my.favorite}}</div>
17833     </form>
17834     </file>
17835     <file name="protractor.js" type="protractor">
17836     var favorite = element(by.binding('my.favorite'));
17837
17838     it('should initialize to model', function() {
17839          expect(favorite.getText()).toContain('unicorns');
17840        });
17841     it('should bind the values to the inputs', function() {
17842          element.all(by.model('my.favorite')).get(0).click();
17843          expect(favorite.getText()).toContain('pizza');
17844        });
17845     </file>
17846     </example>
17847     */
17848    var ngValueDirective = function () {
17849        return {
17850            priority: 100,
17851            compile: function (tpl, tplAttr) {
17852                if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
17853                    return function ngValueConstantLink(scope, elm, attr) {
17854                        attr.$set('value', scope.$eval(attr.ngValue));
17855                    };
17856                } else {
17857                    return function ngValueLink(scope, elm, attr) {
17858                        scope.$watch(attr.ngValue, function valueWatchAction(value) {
17859                            attr.$set('value', value);
17860                        });
17861                    };
17862                }
17863            }
17864        };
17865    };
17866
17867    /**
17868     * @ngdoc directive
17869     * @name ngBind
17870     * @restrict AC
17871     *
17872     * @description
17873     * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
17874     * with the value of a given expression, and to update the text content when the value of that
17875     * expression changes.
17876     *
17877     * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
17878     * `{{ expression }}` which is similar but less verbose.
17879     *
17880     * It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
17881     * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
17882     * element attribute, it makes the bindings invisible to the user while the page is loading.
17883     *
17884     * An alternative solution to this problem would be using the
17885     * {@link ng.directive:ngCloak ngCloak} directive.
17886     *
17887     *
17888     * @element ANY
17889     * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
17890     *
17891     * @example
17892     * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
17893     <example>
17894     <file name="index.jsp">
17895     <script>
17896     function Ctrl($scope) {
17897           $scope.name = 'Whirled';
17898         }
17899     </script>
17900     <div ng-controller="Ctrl">
17901     Enter name: <input type="text" ng-model="name"><br>
17902     Hello <span ng-bind="name"></span>!
17903     </div>
17904     </file>
17905     <file name="protractor.js" type="protractor">
17906     it('should check ng-bind', function() {
17907         var nameInput = element(by.model('name'));
17908
17909         expect(element(by.binding('name')).getText()).toBe('Whirled');
17910         nameInput.clear();
17911         nameInput.sendKeys('world');
17912         expect(element(by.binding('name')).getText()).toBe('world');
17913       });
17914     </file>
17915     </example>
17916     */
17917    var ngBindDirective = ngDirective(function (scope, element, attr) {
17918        element.addClass('ng-binding').data('$binding', attr.ngBind);
17919        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
17920            // We are purposefully using == here rather than === because we want to
17921            // catch when value is "null or undefined"
17922            // jshint -W041
17923            element.text(value == undefined ? '' : value);
17924        });
17925    });
17926
17927
17928    /**
17929     * @ngdoc directive
17930     * @name ngBindTemplate
17931     *
17932     * @description
17933     * The `ngBindTemplate` directive specifies that the element
17934     * text content should be replaced with the interpolation of the template
17935     * in the `ngBindTemplate` attribute.
17936     * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
17937     * expressions. This directive is needed since some HTML elements
17938     * (such as TITLE and OPTION) cannot contain SPAN elements.
17939     *
17940     * @element ANY
17941     * @param {string} ngBindTemplate template of form
17942     *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
17943     *
17944     * @example
17945     * Try it here: enter text in text box and watch the greeting change.
17946     <example>
17947     <file name="index.jsp">
17948     <script>
17949     function Ctrl($scope) {
17950           $scope.salutation = 'Hello';
17951           $scope.name = 'World';
17952         }
17953     </script>
17954     <div ng-controller="Ctrl">
17955     Salutation: <input type="text" ng-model="salutation"><br>
17956     Name: <input type="text" ng-model="name"><br>
17957     <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
17958     </div>
17959     </file>
17960     <file name="protractor.js" type="protractor">
17961     it('should check ng-bind', function() {
17962         var salutationElem = element(by.binding('salutation'));
17963         var salutationInput = element(by.model('salutation'));
17964         var nameInput = element(by.model('name'));
17965
17966         expect(salutationElem.getText()).toBe('Hello World!');
17967
17968         salutationInput.clear();
17969         salutationInput.sendKeys('Greetings');
17970         nameInput.clear();
17971         nameInput.sendKeys('user');
17972
17973         expect(salutationElem.getText()).toBe('Greetings user!');
17974       });
17975     </file>
17976     </example>
17977     */
17978    var ngBindTemplateDirective = ['$interpolate', function ($interpolate) {
17979        return function (scope, element, attr) {
17980            // TODO: move this to scenario runner
17981            var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
17982            element.addClass('ng-binding').data('$binding', interpolateFn);
17983            attr.$observe('ngBindTemplate', function (value) {
17984                element.text(value);
17985            });
17986        };
17987    }];
17988
17989
17990    /**
17991     * @ngdoc directive
17992     * @name ngBindHtml
17993     *
17994     * @description
17995     * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
17996     * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
17997        * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
17998     * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
17999     * core Angular.)  You may also bypass sanitization for values you know are safe. To do so, bind to
18000     * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
18001     * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
18002     *
18003     * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
18004     * will have an exception (instead of an exploit.)
18005     *
18006     * @element ANY
18007     * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18008     *
18009     * @example
18010     Try it here: enter text in text box and watch the greeting change.
18011
18012     <example module="ngBindHtmlExample" deps="angular-sanitize.js">
18013     <file name="index.jsp">
18014     <div ng-controller="ngBindHtmlCtrl">
18015     <p ng-bind-html="myHTML"></p>
18016     </div>
18017     </file>
18018
18019     <file name="script.js">
18020     angular.module('ngBindHtmlExample', ['ngSanitize'])
18021
18022     .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
18023         $scope.myHTML =
18024            'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
18025       }]);
18026     </file>
18027
18028     <file name="protractor.js" type="protractor">
18029     it('should check ng-bind-html', function() {
18030         expect(element(by.binding('myHTML')).getText()).toBe(
18031             'I am an HTMLstring with links! and other stuff');
18032       });
18033     </file>
18034     </example>
18035     */
18036    var ngBindHtmlDirective = ['$sce', '$parse', function ($sce, $parse) {
18037        return function (scope, element, attr) {
18038            element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
18039
18040            var parsed = $parse(attr.ngBindHtml);
18041
18042            function getStringValue() {
18043                return (parsed(scope) || '').toString();
18044            }
18045
18046            scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
18047                element.html($sce.getTrustedHtml(parsed(scope)) || '');
18048            });
18049        };
18050    }];
18051
18052    function classDirective(name, selector) {
18053        name = 'ngClass' + name;
18054        return ['$animate', function ($animate) {
18055            return {
18056                restrict: 'AC',
18057                link: function (scope, element, attr) {
18058                    var oldVal;
18059
18060                    scope.$watch(attr[name], ngClassWatchAction, true);
18061
18062                    attr.$observe('class', function (value) {
18063                        ngClassWatchAction(scope.$eval(attr[name]));
18064                    });
18065
18066
18067                    if (name !== 'ngClass') {
18068                        scope.$watch('$index', function ($index, old$index) {
18069                            // jshint bitwise: false
18070                            var mod = $index & 1;
18071                            if (mod !== old$index & 1) {
18072                                var classes = arrayClasses(scope.$eval(attr[name]));
18073                                mod === selector ?
18074                                    addClasses(classes) :
18075                                    removeClasses(classes);
18076                            }
18077                        });
18078                    }
18079
18080                    function addClasses(classes) {
18081                        var newClasses = digestClassCounts(classes, 1);
18082                        attr.$addClass(newClasses);
18083                    }
18084
18085                    function removeClasses(classes) {
18086                        var newClasses = digestClassCounts(classes, -1);
18087                        attr.$removeClass(newClasses);
18088                    }
18089
18090                    function digestClassCounts(classes, count) {
18091                        var classCounts = element.data('$classCounts') || {};
18092                        var classesToUpdate = [];
18093                        forEach(classes, function (className) {
18094                            if (count > 0 || classCounts[className]) {
18095                                classCounts[className] = (classCounts[className] || 0) + count;
18096                                if (classCounts[className] === +(count > 0)) {
18097                                    classesToUpdate.push(className);
18098                                }
18099                            }
18100                        });
18101                        element.data('$classCounts', classCounts);
18102                        return classesToUpdate.join(' ');
18103                    }
18104
18105                    function updateClasses(oldClasses, newClasses) {
18106                        var toAdd = arrayDifference(newClasses, oldClasses);
18107                        var toRemove = arrayDifference(oldClasses, newClasses);
18108                        toRemove = digestClassCounts(toRemove, -1);
18109                        toAdd = digestClassCounts(toAdd, 1);
18110
18111                        if (toAdd.length === 0) {
18112                            $animate.removeClass(element, toRemove);
18113                        } else if (toRemove.length === 0) {
18114                            $animate.addClass(element, toAdd);
18115                        } else {
18116                            $animate.setClass(element, toAdd, toRemove);
18117                        }
18118                    }
18119
18120                    function ngClassWatchAction(newVal) {
18121                        if (selector === true || scope.$index % 2 === selector) {
18122                            var newClasses = arrayClasses(newVal || []);
18123                            if (!oldVal) {
18124                                addClasses(newClasses);
18125                            } else if (!equals(newVal, oldVal)) {
18126                                var oldClasses = arrayClasses(oldVal);
18127                                updateClasses(oldClasses, newClasses);
18128                            }
18129                        }
18130                        oldVal = copy(newVal);
18131                    }
18132                }
18133            };
18134
18135            function arrayDifference(tokens1, tokens2) {
18136                var values = [];
18137
18138                outer:
18139                    for (var i = 0; i < tokens1.length; i++) {
18140                        var token = tokens1[i];
18141                        for (var j = 0; j < tokens2.length; j++) {
18142                            if (token == tokens2[j]) continue outer;
18143                        }
18144                        values.push(token);
18145                    }
18146                return values;
18147            }
18148
18149            function arrayClasses(classVal) {
18150                if (isArray(classVal)) {
18151                    return classVal;
18152                } else if (isString(classVal)) {
18153                    return classVal.split(' ');
18154                } else if (isObject(classVal)) {
18155                    var classes = [], i = 0;
18156                    forEach(classVal, function (v, k) {
18157                        if (v) {
18158                            classes.push(k);
18159                        }
18160                    });
18161                    return classes;
18162                }
18163                return classVal;
18164            }
18165        }];
18166    }
18167
18168    /**
18169     * @ngdoc directive
18170     * @name ngClass
18171     * @restrict AC
18172     *
18173     * @description
18174     * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
18175     * an expression that represents all classes to be added.
18176     *
18177     * The directive operates in three different ways, depending on which of three types the expression
18178     * evaluates to:
18179     *
18180     * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
18181     * names.
18182     *
18183     * 2. If the expression evaluates to an array, each element of the array should be a string that is
18184     * one or more space-delimited class names.
18185     *
18186     * 3. If the expression evaluates to an object, then for each key-value pair of the
18187     * object with a truthy value the corresponding key is used as a class name.
18188     *
18189     * The directive won't add duplicate classes if a particular class was already set.
18190     *
18191     * When the expression changes, the previously added classes are removed and only then the
18192     * new classes are added.
18193     *
18194     * @animations
18195     * add - happens just before the class is applied to the element
18196     * remove - happens just before the class is removed from the element
18197     *
18198     * @element ANY
18199     * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
18200     *   of the evaluation can be a string representing space delimited class
18201     *   names, an array, or a map of class names to boolean values. In the case of a map, the
18202     *   names of the properties whose values are truthy will be added as css classes to the
18203     *   element.
18204     *
18205     * @example Example that demonstrates basic bindings via ngClass directive.
18206     <example>
18207     <file name="index.jsp">
18208     <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
18209     <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
18210     <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
18211     <input type="checkbox" ng-model="error"> error (apply "red" class)
18212     <hr>
18213     <p ng-class="style">Using String Syntax</p>
18214     <input type="text" ng-model="style" placeholder="Type: bold strike red">
18215     <hr>
18216     <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
18217     <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
18218     <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
18219     <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
18220     </file>
18221     <file name="style.css">
18222     .strike {
18223         text-decoration: line-through;
18224       }
18225     .bold {
18226           font-weight: bold;
18227       }
18228     .red {
18229           color: red;
18230       }
18231     </file>
18232     <file name="protractor.js" type="protractor">
18233     var ps = element.all(by.css('p'));
18234
18235     it('should let you toggle the class', function() {
18236
18237         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
18238         expect(ps.first().getAttribute('class')).not.toMatch(/red/);
18239
18240         element(by.model('important')).click();
18241         expect(ps.first().getAttribute('class')).toMatch(/bold/);
18242
18243         element(by.model('error')).click();
18244         expect(ps.first().getAttribute('class')).toMatch(/red/);
18245       });
18246
18247     it('should let you toggle string example', function() {
18248         expect(ps.get(1).getAttribute('class')).toBe('');
18249         element(by.model('style')).clear();
18250         element(by.model('style')).sendKeys('red');
18251         expect(ps.get(1).getAttribute('class')).toBe('red');
18252       });
18253
18254     it('array example should have 3 classes', function() {
18255         expect(ps.last().getAttribute('class')).toBe('');
18256         element(by.model('style1')).sendKeys('bold');
18257         element(by.model('style2')).sendKeys('strike');
18258         element(by.model('style3')).sendKeys('red');
18259         expect(ps.last().getAttribute('class')).toBe('bold strike red');
18260       });
18261     </file>
18262     </example>
18263
18264     ## Animations
18265
18266     The example below demonstrates how to perform animations using ngClass.
18267
18268     <example module="ngAnimate" deps="angular-animate.js" animations="true">
18269     <file name="index.jsp">
18270     <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
18271     <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
18272     <br>
18273     <span class="base-class" ng-class="myVar">Sample Text</span>
18274     </file>
18275     <file name="style.css">
18276     .base-class {
18277         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18278         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
18279       }
18280
18281     .base-class.my-class {
18282         color: red;
18283         font-size:3em;
18284       }
18285     </file>
18286     <file name="protractor.js" type="protractor">
18287     it('should check ng-class', function() {
18288         expect(element(by.css('.base-class')).getAttribute('class')).not.
18289           toMatch(/my-class/);
18290
18291         element(by.id('setbtn')).click();
18292
18293         expect(element(by.css('.base-class')).getAttribute('class')).
18294           toMatch(/my-class/);
18295
18296         element(by.id('clearbtn')).click();
18297
18298         expect(element(by.css('.base-class')).getAttribute('class')).not.
18299           toMatch(/my-class/);
18300       });
18301     </file>
18302     </example>
18303
18304
18305     ## ngClass and pre-existing CSS3 Transitions/Animations
18306     The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
18307     Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
18308     any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
18309     to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
18310     {@link ngAnimate.$animate#removeclass $animate.removeClass}.
18311     */
18312    var ngClassDirective = classDirective('', true);
18313
18314    /**
18315     * @ngdoc directive
18316     * @name ngClassOdd
18317     * @restrict AC
18318     *
18319     * @description
18320     * The `ngClassOdd` and `ngClassEven` directives work exactly as
18321     * {@link ng.directive:ngClass ngClass}, except they work in
18322     * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18323     *
18324     * This directive can be applied only within the scope of an
18325     * {@link ng.directive:ngRepeat ngRepeat}.
18326     *
18327     * @element ANY
18328     * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
18329     *   of the evaluation can be a string representing space delimited class names or an array.
18330     *
18331     * @example
18332     <example>
18333     <file name="index.jsp">
18334     <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18335     <li ng-repeat="name in names">
18336     <span ng-class-odd="'odd'" ng-class-even="'even'">
18337     {{name}}
18338     </span>
18339     </li>
18340     </ol>
18341     </file>
18342     <file name="style.css">
18343     .odd {
18344         color: red;
18345       }
18346     .even {
18347         color: blue;
18348       }
18349     </file>
18350     <file name="protractor.js" type="protractor">
18351     it('should check ng-class-odd and ng-class-even', function() {
18352         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18353           toMatch(/odd/);
18354         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18355           toMatch(/even/);
18356       });
18357     </file>
18358     </example>
18359     */
18360    var ngClassOddDirective = classDirective('Odd', 0);
18361
18362    /**
18363     * @ngdoc directive
18364     * @name ngClassEven
18365     * @restrict AC
18366     *
18367     * @description
18368     * The `ngClassOdd` and `ngClassEven` directives work exactly as
18369     * {@link ng.directive:ngClass ngClass}, except they work in
18370     * conjunction with `ngRepeat` and take effect only on odd (even) rows.
18371     *
18372     * This directive can be applied only within the scope of an
18373     * {@link ng.directive:ngRepeat ngRepeat}.
18374     *
18375     * @element ANY
18376     * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
18377     *   result of the evaluation can be a string representing space delimited class names or an array.
18378     *
18379     * @example
18380     <example>
18381     <file name="index.jsp">
18382     <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
18383     <li ng-repeat="name in names">
18384     <span ng-class-odd="'odd'" ng-class-even="'even'">
18385     {{name}} &nbsp; &nbsp; &nbsp;
18386     </span>
18387     </li>
18388     </ol>
18389     </file>
18390     <file name="style.css">
18391     .odd {
18392         color: red;
18393       }
18394     .even {
18395         color: blue;
18396       }
18397     </file>
18398     <file name="protractor.js" type="protractor">
18399     it('should check ng-class-odd and ng-class-even', function() {
18400         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
18401           toMatch(/odd/);
18402         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
18403           toMatch(/even/);
18404       });
18405     </file>
18406     </example>
18407     */
18408    var ngClassEvenDirective = classDirective('Even', 1);
18409
18410    /**
18411     * @ngdoc directive
18412     * @name ngCloak
18413     * @restrict AC
18414     *
18415     * @description
18416     * The `ngCloak` directive is used to prevent the Angular html template from being briefly
18417     * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
18418     * directive to avoid the undesirable flicker effect caused by the html template display.
18419     *
18420     * The directive can be applied to the `<body>` element, but the preferred usage is to apply
18421     * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
18422     * of the browser view.
18423     *
18424     * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
18425     * `angular.min.js`.
18426     * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
18427     *
18428     * ```css
18429     * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
18430 *   display: none !important;
18431 * }
18432     * ```
18433     *
18434     * When this css rule is loaded by the browser, all html elements (including their children) that
18435     * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
18436     * during the compilation of the template it deletes the `ngCloak` element attribute, making
18437     * the compiled element visible.
18438     *
18439     * For the best result, the `angular.js` script must be loaded in the head section of the html
18440     * document; alternatively, the css rule above must be included in the external stylesheet of the
18441     * application.
18442     *
18443     * Legacy browsers, like IE7, do not provide attribute selector support (a
18443dded in CSS 2.1) so they
18444     * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
18445     * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
18446     *
18447     * @element ANY
18448     *
18449     * @example
18450     <example>
18451     <file name="index.jsp">
18452     <div id="template1" ng-cloak>{{ 'hello' }}</div>
18453     <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
18454     </file>
18455     <file name="protractor.js" type="protractor">
18456     it('should remove the template directive and css class', function() {
18457         expect($('#template1').getAttribute('ng-cloak')).
18458           toBeNull();
18459         expect($('#template2').getAttribute('ng-cloak')).
18460           toBeNull();
18461       });
18462     </file>
18463     </example>
18464     *
18465     */
18466    var ngCloakDirective = ngDirective({
18467        compile: function (element, attr) {
18468            attr.$set('ngCloak', undefined);
18469            element.removeClass('ng-cloak');
18470        }
18471    });
18472
18473    /**
18474     * @ngdoc directive
18475     * @name ngController
18476     *
18477     * @description
18478     * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
18479     * supports the principles behind the Model-View-Controller design pattern.
18480     *
18481     * MVC components in angular:
18482     *
18483     * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
18484     *   are accessed through bindings.
18485     * * View — The template (HTML with data bindings) that is rendered into the View.
18486     * * Controller — The `ngController` directive specifies a Controller class; the class contains business
18487     *   logic behind the application to decorate the scope with functions and values
18488     *
18489     * Note that you can also attach controllers to the DOM by declaring it in a route definition
18490     * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
18491     * again using `ng-controller` in the template itself.  This will cause the controller to be attached
18492     * and executed twice.
18493     *
18494     * @element ANY
18495     * @scope
18496     * @param {expression} ngController Name of a globally accessible constructor function or an
18497     *     {@link guide/expression expression} that on the current scope evaluates to a
18498     *     constructor function. The controller instance can be published into a scope property
18499     *     by specifying `as propertyName`.
18500     *
18501     * @example
18502     * Here is a simple form for editing user contact information. Adding, removing, clearing, and
18503     * greeting are methods declared on the controller (see source tab). These methods can
18504     * easily be called from the angular markup. Notice that the scope becomes the `this` for the
18505     * controller's instance. This allows for easy access to the view data from the controller. Also
18506     * notice that any changes to the data are automatically reflected in the View without the need
18507     * for a manual update. The example is shown in two different declaration styles you may use
18508     * according to preference.
18509     <example>
18510     <file name="index.jsp">
18511     <script>
18512     function SettingsController1() {
18513          this.name = "John Smith";
18514          this.contacts = [
18515            {type: 'phone', value: '408 555 1212'},
18516            {type: 'email', value: '[email protected]'} ];
18517     };
18518
18519     SettingsController1.prototype.greet = function() {
18520          alert(this.name);
18521        };
18522
18523     SettingsController1.prototype.addContact = function() {
18524          this.contacts.push({type: 'email', value: '[email protected]'});
18525     };
18526
18527     SettingsController1.prototype.removeContact = function(contactToRemove) {
18528         var index = this.contacts.indexOf(contactToRemove);
18529          this.contacts.splice(index, 1);
18530        };
18531
18532     SettingsController1.prototype.clearContact = function(contact) {
18533          contact.type = 'phone';
18534          contact.value = '';
18535        };
18536     </script>
18537     <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
18538     Name: <input type="text" ng-model="settings.name"/>
18539     [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
18540     Contact:
18541     <ul>
18542     <li ng-repeat="contact in settings.contacts">
18543     <select ng-model="contact.type">
18544     <option>phone</option>
18545     <option>email</option>
18546     </select>
18547     <input type="text" ng-model="contact.value"/>
18548     [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
18549     | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
18550     </li>
18551     <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
18552     </ul>
18553     </div>
18554     </file>
18555     <file name="protractor.js" type="protractor">
18556     it('should check controller as', function() {
18557         var container = element(by.id('ctrl-as-exmpl'));
18558
18559         expect(container.findElement(by.model('settings.name'))
18560             .getAttribute('value')).toBe('John Smith');
18561
18562         var firstRepeat =
18563             container.findElement(by.repeater('contact in settings.contacts').row(0));
18564         var secondRepeat =
18565             container.findElement(by.repeater('contact in settings.contacts').row(1));
18566
18567         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18568             .toBe('408 555 1212');
18569         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18570             .toBe('[email protected]');
18571
18572     firstRepeat.findElement(by.linkText('clear')).click();
18573
18574     expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18575     .toBe('');
18576
18577     container.findElement(by.linkText('add')).click();
18578
18579     expect(container.findElement(by.repeater('contact in settings.contacts').row(2))
18580     .findElement(by.model('contact.value'))
18581     .getAttribute('value'))
18582     .toBe('[email protected]');
18583     });
18584     </file>
18585     </example>
18586     <example>
18587     <file name="index.jsp">
18588     <script>
18589     function SettingsController2($scope) {
18590          $scope.name = "John Smith";
18591          $scope.contacts = [
18592            {type:'phone', value:'408 555 1212'},
18593            {type:'email', value:'[email protected]'} ];
18594
18595     $scope.greet = function() {
18596           alert(this.name);
18597          };
18598
18599     $scope.addContact = function() {
18600           this.contacts.push({type:'email', value:'[email protected]'});
18601     };
18602
18603     $scope.removeContact = function(contactToRemove) {
18604           var index = this.contacts.indexOf(contactToRemove);
18605           this.contacts.splice(index, 1);
18606          };
18607
18608     $scope.clearContact = function(contact) {
18609           contact.type = 'phone';
18610           contact.value = '';
18611          };
18612     }
18613     </script>
18614     <div id="ctrl-exmpl" ng-controller="SettingsController2">
18615     Name: <input type="text" ng-model="name"/>
18616     [ <a href="" ng-click="greet()">greet</a> ]<br/>
18617     Contact:
18618     <ul>
18619     <li ng-repeat="contact in contacts">
18620     <select ng-model="contact.type">
18621     <option>phone</option>
18622     <option>email</option>
18623     </select>
18624     <input type="text" ng-model="contact.value"/>
18625     [ <a href="" ng-click="clearContact(contact)">clear</a>
18626     | <a href="" ng-click="removeContact(contact)">X</a> ]
18627     </li>
18628     <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
18629     </ul>
18630     </div>
18631     </file>
18632     <file name="protractor.js" type="protractor">
18633     it('should check controller', function() {
18634         var container = element(by.id('ctrl-exmpl'));
18635
18636         expect(container.findElement(by.model('name'))
18637             .getAttribute('value')).toBe('John Smith');
18638
18639         var firstRepeat =
18640             container.findElement(by.repeater('contact in contacts').row(0));
18641         var secondRepeat =
18642             container.findElement(by.repeater('contact in contacts').row(1));
18643
18644         expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18645             .toBe('408 555 1212');
18646         expect(secondRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18647             .toBe('[email protected]');
18648
18649     firstRepeat.findElement(by.linkText('clear')).click();
18650
18651     expect(firstRepeat.findElement(by.model('contact.value')).getAttribute('value'))
18652     .toBe('');
18653
18654     container.findElement(by.linkText('add')).click();
18655
18656     expect(container.findElement(by.repeater('contact in contacts').row(2))
18657     .findElement(by.model('contact.value'))
18658     .getAttribute('value'))
18659     .toBe('[email protected]');
18660     });
18661     </file>
18662     </example>
18663
18664     */
18665    var ngControllerDirective = [function () {
18666        return {
18667            scope: true,
18668            controller: '@',
18669            priority: 500
18670        };
18671    }];
18672
18673    /**
18674     * @ngdoc directive
18675     * @name ngCsp
18676     *
18677     * @element html
18678     * @description
18679     * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
18680     *
18681     * This is necessary when developing things like Google Chrome Extensions.
18682     *
18683     * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
18684     * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
18685     * any of these restrictions.
18686     *
18687     * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
18688     * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
18689     * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
18690     * be raised.
18691     *
18692     * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
18693     * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
18694     * To make those directives work in CSP mode, include the `angular-csp.css` manually.
18695     *
18696     * In order to use this feature put the `ngCsp` directive on the root element of the application.
18697     *
18698     * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
18699     *
18700     * @example
18701     * This example shows how to apply the `ngCsp` directive to the `html` tag.
18702     ```html
18703     <!doctype html>
18704     <html ng-app ng-csp>
18705     ...
18706     ...
18707     </html>
18708     ```
18709     */
18710
18711// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
18712// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
18713// anywhere in the current doc
18714
18715    /**
18716     * @ngdoc directive
18717     * @name ngClick
18718     *
18719     * @description
18720     * The ngClick directive allows you to specify custom behavior when
18721     * an element is clicked.
18722     *
18723     * @element ANY
18724     * @priority 0
18725     * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
18726     * click. ({@link guide/expression#-event- Event object is available as `$event`})
18727     *
18728     * @example
18729     <example>
18730     <file name="index.jsp">
18731     <button ng-click="count = count + 1" ng-init="count=0">
18732     Increment
18733     </button>
18734     count: {{count}}
18735     </file>
18736     <file name="protractor.js" type="protractor">
18737     it('should check ng-click', function() {
18738         expect(element(by.binding('count')).getText()).toMatch('0');
18739         element(by.css('button')).click();
18740         expect(element(by.binding('count')).getText()).toMatch('1');
18741       });
18742     </file>
18743     </example>
18744     */
18745    /*
18746     * A directive that allows creation of custom onclick handlers that are defined as angular
18747     * expressions and are compiled and executed within the current scope.
18748     *
18749     * Events that are handled via these handler are always configured not to propagate further.
18750     */
18751    var ngEventDirectives = {};
18752    forEach(
18753        'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
18754        function (name) {
18755            var directiveName = directiveNormalize('ng-' + name);
18756            ngEventDirectives[directiveName] = ['$parse', function ($parse) {
18757                return {
18758                    compile: function ($element, attr) {
18759                        var fn = $parse(attr[directiveName]);
18760                        return function (scope, element, attr) {
18761                            element.on(lowercase(name), function (event) {
18762                                scope.$apply(function () {
18763                                    fn(scope, {$event: event});
18764                                });
18765                            });
18766                        };
18767                    }
18768                };
18769            }];
18770        }
18771    );
18772
18773    /**
18774     * @ngdoc directive
18775     * @name ngDblclick
18776     *
18777     * @description
18778     * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
18779     *
18780     * @element ANY
18781     * @priority 0
18782     * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
18783     * a dblclick. (The Event object is available as `$event`)
18784     *
18785     * @example
18786     <example>
18787     <file name="index.jsp">
18788     <button ng-dblclick="count = count + 1" ng-init="count=0">
18789     Increment (on double click)
18790     </button>
18791     count: {{count}}
18792     </file>
18793     </example>
18794     */
18795
18796
18797    /**
18798     * @ngdoc directive
18799     * @name ngMousedown
18800     *
18801     * @description
18802     * The ngMousedown directive allows you to specify custom behavior on mousedown event.
18803     *
18804     * @element ANY
18805     * @priority 0
18806     * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
18807     * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
18808     *
18809     * @example
18810     <example>
18811     <file name="index.jsp">
18812     <button ng-mousedown="count = count + 1" ng-init="count=0">
18813     Increment (on mouse down)
18814     </button>
18815     count: {{count}}
18816     </file>
18817     </example>
18818     */
18819
18820
18821    /**
18822     * @ngdoc directive
18823     * @name ngMouseup
18824     *
18825     * @description
18826     * Specify custom behavior on mouseup event.
18827     *
18828     * @element ANY
18829     * @priority 0
18830     * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
18831     * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
18832     *
18833     * @example
18834     <example>
18835     <file name="index.jsp">
18836     <button ng-mouseup="count = count + 1" ng-init="count=0">
18837     Increment (on mouse up)
18838     </button>
18839     count: {{count}}
18840     </file>
18841     </example>
18842     */
18843
18844    /**
18845     * @ngdoc directive
18846     * @name ngMouseover
18847     *
18848     * @description
18849     * Specify custom behavior on mouseover event.
18850     *
18851     * @element ANY
18852     * @priority 0
18853     * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
18854     * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
18855     *
18856     * @example
18857     <example>
18858     <file name="index.jsp">
18859     <button ng-mouseover="count = count + 1" ng-init="count=0">
18860     Increment (when mouse is over)
18861     </button>
18862     count: {{count}}
18863     </file>
18864     </example>
18865     */
18866
18867
18868    /**
18869     * @ngdoc directive
18870     * @name ngMouseenter
18871     *
18872     * @description
18873     * Specify custom behavior on mouseenter event.
18874     *
18875     * @element ANY
18876     * @priority 0
18877     * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
18878     * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
18879     *
18880     * @example
18881     <example>
18882     <file name="index.jsp">
18883     <button ng-mouseenter="count = count + 1" ng-init="count=0">
18884     Increment (when mouse enters)
18885     </button>
18886     count: {{count}}
18887     </file>
18888     </example>
18889     */
18890
18891
18892    /**
18893     * @ngdoc directive
18894     * @name ngMouseleave
18895     *
18896     * @description
18897     * Specify custom behavior on mouseleave event.
18898     *
18899     * @element ANY
18900     * @priority 0
18901     * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
18902     * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
18903     *
18904     * @example
18905     <example>
18906     <file name="index.jsp">
18907     <button ng-mouseleave="count = count + 1" ng-init="count=0">
18908     Increment (when mouse leaves)
18909     </button>
18910     count: {{count}}
18911     </file>
18912     </example>
18913     */
18914
18915
18916    /**
18917     * @ngdoc directive
18918     * @name ngMousemove
18919     *
18920     * @description
18921     * Specify custom behavior on mousemove event.
18922     *
18923     * @element ANY
18924     * @priority 0
18925     * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
18926     * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
18927     *
18928     * @example
18929     <example>
18930     <file name="index.jsp">
18931     <button ng-mousemove="count = count + 1" ng-init="count=0">
18932     Increment (when mouse moves)
18933     </button>
18934     count: {{count}}
18935     </file>
18936     </example>
18937     */
18938
18939
18940    /**
18941     * @ngdoc directive
18942     * @name ngKeydown
18943     *
18944     * @description
18945     * Specify custom behavior on keydown event.
18946     *
18947     * @element ANY
18948     * @priority 0
18949     * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
18950     * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18951     *
18952     * @example
18953     <example>
18954     <file name="index.jsp">
18955     <input ng-keydown="count = count + 1" ng-init="count=0">
18956     key down count: {{count}}
18957     </file>
18958     </example>
18959     */
18960
18961
18962    /**
18963     * @ngdoc directive
18964     * @name ngKeyup
18965     *
18966     * @description
18967     * Specify custom behavior on keyup event.
18968     *
18969     * @element ANY
18970     * @priority 0
18971     * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
18972     * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
18973     *
18974     * @example
18975     <example>
18976     <file name="index.jsp">
18977     <input ng-keyup="count = count + 1" ng-init="count=0">
18978     key up count: {{count}}
18979     </file>
18980     </example>
18981     */
18982
18983
18984    /**
18985     * @ngdoc directive
18986     * @name ngKeypress
18987     *
18988     * @description
18989     * Specify custom behavior on keypress event.
18990     *
18991     * @element ANY
18992     * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
18993     * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
18994     * and can be interrogated for keyCode, altKey, etc.)
18995     *
18996     * @example
18997     <example>
18998     <file name="index.jsp">
18999     <input ng-keypress="count = count + 1" ng-init="count=0">
19000     key press count: {{count}}
19001     </file>
19002     </example>
19003     */
19004
19005
19006    /**
19007     * @ngdoc directive
19008     * @name ngSubmit
19009     *
19010     * @description
19011     * Enables binding angular expressions to onsubmit events.
19012     *
19013     * Additionally it prevents the default action (which for form means sending the request to the
19014     * server and reloading the current page), but only if the form does not contain `action`,
19015     * `data-action`, or `x-action` attributes.
19016     *
19017     * @element form
19018     * @priority 0
19019     * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
19020     * ({@link guide/expression#-event- Event object is available as `$event`})
19021     *
19022     * @example
19023     <example>
19024     <file name="index.jsp">
19025     <script>
19026     function Ctrl($scope) {
19027          $scope.list = [];
19028          $scope.text = 'hello';
19029          $scope.submit = function() {
19030            if ($scope.text) {
19031              $scope.list.push(this.text);
19032              $scope.text = '';
19033            }
19034          };
19035        }
19036     </script>
19037     <form ng-submit="submit()" ng-controller="Ctrl">
19038     Enter text and hit enter:
19039     <input type="text" ng-model="text" name="text" />
19040     <input type="submit" id="submit" value="Submit" />
19041     <pre>list={{list}}</pre>
19042     </form>
19043     </file>
19044     <file name="protractor.js" type="protractor">
19045     it('should check ng-submit', function() {
19046         expect(element(by.binding('list')).getText()).toBe('list=[]');
19047         element(by.css('#submit')).click();
19048         expect(element(by.binding('list')).getText()).toContain('hello');
19049         expect(element(by.input('text')).getAttribute('value')).toBe('');
19050       });
19051     it('should ignore empty strings', function() {
19052         expect(element(by.binding('list')).getText()).toBe('list=[]');
19053         element(by.css('#submit')).click();
19054         element(by.css('#submit')).click();
19055         expect(element(by.binding('list')).getText()).toContain('hello');
19056        });
19057     </file>
19058     </example>
19059     */
19060
19061    /**
19062     * @ngdoc directive
19063     * @name ngFocus
19064     *
19065     * @description
19066     * Specify custom behavior on focus event.
19067     *
19068     * @element window, input, select, textarea, a
19069     * @priority 0
19070     * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
19071     * focus. ({@link guide/expression#-event- Event object is available as `$event`})
19072     *
19073     * @example
19074     * See {@link ng.directive:ngClick ngClick}
19075     */
19076
19077    /**
19078     * @ngdoc directive
19079     * @name ngBlur
19080     *
19081     * @description
19082     * Specify custom behavior on blur event.
19083     *
19084     * @element window, input, select, textarea, a
19085     * @priority 0
19086     * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
19087     * blur. ({@link guide/expression#-event- Event object is available as `$event`})
19088     *
19089     * @example
19090     * See {@link ng.directive:ngClick ngClick}
19091     */
19092
19093    /**
19094     * @ngdoc directive
19095     * @name ngCopy
19096     *
19097     * @description
19098     * Specify custom behavior on copy event.
19099     *
19100     * @element window, input, select, textarea, a
19101     * @priority 0
19102     * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
19103     * copy. ({@link guide/expression#-event- Event object is available as `$event`})
19104     *
19105     * @example
19106     <example>
19107     <file name="index.jsp">
19108     <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
19109     copied: {{copied}}
19110     </file>
19111     </example>
19112     */
19113
19114    /**
19115     * @ngdoc directive
19116     * @name ngCut
19117     *
19118     * @description
19119     * Specify custom behavior on cut event.
19120     *
19121     * @element window, input, select, textarea, a
19122     * @priority 0
19123     * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
19124     * cut. ({@link guide/expression#-event- Event object is available as `$event`})
19125     *
19126     * @example
19127     <example>
19128     <file name="index.jsp">
19129     <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
19130     cut: {{cut}}
19131     </file>
19132     </example>
19133     */
19134
19135    /**
19136     * @ngdoc directive
19137     * @name ngPaste
19138     *
19139     * @description
19140     * Specify custom behavior on paste event.
19141     *
19142     * @element window, input, select, textarea, a
19143     * @priority 0
19144     * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
19145     * paste. ({@link guide/expression#-event- Event object is available as `$event`})
19146     *
19147     * @example
19148     <example>
19149     <file name="index.jsp">
19150     <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
19151     pasted: {{paste}}
19152     </file>
19153     </example>
19154     */
19155
19156    /**
19157     * @ngdoc directive
19158     * @name ngIf
19159     * @restrict A
19160     *
19161     * @description
19162     * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
19163     * {expression}. If the expression assigned to `ngIf` evaluates to a false
19164     * value then the element is removed from the DOM, otherwise a clone of the
19165     * element is reinserted into the DOM.
19166     *
19167     * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
19168     * element in the DOM rather than changing its visibility via the `display` css property.  A common
19169     * case when this difference is significant is when using css selectors that rely on an element's
19170     * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
19171     *
19172     * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
19173     * is created when the element is restored.  The scope created within `ngIf` inherits from
19174     * its parent scope using
19175     * [prototypal inheritance](https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance).
19176     * An important implication of this is if `ngModel` is used within `ngIf` to bind to
19177     * a javascript primitive defined in the parent scope. In this case any modifications made to the
19178     * variable within the child scope will override (hide) the value in the parent scope.
19179     *
19180     * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
19181     * is if an element's class attribute is directly modified after it's compiled, using something like
19182     * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
19183     * the added class will be lost because the original compiled state is used to regenerate the element.
19184     *
19185     * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
19186     * and `leave` effects.
19187     *
19188     * @animations
19189     * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
19190     * leave - happens just before the ngIf contents are removed from the DOM
19191     *
19192     * @element ANY
19193     * @scope
19194     * @priority 600
19195     * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
19196     *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
19197     *     element is added to the DOM tree.
19198     *
19199     * @example
19200     <example module="ngAnimate" deps="angular-animate.js" animations="true">
19201     <file name="index.jsp">
19202     Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
19203     Show when checked:
19204     <span ng-if="checked" class="animate-if">
19205     I'm removed when the checkbox is unchecked.
19206     </span>
19207     </file>
19208     <file name="animations.css">
19209     .animate-if {
19210        background:white;
19211        border:1px solid black;
19212        padding:10px;
19213      }
19214
19215     .animate-if.ng-enter, .animate-if.ng-leave {
19216        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19217        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19218      }
19219
19220     .animate-if.ng-enter,
19221     .animate-if.ng-leave.ng-leave-active {
19222        opacity:0;
19223      }
19224
19225     .animate-if.ng-leave,
19226     .animate-if.ng-enter.ng-enter-active {
19227        opacity:1;
19228      }
19229     </file>
19230     </example>
19231     */
19232    var ngIfDirective = ['$animate', function ($animate) {
19233        return {
19234            transclude: 'element',
19235            priority: 600,
19236            terminal: true,
19237            restrict: 'A',
19238            $$tlb: true,
19239            link: function ($scope, $element, $attr, ctrl, $transclude) {
19240                var block, childScope, previousElements;
19241                $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
19242
19243                    if (toBoolean(value)) {
19244                        if (!childScope) {
19245                            childScope = $scope.$new();
19246                            $transclude(childScope, function (clone) {
19247                                clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
19248                                // Note: We only need the first/last node of the cloned 
19248nodes.
19249                                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19250                                // by a directive with templateUrl when it's template arrives.
19251                                block = {
19252                                    clone: clone
19253                                };
19254                                $animate.enter(clone, $element.parent(), $element);
19255                            });
19256                        }
19257                    } else {
19258                        if (previousElements) {
19259                            previousElements.remove();
19260                            previousElements = null;
19261                        }
19262                        if (childScope) {
19263                            childScope.$destroy();
19264                            childScope = null;
19265                        }
19266                        if (block) {
19267                            previousElements = getBlockElements(block.clone);
19268                            $animate.leave(previousElements, function () {
19269                                previousElements = null;
19270                            });
19271                            block = null;
19272                        }
19273                    }
19274                });
19275            }
19276        };
19277    }];
19278
19279    /**
19280     * @ngdoc directive
19281     * @name ngInclude
19282     * @restrict ECA
19283     *
19284     * @description
19285     * Fetches, compiles and includes an external HTML fragment.
19286     *
19287     * By default, the template URL is restricted to the same domain and protocol as the
19288     * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
19289 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
19290     * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
19291     * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
19292        * ng.$sce Strict Contextual Escaping}.
19293     *
19294     * In addition, the browser's
19295     * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
19296     * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
19297     * policy may further restrict whether the template is successfully loaded.
19298     * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
19299     * access on some browsers.
19300     *
19301     * @animations
19302     * enter - animation is used to bring new content into the browser.
19303     * leave - animation is used to animate existing content away.
19304     *
19305     * The enter and leave animation occur concurrently.
19306     *
19307     * @scope
19308     * @priority 400
19309     *
19310     * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
19311     *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
19312     * @param {string=} onload Expression to evaluate when a new partial is loaded.
19313     *
19314     * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
19315 *                  $anchorScroll} to scroll the viewport after the content is loaded.
19316     *
19317     *                  - If the attribute is not set, disable scrolling.
19318     *                  - If the attribute is set without value, enable scrolling.
19319     *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
19320     *
19321     * @example
19322     <example module="ngAnimate" deps="angular-animate.js" animations="true">
19323     <file name="index.jsp">
19324     <div ng-controller="Ctrl">
19325     <select ng-model="template" ng-options="t.name for t in templates">
19326     <option value="">(blank)</option>
19327     </select>
19328     url of the template: <tt>{{template.url}}</tt>
19329     <hr/>
19330     <div class="slide-animate-container">
19331     <div class="slide-animate" ng-include="template.url"></div>
19332     </div>
19333     </div>
19334     </file>
19335     <file name="script.js">
19336     function Ctrl($scope) {
19337        $scope.templates =
19338          [ { name: 'template1.html', url: 'template1.html'},
19339            { name: 'template2.html', url: 'template2.html'} ];
19340        $scope.template = $scope.templates[0];
19341      }
19342     </file>
19343     <file name="template1.html">
19344     Content of template1.html
19345     </file>
19346     <file name="template2.html">
19347     Content of template2.html
19348     </file>
19349     <file name="animations.css">
19350     .slide-animate-container {
19351        position:relative;
19352        background:white;
19353        border:1px solid black;
19354        height:40px;
19355        overflow:hidden;
19356      }
19357
19358     .slide-animate {
19359        padding:10px;
19360      }
19361
19362     .slide-animate.ng-enter, .slide-animate.ng-leave {
19363        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19364        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
19365
19366        position:absolute;
19367        top:0;
19368        left:0;
19369        right:0;
19370        bottom:0;
19371        display:block;
19372        padding:10px;
19373      }
19374
19375     .slide-animate.ng-enter {
19376        top:-50px;
19377      }
19378     .slide-animate.ng-enter.ng-enter-active {
19379        top:0;
19380      }
19381
19382     .slide-animate.ng-leave {
19383        top:0;
19384      }
19385     .slide-animate.ng-leave.ng-leave-active {
19386        top:50px;
19387      }
19388     </file>
19389     <file name="protractor.js" type="protractor">
19390     var templateSelect = element(by.model('template'));
19391     var includeElem = element(by.css('[ng-include]'));
19392
19393     it('should load template1.html', function() {
19394        expect(includeElem.getText()).toMatch(/Content of template1.html/);
19395      });
19396
19397     it('should load template2.html', function() {
19398        if (browser.params.browser == 'firefox') {
19399          // Firefox can't handle using selects
19400          // See https://github.com/angular/protractor/issues/480
19401          return;
19402        }
19403        templateSelect.click();
19404        templateSelect.element.all(by.css('option')).get(2).click();
19405        expect(includeElem.getText()).toMatch(/Content of template2.html/);
19406      });
19407
19408     it('should change to blank', function() {
19409        if (browser.params.browser == 'firefox') {
19410          // Firefox can't handle using selects
19411          return;
19412        }
19413        templateSelect.click();
19414        templateSelect.element.all(by.css('option')).get(0).click();
19415        expect(includeElem.isPresent()).toBe(false);
19416      });
19417     </file>
19418     </example>
19419     */
19420
19421
19422    /**
19423     * @ngdoc event
19424     * @name ngInclude#$includeContentRequested
19425     * @eventType emit on the scope ngInclude was declared in
19426     * @description
19427     * Emitted every time the ngInclude content is requested.
19428     */
19429
19430
19431    /**
19432     * @ngdoc event
19433     * @name ngInclude#$includeContentLoaded
19434     * @eventType emit on the current ngInclude scope
19435     * @description
19436     * Emitted every time the ngInclude content is reloaded.
19437     */
19438    var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
19439        function ($http, $templateCache, $anchorScroll, $animate, $sce) {
19440            return {
19441                restrict: 'ECA',
19442                priority: 400,
19443                terminal: true,
19444                transclude: 'element',
19445                controller: angular.noop,
19446                compile: function (element, attr) {
19447                    var srcExp = attr.ngInclude || attr.src,
19448                        onloadExp = attr.onload || '',
19449                        autoScrollExp = attr.autoscroll;
19450
19451                    return function (scope, $element, $attr, ctrl, $transclude) {
19452                        var changeCounter = 0,
19453                            currentScope,
19454                            previousElement,
19455                            currentElement;
19456
19457                        var cleanupLastIncludeContent = function () {
19458                            if (previousElement) {
19459                                previousElement.remove();
19460                                previousElement = null;
19461                            }
19462                            if (currentScope) {
19463                                currentScope.$destroy();
19464                                currentScope = null;
19465                            }
19466                            if (currentElement) {
19467                                $animate.leave(currentElement, function () {
19468                                    previousElement = null;
19469                                });
19470                                previousElement = currentElement;
19471                                currentElement = null;
19472                            }
19473                        };
19474
19475                        scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
19476                            var afterAnimation = function () {
19477                                if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
19478                                    $anchorScroll();
19479                                }
19480                            };
19481                            var thisChangeId = ++changeCounter;
19482
19483                            if (src) {
19484                                $http.get(src, {cache: $templateCache}).success(function (response) {
19485                                    if (thisChangeId !== changeCounter) return;
19486                                    var newScope = scope.$new();
19487                                    ctrl.template = response;
19488
19489                                    // Note: This will also link all children of ng-include that were contained in the original
19490                                    // html. If that content contains controllers, ... they could pollute/change the scope.
19491                                    // However, using ng-include on an element with additional content does not make sense...
19492                                    // Note: We can't remove them in the cloneAttchFn of $transclude as that
19493                                    // function is called before linking the content, which would apply child
19494                                    // directives to non existing elements.
19495                                    var clone = $transclude(newScope, function (clone) {
19496                                        cleanupLastIncludeContent();
19497                                        $animate.enter(clone, null, $element, afterAnimation);
19498                                    });
19499
19500                                    currentScope = newScope;
19501                                    currentElement = clone;
19502
19503                                    currentScope.$emit('$includeContentLoaded');
19504                                    scope.$eval(onloadExp);
19505                                }).error(function () {
19506                                        if (thisChangeId === changeCounter) cleanupLastIncludeContent();
19507                                    });
19508                                scope.$emit('$includeContentRequested');
19509                            } else {
19510                                cleanupLastIncludeContent();
19511                                ctrl.template = null;
19512                            }
19513                        });
19514                    };
19515                }
19516            };
19517        }];
19518
19519// This directive is called during the $transclude call of the first `ngInclude` directive.
19520// It will replace and compile the content of the element with the loaded template.
19521// We need this directive so that the element content is already filled when
19522// the link function of another directive on the same element as ngInclude
19523// is called.
19524    var ngIncludeFillContentDirective = ['$compile',
19525        function ($compile) {
19526            return {
19527                restrict: 'ECA',
19528                priority: -400,
19529                require: 'ngInclude',
19530                link: function (scope, $element, $attr, ctrl) {
19531                    $element.html(ctrl.template);
19532                    $compile($element.contents())(scope);
19533                }
19534            };
19535        }];
19536
19537    /**
19538     * @ngdoc directive
19539     * @name ngInit
19540     * @restrict AC
19541     *
19542     * @description
19543     * The `ngInit` directive allows you to evaluate an expression in the
19544     * current scope.
19545     *
19546     * <div class="alert alert-error">
19547     * The only appropriate use of `ngInit` is for aliasing special properties of
19548     * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
19549     * should use {@link guide/controller controllers} rather than `ngInit`
19550     * to initialize values on a scope.
19551     * </div>
19552     * <div class="alert alert-warning">
19553     * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
19554     * sure you have parenthesis for correct precedence:
19555     * <pre class="prettyprint">
19556     *   <div ng-init="test1 = (data | orderBy:'name')"></div>
19557     * </pre>
19558     * </div>
19559     *
19560     * @priority 450
19561     *
19562     * @element ANY
19563     * @param {expression} ngInit {@link guide/expression Expression} to eval.
19564     *
19565     * @example
19566     <example>
19567     <file name="index.jsp">
19568     <script>
19569     function Ctrl($scope) {
19570       $scope.list = [['a', 'b'], ['c', 'd']];
19571     }
19572     </script>
19573     <div ng-controller="Ctrl">
19574     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
19575     <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
19576     <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
19577     </div>
19578     </div>
19579     </div>
19580     </file>
19581     <file name="protractor.js" type="protractor">
19582     it('should alias index positions', function() {
19583         var elements = element.all(by.css('.example-init'));
19584         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
19585         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
19586         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
19587         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
19588       });
19589     </file>
19590     </example>
19591     */
19592    var ngInitDirective = ngDirective({
19593        priority: 450,
19594        compile: function () {
19595            return {
19596                pre: function (scope, element, attrs) {
19597                    scope.$eval(attrs.ngInit);
19598                }
19599            };
19600        }
19601    });
19602
19603    /**
19604     * @ngdoc directive
19605     * @name ngNonBindable
19606     * @restrict AC
19607     * @priority 1000
19608     *
19609     * @description
19610     * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
19611     * DOM element. This is useful if the element contains what appears to be Angular directives and
19612     * bindings but which should be ignored by Angular. This could be the case if you have a site that
19613     * displays snippets of code, for instance.
19614     *
19615     * @element ANY
19616     *
19617     * @example
19618     * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
19619     * but the one wrapped in `ngNonBindable` is left alone.
19620     *
19621     * @example
19622     <example>
19623     <file name="index.jsp">
19624     <div>Normal: {{1 + 2}}</div>
19625     <div ng-non-bindable>Ignored: {{1 + 2}}</div>
19626     </file>
19627     <file name="protractor.js" type="protractor">
19628     it('should check ng-non-bindable', function() {
19629         expect(element(by.binding('1 + 2')).getText()).toContain('3');
19630         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
19631       });
19632     </file>
19633     </example>
19634     */
19635    var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
19636
19637    /**
19638     * @ngdoc directive
19639     * @name ngPluralize
19640     * @restrict EA
19641     *
19642     * @description
19643     * `ngPluralize` is a directive that displays messages according to en-US localization rules.
19644     * These rules are bundled with angular.js, but can be overridden
19645     * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
19646     * by specifying the mappings between
19647     * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19648     * and the strings to be displayed.
19649     *
19650     * # Plural categories and explicit number rules
19651     * There are two
19652     * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
19653     * in Angular's default en-US locale: "one" and "other".
19654     *
19655     * While a plural category may match many numbers (for example, in en-US locale, "other" can match
19656     * any number that is not 1), an explicit number rule can only match one number. For example, the
19657     * explicit number rule for "3" matches the number 3. There are examples of plural categories
19658     * and explicit number rules throughout the rest of this documentation.
19659     *
19660     * # Configuring ngPluralize
19661     * You configure ngPluralize by providing 2 attributes: `count` and `when`.
19662     * You can also provide an optional attribute, `offset`.
19663     *
19664     * The value of the `count` attribute can be either a string or an {@link guide/expression
19665 * Angular expression}; these are evaluated on the current scope for its bound value.
19666     *
19667     * The `when` attribute specifies the mappings between plural categories and the actual
19668     * string to be displayed. The value of the attribute should be a JSON object.
19669     *
19670     * The following example shows how to configure ngPluralize:
19671     *
19672     * ```html
19673     * <ng-pluralize count="personCount"
19674     when="{'0': 'Nobody is viewing.',
19675 *                      'one': '1 person is viewing.',
19676 *                      'other': '{} people are viewing.'}">
19677     * </ng-pluralize>
19678     *```
19679     *
19680     * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
19681     * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
19682     * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
19683     * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
19684     * show "a dozen people are viewing".
19685     *
19686     * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
19687     * into pluralized strings. In the previous example, Angular will replace `{}` with
19688     * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
19689     * for <span ng-non-bindable>{{numberExpression}}</span>.
19690     *
19691     * # Configuring ngPluralize with offset
19692     * The `offset` attribute allows further customization of pluralized text, which can result in
19693     * a better user experience. For example, instead of the message "4 people are viewing this document",
19694     * you might display "John, Kate and 2 others are viewing this document".
19695     * The offset attribute allows you to offset a number by any desired value.
19696     * Let's take a look at an example:
19697     *
19698     * ```html
19699     * <ng-pluralize count="personCount" offset=2
19700     *               when="{'0': 'Nobody is viewing.',
19701 *                      '1': '{{person1}} is viewing.',
19702 *                      '2': '{{person1}} and {{person2}} are viewing.',
19703 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
19704 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19705     * </ng-pluralize>
19706     * ```
19707     *
19708     * Notice that we are still using two plural categories(one, other), but we added
19709     * three explicit number rules 0, 1 and 2.
19710     * When one person, perhaps John, views the document, "John is viewing" will be shown.
19711     * When three people view the document, no explicit number rule is found, so
19712     * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
19713     * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
19714     * is shown.
19715     *
19716     * Note that when you specify offsets, you must provide explicit number rules for
19717     * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
19718     * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
19719     * plural categories "one" and "other".
19720     *
19721     * @param {string|expression} count The variable to be bound to.
19722     * @param {string} when The mapping between plural category to its corresponding strings.
19723     * @param {number=} offset Offset to deduct from the total number.
19724     *
19725     * @example
19726     <example>
19727     <file name="index.jsp">
19728     <script>
19729     function Ctrl($scope) {
19730            $scope.person1 = 'Igor';
19731            $scope.person2 = 'Misko';
19732            $scope.personCount = 1;
19733          }
19734     </script>
19735     <div ng-controller="Ctrl">
19736     Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
19737     Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
19738     Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
19739
19740     <!--- Example with simple pluralization rules for en locale --->
19741     Without Offset:
19742     <ng-pluralize count="personCount"
19743     when="{'0': 'Nobody is viewing.',
19744                               'one': '1 person is viewing.',
19745                               'other': '{} people are viewing.'}">
19746     </ng-pluralize><br>
19747
19748     <!--- Example with offset --->
19749     With Offset(2):
19750     <ng-pluralize count="personCount" offset=2
19751     when="{'0': 'Nobody is viewing.',
19752                               '1': '{{person1}} is viewing.',
19753                               '2': '{{person1}} and {{person2}} are viewing.',
19754                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
19755                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
19756     </ng-pluralize>
19757     </div>
19758     </file>
19759     <file name="protractor.js" type="protractor">
19760     it('should show correct pluralized string', function() {
19761          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
19762          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19763          var countInput = element(by.model('personCount'));
19764
19765          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
19766          expect(withOffset.getText()).toEqual('Igor is viewing.');
19767
19768          countInput.clear();
19769          countInput.sendKeys('0');
19770
19771          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
19772          expect(withOffset.getText()).toEqual('Nobody is viewing.');
19773
19774          countInput.clear();
19775          countInput.sendKeys('2');
19776
19777          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
19778          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
19779
19780          countInput.clear();
19781          countInput.sendKeys('3');
19782
19783          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
19784          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
19785
19786          countInput.clear();
19787          countInput.sendKeys('4');
19788
19789          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
19790          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
19791        });
19792     it('should show data-bound names', function() {
19793          var withOffset = element.all(by.css('ng-pluralize')).get(1);
19794          var personCount = element(by.model('personCount'));
19795          var person1 = element(by.model('person1'));
19796          var person2 = element(by.model('person2'));
19797          personCount.clear();
19798          personCount.sendKeys('4');
19799          person1.clear();
19800          person1.sendKeys('Di');
19801          person2.clear();
19802          person2.sendKeys('Vojta');
19803          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
19804        });
19805     </file>
19806     </example>
19807     */
19808    var ngPluralizeDirective = ['$locale', '$interpolate', function ($locale, $interpolate) {
19809        var BRACE = /{}/g;
19810        return {
19811            restrict: 'EA',
19812            link: function (scope, element, attr) {
19813                var numberExp = attr.count,
19814                    whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
19815                    offset = attr.offset || 0,
19816                    whens = scope.$eval(whenExp) || {},
19817                    whensExpFns = {},
19818                    startSymbol = $interpolate.startSymbol(),
19819                    endSymbol = $interpolate.endSymbol(),
19820                    isWhen = /^when(Minus)?(.+)$/;
19821
19822                forEach(attr, function (expression, attributeName) {
19823                    if (isWhen.test(attributeName)) {
19824                        whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
19825                            element.attr(attr.$attr[attributeName]);
19826                    }
19827                });
19828                forEach(whens, function (expression, key) {
19829                    whensExpFns[key] =
19830                        $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
19831                            offset + endSymbol));
19832                });
19833
19834                scope.$watch(function ngPluralizeWatch() {
19835                    var value = parseFloat(scope.$eval(numberExp));
19836
19837                    if (!isNaN(value)) {
19838                        //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
19839                        //check it against pluralization rules in $locale service
19840                        if (!(value in whens)) value = $locale.pluralCat(value - offset);
19841                        return whensExpFns[value](scope, element, true);
19842                    } else {
19843                        return '';
19844                    }
19845                }, function ngPluralizeWatchAction(newVal) {
19846                    element.text(newVal);
19847                });
19848            }
19849        };
19850    }];
19851
19852    /**
19853     * @ngdoc directive
19854     * @name ngRepeat
19855     *
19856     * @description
19857     * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
19858     * instance gets its own scope, where the given loop variable is set to the current collection item,
19859     * and `$index` is set to the item index or key.
19860     *
19861     * Special properties are exposed on the local scope of each template instance, including:
19862     *
19863     * | Variable  | Type            | Details                                                                     |
19864     * |-----------|-----------------|-----------------------------------------------------------------------------|
19865     * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
19866     * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
19867     * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
19868     * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
19869     * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
19870     * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
19871     *
19872     * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
19873     * This may be useful when, for instance, nesting ngRepeats.
19874     *
19875     * # Special repeat start and end points
19876     * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
19877     * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
19878     * 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)
19879     * up to and including the ending HTML tag where **ng-repeat-end** is placed.
19880     *
19881     * The example below makes use of this feature:
19882     * ```html
19883     *   <header ng-repeat-start="item in items">
19884     *     Header {{ item }}
19885     *   </header>
19886     *   <div class="body">
19887     *     Body {{ item }}
19888     *   </div>
19889     *   <footer ng-repeat-end>
19890     *     Footer {{ item }}
19891     *   </footer>
19892     * ```
19893     *
19894     * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
19895     * ```html
19896     *   <header>
19897     *     Header A
19898     *   </header>
19899     *   <div class="body">
19900     *     Body A
19901     *   </div>
19902     *   <footer>
19903     *     Footer A
19904     *   </footer>
19905     *   <header>
19906     *     Header B
19907     *   </header>
19908     *   <div class="body">
19909     *     Body B
19910     *   </div>
19911     *   <footer>
19912     *     Footer B
19913     *   </footer>
19914     * ```
19915     *
19916     * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
19917     * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
19918     *
19919     * @animations
19920     * **.enter** - when a new item is added to the list or when an item is revealed after a filter
19921     *
19922     * **.leave** - when an item is removed from the list or when an item is filtered out
19923     *
19924     * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
19925     *
19926     * @element ANY
19927     * @scope
19928     * @priority 1000
19929     * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
19930     *   formats are currently supported:
19931     *
19932     *   * `variable in expression` – where variable is the user defined loop variable and `expression`
19933     *     is a scope expression giving the collection to enumerate.
19934     *
19935     *     For example: `album in artist.albums`.
19936     *
19937     *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
19938     *     and `expression` is the scope expression giving the collection to enumerate.
19939     *
19940     *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
19941     *
19942     *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
19943     *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
19944     *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
19945     *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
19946     *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
19947     *     before specifying a tracking expression.
19948     *
19949     *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
19950     *     will be associated by item identity in the array.
19951     *
19952     *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
19953     *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
19954     *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
19955     *     element in the same way in the DOM.
19956     *
19957     *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
19958     *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
19959     *     property is same.
19960     *
19961     *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
19962     *     to items in conjunction with a tracking expression.
19963     *
19964     * @example
19965     * This example initializes the scope to a list of names and
19966     * then uses `ngRepeat` to display every person:
19967     <example module="ngAnimate" deps="angular-animate.js" animations="true">
19968     <file name="index.jsp">
19969     <div ng-init="friends = [
19970     {name:'John', age:25, gender:'boy'},
19971     {name:'Jessie', age:30, gender:'girl'},
19972     {name:'Johanna', age:28, gender:'girl'},
19973     {name:'Joy', age:15, gender:'girl'},
19974     {name:'Mary', age:28, gender:'girl'},
19975     {name:'Peter', age:95, gender:'boy'},
19976     {name:'Sebastian', age:50, gender:'boy'},
19977     {name:'Erika', age:27, gender:'girl'},
19978     {name:'Patrick', age:40, gender:'boy'},
19979     {name:'Samantha', age:60, gender:'girl'}
19980     ]">
19981     I have {{friends.length}} friends. They are:
19982     <input type="search" ng-model="q" placeholder="filter friends..." />
19983     <ul class="example-animate-container">
19984     <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
19985     [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
19986     </li>
19987     </ul>
19988     </div>
19989     </file>
19990     <file name="animations.css">
19991     .example-animate-container {
19992        background:white;
19993        border:1px solid black;
19994        list-style:none;
19995        margin:0;
19996        padding:0 10px;
19997      }
19998
19999     .animate-repeat {
20000        line-height:40px;
20001        list-style:none;
20002        box-sizing:border-box;
20003      }
20004
20005     .animate-repeat.ng-move,
20006     .animate-repeat.ng-enter,
20007     .animate-repeat.ng-leave {
20008        -webkit-transition:all linear 0.5s;
20009        transition:all linear 0.5s;
20010      }
20011
20012     .animate-repeat.ng-leave.ng-leave-active,
20013     .animate-repeat.ng-move,
20014     .animate-repeat.ng-enter {
20015        opacity:0;
20016        max-height:0;
20017      }
20018
20019     .animate-repeat.ng-leave,
20020     .animate-repeat.ng-move.ng-move-active,
20021     .animate-repeat.ng-enter.ng-enter-active {
20022        opacity:1;
20023        max-height:40px;
20024      }
20025     </file>
20026     <file name="protractor.js" type="protractor">
20027     var friends = element.all(by.repeater('friend in friends'));
20028
20029     it('should render initial data set', function() {
20030        expect(friends.count()).toBe(10);
20031        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
20032        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
20033        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
20034        expect(element(by.binding('friends.length')).getText())
20035            .toMatch("I have 10 friends. They are:");
20036      });
20037
20038     it('should update repeater when filter predicate changes', function() {
20039         expect(friends.count()).toBe(10);
20040
20041         element(by.model('q')).sendKeys('ma');
20042
20043         expect(friends.count()).toBe(2);
20044         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
20045         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
20046       });
20047     </file>
20048     </example>
20049     */
20050    var ngRepeatDirective = ['$parse', '$animate', function ($parse, $animate) {
20051        var NG_REMOVED = '$$NG_REMOVED';
20052        var ngRepeatMinErr = minErr('ngRepeat');
20053        return {
20054            transclude: 'element',
20055            priority: 1000,
20056            terminal: true,
20057            $$tlb: true,
20058            link: function ($scope, $element, $attr, ctrl, $transclude) {
20059                var expression = $attr.ngRepeat;
20060                var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),
20061                    trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
20062                    lhs, rhs, valueIdentifier, keyIdentifier,
20063                    hashFnLocals = {$id: hashKey};
20064
20065                if (!match) {
20066                    throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
20067                        expression);
20068                }
20069
20070                lhs = match[1];
20071                rhs = match[2];
20072                trackByExp = match[3];
20073
20074                if (trackByExp) {
20075                    trackByExpGetter = $parse(trackByExp);
20076                    trackByIdExpFn = function (key, value, index) {
20077                        // assign key, value, and $index to the locals so that they can be used in hash functions
20078                        if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
20079                        hashFnLocals[valueIdentifier] = value;
20080                        hashFnLocals.$index = index;
20081                        return trackByExpGetter($scope, hashFnLocals);
20082                    };
20083                } else {
20084                    trackByIdArrayFn = function (key, value) {
20085                        return hashKey(value);
20086                    };
20087                    trackByIdObjFn = function (key) {
20088                        return key;
20089                    };
20090                }
20091
20092                match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
20093                if (!match) {
20094                    throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
20095                        lhs);
20096                }
20097                valueIdentifier = match[3] || match[1];
20098                keyIdentifier = match[2];
20099
20100                // Store a list of elements from previous run. This is a hash where key is the item from the
20101                // iterator, and the value is objects with following properties.
20102                //   - scope: bound scope
20103                //   - element: previous element.
20104                //   - index: position
20105                var lastBlockMap = {};
20106
20107                //watch props
20108                $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
20109                    var index, length,
20110                        previousNode = $element[0],     // current position of the node
20111                        nextNode,
20112                    // Same as lastBlockMap but it has the current state. It will become the
20113                    // lastBlockMap on the next iteration.
20114                        nextBlockMap = {},
20115                        arrayLength,
20116                        childScope,
20117                        key, value, // key/value of iteration
20118                        trackById,
20119                        trackByIdFn,
20120                        collectionKeys,
20121                        block,       // last object information {scope, element, id}
20122                        nextBlockOrder = [],
20123                        elementsToRemove;
20124
20125
20126                    if (isArrayLike(collection)) {
20127                        collectionKeys = collection;
20128                        trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
20129                    } else {
20130                        trackByIdFn = trackByIdExpFn || trackByIdObjFn;
20131                        // if object, extract keys, sort them and use to determine order of iteration over obj props
20132                        collectionKeys = [];
20133                        for (key in collection) {
20134                            if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
20135                                collectionKeys.push(key);
20136                            }
20137                        }
20138                        collectionKeys.sort();
20139                    }
20140
20141                    arrayLength = collectionKeys.length;
20142
20143                    // locate existing items
20144                    length = nextBlockOrder.length = collectionKeys.length;
20145                    for (index = 0; index < length; index++) {
20146                        key = (collection === collectionKeys) ? index : collectionKeys[index];
20147                        value = collection[key];
20148                        trackById = trackByIdFn(key, value, index);
20149                        assertNotHasOwnProperty(trackById, '`track by` id');
20150                        if (lastBlockMap.hasOwnProperty(trackById)) {
20151                            block = lastBlockMap[trackById];
20152                            delete lastBlockMap[trackById];
20153                            nextBlockMap[trackById] = block;
20154                            nextBlockOrder[index] = block;
20155                        } else if (nextBlockMap.hasOwnProperty(trackById)) {
20156                            // restore lastBlockMap
20157                            forEach(nextBlockOrder, function (block) {
20158                                if (block && block.scope) lastBlockMap[block.id] = block;
20159                            });
20160                            // This is a duplicate and we need to throw an error
20161                            throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
20162                                expression, trackById);
20163                        } else {
20164                            // new never before seen block
20165                            nextBlockOrder[index] = { id: trackById };
20166                            nextBlockMap[trackById] = false;
20167                        }
20168                    }
20169
20170                    // remove existing items
20171                    for (key in lastBlockMap) {
20172                        // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
20173                        if (lastBlockMap.hasOwnProperty(key)) {
20174                            block = lastBlockMap[key];
20175                            elementsToRemove = getBlockElements(block.clone);
20176                            $animate.leave(elementsToRemove);
20177                            forEach(elementsToRemove, function (element) {
20178                                element[NG_REMOVED] = true;
20179                            });
20180                            block.scope.$destroy();
20181                        }
20182                    }
20183
20184                    // we are not using forEach for perf reasons (trying to avoid #call)
20185                    for (index = 0, length = collectionKeys.length; index < length; index++) {
20186                        key = (collection === collectionKeys) ? index : collectionKeys[index];
20187                        value = collection[key];
20188                        block = nextBlockOrder[index];
20189                        if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
20190
20191                        if (block.scope) {
20192                            // if we have already seen this object, then we need to reuse the
20193                            // associated scope/element
20194                            childScope = block.scope;
20195
20196                            nextNode = previousNode;
20197                            do {
20198                                nextNode = nextNode.nextSibling;
20199                            } while (nextNode && nextNode[NG_REMOVED]);
20200
20201                            if (getBlockStart(block) != nextNode) {
20202                                // existing item which got moved
20203                                $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
20204                            }
20205                            previousNode = getBlockEnd(block);
20206                        } else {
20207                            // new item which we don't know about
20208                            childScope = $scope.$new();
20209                        }
20210
20211                        childScope[valueIdentifier] = value;
20212                        if (keyIdentifier) childScope[keyIdentifier] = key;
20213                        childScope.$index = index;
20214                        childScope.$first = (index === 0);
20215                        childScope.$last = (index === (arrayLength - 1));
20216                        childScope.$middle = !(childScope.$first || childScope.$last);
20217                        // jshint bitwise: false
20218                        childScope.$odd = !(childScope.$even = (index & 1) === 0);
20219                        // jshint bitwise: true
20220
20221                        if (!block.scope) {
20222                            $transclude(childScope, function (clone) {
20223                                clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
20224                                $animate.enter(clone, null, jqLite(previousNode));
20225                                previousNode = clone;
20226                                block.scope = childScope;
20227                                // Note: We only need the first/last node of the cloned 
20227nodes.
20228                                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
20229                                // by a directive with templateUrl when it's template arrives.
20230                                block.clone = clone;
20231                                nextBlockMap[block.id] = block;
20232                            });
20233                        }
20234                    }
20235                    lastBlockMap = nextBlockMap;
20236                });
20237            }
20238        };
20239
20240        function getBlockStart(block) {
20241            return block.clone[0];
20242        }
20243
20244        function getBlockEnd(block) {
20245            return block.clone[block.clone.length - 1];
20246        }
20247    }];
20248
20249    /**
20250     * @ngdoc directive
20251     * @name ngShow
20252     *
20253     * @description
20254     * The `ngShow` directive shows or hides the given HTML element based on the expression
20255     * provided to the ngShow attribute. The element is shown or hidden by removing or adding
20256     * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20257     * in AngularJS and sets the display style to none (using an !important flag).
20258     * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20259     *
20260     * ```html
20261     * <!-- when $scope.myValue is truthy (element is visible) -->
20262     * <div ng-show="myValue"></div>
20263     *
20264     * <!-- when $scope.myValue is falsy (element is hidden) -->
20265     * <div ng-show="myValue" class="ng-hide"></div>
20266     * ```
20267     *
20268     * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
20269     * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20270     * from the element causing the element not to appear hidden.
20271     *
20272     * ## Why is !important used?
20273     *
20274     * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20275     * can be easily overridden by heavier selectors. For example, something as simple
20276     * as changing the display style on a HTML list item would make hidden elements appear visible.
20277     * This also becomes a bigger issue when dealing with CSS frameworks.
20278     *
20279     * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20280     * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20281     * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20282     *
20283     * ### Overriding .ng-hide
20284     *
20285     * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20286     * restating the styles for the .ng-hide class in CSS:
20287     * ```css
20288     * .ng-hide {
20289 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20290 *   display:block!important;
20291 *
20292 *   //this is just another form of hiding an element
20293 *   position:absolute;
20294 *   top:-9999px;
20295 *   left:-9999px;
20296 * }
20297     * ```
20298     *
20299     * Just remember to include the important flag so the CSS override will function.
20300     *
20301     * <div class="alert alert-warning">
20302     * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
20303     * "f" / "0" / "false" / "no" / "n" / "[]"
20304     * </div>
20305     *
20306     * ## A note about animations with ngShow
20307     *
20308     * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20309     * is true and false. This system works like the animation system present with ngClass except that
20310     * you must also include the !important flag to override the display property
20311     * so that you can perform an animation when the element is hidden during the time of the animation.
20312     *
20313     * ```css
20314     * //
20315     * //a working example can be found at the bottom of this page
20316     * //
20317     * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20318 *   transition:0.5s linear all;
20319 *   display:block!important;
20320 * }
20321     *
20322     * .my-element.ng-hide-add { ... }
20323     * .my-element.ng-hide-add.ng-hide-add-active { ... }
20324     * .my-element.ng-hide-remove { ... }
20325     * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20326     * ```
20327     *
20328     * @animations
20329     * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20330     * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
20331     *
20332     * @element ANY
20333     * @param {expression} ngShow If the {@link guide/expression expression} is truthy
20334     *     then the element is shown or hidden respectively.
20335     *
20336     * @example
20337     <example module="ngAnimate" deps="angular-animate.js" animations="true">
20338     <file name="index.jsp">
20339     Click me: <input type="checkbox" ng-model="checked"><br/>
20340     <div>
20341     Show:
20342     <div class="check-element animate-show" ng-show="checked">
20343     <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20344     </div>
20345     </div>
20346     <div>
20347     Hide:
20348     <div class="check-element animate-show" ng-hide="checked">
20349     <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20350     </div>
20351     </div>
20352     </file>
20353     <file name="glyphicons.css">
20354     @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20355     </file>
20356     <file name="animations.css">
20357     .animate-show {
20358        -webkit-transition:all linear 0.5s;
20359        transition:all linear 0.5s;
20360        line-height:20px;
20361        opacity:1;
20362        padding:10px;
20363        border:1px solid black;
20364        background:white;
20365      }
20366
20367     .animate-show.ng-hide-add,
20368     .animate-show.ng-hide-remove {
20369        display:block!important;
20370      }
20371
20372     .animate-show.ng-hide {
20373        line-height:0;
20374        opacity:0;
20375        padding:0 10px;
20376      }
20377
20378     .check-element {
20379        padding:10px;
20380        border:1px solid black;
20381        background:white;
20382      }
20383     </file>
20384     <file name="protractor.js" type="protractor">
20385     var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20386     var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20387
20388     it('should check ng-show / ng-hide', function() {
20389        expect(thumbsUp.isDisplayed()).toBeFalsy();
20390        expect(thumbsDown.isDisplayed()).toBeTruthy();
20391
20392        element(by.model('checked')).click();
20393
20394        expect(thumbsUp.isDisplayed()).toBeTruthy();
20395        expect(thumbsDown.isDisplayed()).toBeFalsy();
20396      });
20397     </file>
20398     </example>
20399     */
20400    var ngShowDirective = ['$animate', function ($animate) {
20401        return function (scope, element, attr) {
20402            scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
20403                $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
20404            });
20405        };
20406    }];
20407
20408
20409    /**
20410     * @ngdoc directive
20411     * @name ngHide
20412     *
20413     * @description
20414     * The `ngHide` directive shows or hides the given HTML element based on the expression
20415     * provided to the ngHide attribute. The element is shown or hidden by removing or adding
20416     * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20417     * in AngularJS and sets the display style to none (using an !important flag).
20418     * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20419     *
20420     * ```html
20421     * <!-- when $scope.myValue is truthy (element is hidden) -->
20422     * <div ng-hide="myValue"></div>
20423     *
20424     * <!-- when $scope.myValue is falsy (element is visible) -->
20425     * <div ng-hide="myValue" class="ng-hide"></div>
20426     * ```
20427     *
20428     * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20429     * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20430     * from the element causing the element not to appear hidden.
20431     *
20432     * ## Why is !important used?
20433     *
20434     * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20435     * can be easily overridden by heavier selectors. For example, something as simple
20436     * as changing the display style on a HTML list item would make hidden elements appear visible.
20437     * This also becomes a bigger issue when dealing with CSS frameworks.
20438     *
20439     * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
20440     * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20441     * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20442     *
20443     * ### Overriding .ng-hide
20444     *
20445     * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
20446     * restating the styles for the .ng-hide class in CSS:
20447     * ```css
20448     * .ng-hide {
20449 *   //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
20450 *   display:block!important;
20451 *
20452 *   //this is just another form of hiding an element
20453 *   position:absolute;
20454 *   top:-9999px;
20455 *   left:-9999px;
20456 * }
20457     * ```
20458     *
20459     * Just remember to include the important flag so the CSS override will function.
20460     *
20461     * <div class="alert alert-warning">
20462     * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
20463     * "f" / "0" / "false" / "no" / "n" / "[]"
20464     * </div>
20465     *
20466     * ## A note about animations with ngHide
20467     *
20468     * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20469     * is true and false. This system works like the animation system present with ngClass, except that
20470     * you must also include the !important flag to override the display property so
20471     * that you can perform an animation when the element is hidden during the time of the animation.
20472     *
20473     * ```css
20474     * //
20475     * //a working example can be found at the bottom of this page
20476     * //
20477     * .my-element.ng-hide-add, .my-element.ng-hide-remove {
20478 *   transition:0.5s linear all;
20479 *   display:block!important;
20480 * }
20481     *
20482     * .my-element.ng-hide-add { ... }
20483     * .my-element.ng-hide-add.ng-hide-add-active { ... }
20484     * .my-element.ng-hide-remove { ... }
20485     * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
20486     * ```
20487     *
20488     * @animations
20489     * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20490     * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
20491     *
20492     * @element ANY
20493     * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
20494     *     the element is shown or hidden respectively.
20495     *
20496     * @example
20497     <example module="ngAnimate" deps="angular-animate.js" animations="true">
20498     <file name="index.jsp">
20499     Click me: <input type="checkbox" ng-model="checked"><br/>
20500     <div>
20501     Show:
20502     <div class="check-element animate-hide" ng-show="checked">
20503     <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
20504     </div>
20505     </div>
20506     <div>
20507     Hide:
20508     <div class="check-element animate-hide" ng-hide="checked">
20509     <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
20510     </div>
20511     </div>
20512     </file>
20513     <file name="glyphicons.css">
20514     @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
20515     </file>
20516     <file name="animations.css">
20517     .animate-hide {
20518        -webkit-transition:all linear 0.5s;
20519        transition:all linear 0.5s;
20520        line-height:20px;
20521        opacity:1;
20522        padding:10px;
20523        border:1px solid black;
20524        background:white;
20525      }
20526
20527     .animate-hide.ng-hide-add,
20528     .animate-hide.ng-hide-remove {
20529        display:block!important;
20530      }
20531
20532     .animate-hide.ng-hide {
20533        line-height:0;
20534        opacity:0;
20535        padding:0 10px;
20536      }
20537
20538     .check-element {
20539        padding:10px;
20540        border:1px solid black;
20541        background:white;
20542      }
20543     </file>
20544     <file name="protractor.js" type="protractor">
20545     var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
20546     var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
20547
20548     it('should check ng-show / ng-hide', function() {
20549        expect(thumbsUp.isDisplayed()).toBeFalsy();
20550        expect(thumbsDown.isDisplayed()).toBeTruthy();
20551
20552        element(by.model('checked')).click();
20553
20554        expect(thumbsUp.isDisplayed()).toBeTruthy();
20555        expect(thumbsDown.isDisplayed()).toBeFalsy();
20556      });
20557     </file>
20558     </example>
20559     */
20560    var ngHideDirective = ['$animate', function ($animate) {
20561        return function (scope, element, attr) {
20562            scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
20563                $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
20564            });
20565        };
20566    }];
20567
20568    /**
20569     * @ngdoc directive
20570     * @name ngStyle
20571     * @restrict AC
20572     *
20573     * @description
20574     * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
20575     *
20576     * @element ANY
20577     * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
20578     *      object whose keys are CSS style names and values are corresponding values for those CSS
20579     *      keys.
20580     *
20581     * @example
20582     <example>
20583     <file name="index.jsp">
20584     <input type="button" value="set" ng-click="myStyle={color:'red'}">
20585     <input type="button" value="clear" ng-click="myStyle={}">
20586     <br/>
20587     <span ng-style="myStyle">Sample Text</span>
20588     <pre>myStyle={{myStyle}}</pre>
20589     </file>
20590     <file name="style.css">
20591     span {
20592         color: black;
20593       }
20594     </file>
20595     <file name="protractor.js" type="protractor">
20596     var colorSpan = element(by.css('span'));
20597
20598     it('should check ng-style', function() {
20599         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20600         element(by.css('input[value=set]')).click();
20601         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
20602         element(by.css('input[value=clear]')).click();
20603         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
20604       });
20605     </file>
20606     </example>
20607     */
20608    var ngStyleDirective = ngDirective(function (scope, element, attr) {
20609        scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
20610            if (oldStyles && (newStyles !== oldStyles)) {
20611                forEach(oldStyles, function (val, style) {
20612                    element.css(style, '');
20613                });
20614            }
20615            if (newStyles) element.css(newStyles);
20616        }, true);
20617    });
20618
20619    /**
20620     * @ngdoc directive
20621     * @name ngSwitch
20622     * @restrict EA
20623     *
20624     * @description
20625     * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
20626     * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
20627     * as specified in the template.
20628     *
20629     * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
20630     * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
20631     * matches the value obtained from the evaluated expression. In other words, you define a container element
20632     * (where you place the directive), place an expression on the **`on="..."` attribute**
20633     * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
20634     * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
20635     * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
20636     * attribute is displayed.
20637     *
20638     * <div class="alert alert-info">
20639     * Be aware that the attribute values to match against cannot be expressions. They are interpreted
20640     * as literal string values to match against.
20641     * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
20642     * value of the expression `$scope.someVal`.
20643     * </div>
20644
20645     * @animations
20646     * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
20647     * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
20648     *
20649     * @usage
20650     * <ANY ng-switch="expression">
20651     *   <ANY ng-switch-when="matchValue1">...</ANY>
20652     *   <ANY ng-switch-when="matchValue2">...</ANY>
20653     *   <ANY ng-switch-default>...</ANY>
20654     * </ANY>
20655     *
20656     *
20657     * @scope
20658     * @priority 800
20659     * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
20660     * On child elements add:
20661     *
20662     * * `ngSwitchWhen`: the case statement to match against. If match then this
20663     *   case will be displayed. If the same match appears multiple times, all the
20664     *   elements will be displayed.
20665     * * `ngSwitchDefault`: the default case when no other case match. If there
20666     *   are multiple default cases, all of them will be displayed when no other
20667     *   case match.
20668     *
20669     *
20670     * @example
20671     <example module="ngAnimate" deps="angular-animate.js" animations="true">
20672     <file name="index.jsp">
20673     <div ng-controller="Ctrl">
20674     <select ng-model="selection" ng-options="item for item in items">
20675     </select>
20676     <tt>selection={{selection}}</tt>
20677     <hr/>
20678     <div class="animate-switch-container"
20679     ng-switch on="selection">
20680     <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
20681     <div class="animate-switch" ng-switch-when="home">Home Span</div>
20682     <div class="animate-switch" ng-switch-default>default</div>
20683     </div>
20684     </div>
20685     </file>
20686     <file name="script.js">
20687     function Ctrl($scope) {
20688        $scope.items = ['settings', 'home', 'other'];
20689        $scope.selection = $scope.items[0];
20690      }
20691     </file>
20692     <file name="animations.css">
20693     .animate-switch-container {
20694        position:relative;
20695        background:white;
20696        border:1px solid black;
20697        height:40px;
20698        overflow:hidden;
20699      }
20700
20701     .animate-switch {
20702        padding:10px;
20703      }
20704
20705     .animate-switch.ng-animate {
20706        -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20707        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
20708
20709        position:absolute;
20710        top:0;
20711        left:0;
20712        right:0;
20713        bottom:0;
20714      }
20715
20716     .animate-switch.ng-leave.ng-leave-active,
20717     .animate-switch.ng-enter {
20718        top:-50px;
20719      }
20720     .animate-switch.ng-leave,
20721     .animate-switch.ng-enter.ng-enter-active {
20722        top:0;
20723      }
20724     </file>
20725     <file name="protractor.js" type="protractor">
20726     var switchElem = element(by.css('[ng-switch]'));
20727     var select = element(by.model('selection'));
20728
20729     it('should start in settings', function() {
20730        expect(switchElem.getText()).toMatch(/Settings Div/);
20731      });
20732     it('should change to home', function() {
20733        select.element.all(by.css('option')).get(1).click();
20734        expect(switchElem.getText()).toMatch(/Home Span/);
20735      });
20736     it('should select default', function() {
20737        select.element.all(by.css('option')).get(2).click();
20738        expect(switchElem.getText()).toMatch(/default/);
20739      });
20740     </file>
20741     </example>
20742     */
20743    var ngSwitchDirective = ['$animate', function ($animate) {
20744        return {
20745            restrict: 'EA',
20746            require: 'ngSwitch',
20747
20748            // asks for $scope to fool the BC controller module
20749            controller: ['$scope', function ngSwitchController() {
20750                this.cases = {};
20751            }],
20752            link: function (scope, element, attr, ngSwitchController) {
20753                var watchExpr = attr.ngSwitch || attr.on,
20754                    selectedTranscludes,
20755                    selectedElements,
20756                    previousElements,
20757                    selectedScopes = [];
20758
20759                scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
20760                    var i, ii = selectedScopes.length;
20761                    if (ii > 0) {
20762                        if (previousElements) {
20763                            for (i = 0; i < ii; i++) {
20764                                previousElements[i].remove();
20765                            }
20766                            previousElements = null;
20767                        }
20768
20769                        previousElements = [];
20770                        for (i = 0; i < ii; i++) {
20771                            var selected = selectedElements[i];
20772                            selectedScopes[i].$destroy();
20773                            previousElements[i] = selected;
20774                            $animate.leave(selected, function () {
20775                                previousElements.splice(i, 1);
20776                                if (previousElements.length === 0) {
20777                                    previousElements = null;
20778                                }
20779                            });
20780                        }
20781                    }
20782
20783                    selectedElements = [];
20784                    selectedScopes = [];
20785
20786                    if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
20787                        scope.$eval(attr.change);
20788                        forEach(selectedTranscludes, function (selectedTransclude) {
20789                            var selectedScope = scope.$new();
20790                            selectedScopes.push(selectedScope);
20791                            selectedTransclude.transclude(selectedScope, function (caseElement) {
20792                                var anchor = selectedTransclude.element;
20793
20794                                selectedElements.push(caseElement);
20795                                $animate.enter(caseElement, anchor.parent(), anchor);
20796                            });
20797                        });
20798                    }
20799                });
20800            }
20801        };
20802    }];
20803
20804    var ngSwitchWhenDirective = ngDirective({
20805        transclude: 'element',
20806        priority: 800,
20807        require: '^ngSwitch',
20808        link: function (scope, element, attrs, ctrl, $transclude) {
20809            ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
20810            ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
20811        }
20812    });
20813
20814    var ngSwitchDefaultDirective = ngDirective({
20815        transclude: 'element',
20816        priority: 800,
20817        require: '^ngSwitch',
20818        link: function (scope, element, attr, ctrl, $transclude) {
20819            ctrl.cases['?'] = (ctrl.cases['?'] || []);
20820            ctrl.cases['?'].push({ transclude: $transclude, element: element });
20821        }
20822    });
20823
20824    /**
20825     * @ngdoc directive
20826     * @name ngTransclude
20827     * @restrict AC
20828     *
20829     * @description
20830     * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
20831     *
20832     * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
20833     *
20834     * @element ANY
20835     *
20836     * @example
20837     <example module="transclude">
20838     <file name="index.jsp">
20839     <script>
20840     function Ctrl($scope) {
20841           $scope.title = 'Lorem Ipsum';
20842           $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
20843         }
20844
20845     angular.module('transclude', [])
20846     .directive('pane', function(){
20847             return {
20848               restrict: 'E',
20849               transclude: true,
20850               scope: { title:'@' },
20851     template: '<div style="border: 1px solid black;">' +
20852     '<div style="background-color: gray">{{title}}</div>' +
20853     '<div ng-transclude></div>' +
20854     '</div>'
20855     };
20856     });
20857     </script>
20858     <div ng-controller="Ctrl">
20859     <input ng-model="title"><br>
20860     <textarea ng-model="text"></textarea> <br/>
20861     <pane title="{{title}}">{{text}}</pane>
20862     </div>
20863     </file>
20864     <file name="protractor.js" type="protractor">
20865     it('should have transcluded', function() {
20866          var titleElement = element(by.model('title'));
20867          titleElement.clear();
20868          titleElement.sendKeys('TITLE');
20869          var textElement = element(by.model('text'));
20870          textElement.clear();
20871          textElement.sendKeys('TEXT');
20872          expect(element(by.binding('title')).getText()).toEqual('TITLE');
20873          expect(element(by.binding('text')).getText()).toEqual('TEXT');
20874        });
20875     </file>
20876     </example>
20877     *
20878     */
20879    var ngTranscludeDirective = ngDirective({
20880        link: function ($scope, $element, $attrs, controller, $transclude) {
20881            if (!$transclude) {
20882                throw minErr('ngTransclude')('orphan',
20883                    'Illegal use of ngTransclude directive in the template! ' +
20884                        'No parent directive that requires a transclusion found. ' +
20885                        'Element: {0}',
20886                    startingTag($element));
20887            }
20888
20889            $transclude(function (clone) {
20890                $element.empty();
20891                $element.append(clone);
20892            });
20893        }
20894    });
20895
20896    /**
20897     * @ngdoc directive
20898     * @name script
20899     * @restrict E
20900     *
20901     * @description
20902     * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
20903     * template can be used by {@link ng.directive:ngInclude `ngInclude`},
20904     * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
20905     * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
20906     * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
20907     *
20908     * @param {string} type Must be set to `'text/ng-template'`.
20909     * @param {string} id Cache name of the template.
20910     *
20911     * @example
20912     <example>
20913     <file name="index.jsp">
20914     <script type="text/ng-template" id="/tpl.html">
20915     Content of the template.
20916     </script>
20917
20918     <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
20919     <div id="tpl-content" ng-include src="currentTpl"></div>
20920     </file>
20921     <file name="protractor.js" type="protractor">
20922     it('should load template defined inside script tag', function() {
20923        element(by.css('#tpl-link')).click();
20924        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
20925      });
20926     </file>
20927     </example>
20928     */
20929    var scriptDirective = ['$templateCache', function ($templateCache) {
20930        return {
20931            restrict: 'E',
20932            terminal: true,
20933            compile: function (element, attr) {
20934                if (attr.type == 'text/ng-template') {
20935                    var templateUrl = attr.id,
20936                    // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
20937                        text = element[0].text;
20938
20939                    $templateCache.put(templateUrl, text);
20940                }
20941            }
20942        };
20943    }];
20944
20945    var ngOptionsMinErr = minErr('ngOptions');
20946    /**
20947     * @ngdoc directive
20948     * @name select
20949     * @restrict E
20950     *
20951     * @description
20952     * HTML `SELECT` element with angular data-binding.
20953     *
20954     * # `ngOptions`
20955     *
20956     * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
20957     * elements for the `<select>` element using the array or object obtained by evaluating the
20958     * `ngOptions` comprehension_expression.
20959     *
20960     * When an item in the `<select>` menu is selected, the array element or object property
20961     * represented by the selected option will be bound to the model identified by the `ngModel`
20962     * directive.
20963     *
20964     * <div class="alert alert-warning">
20965     * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
20966     * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
20967     * </div>
20968     *
20969     * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
20970     * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
20971     * option. See example below for demonstration.
20972     *
20973     * <div class="alert alert-warning">
20974     * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
20975     * of {@link ng.directive:ngRepeat ngRepeat} when you want the
20976     * `select` model to be bound to a non-string value. This is because an option element can only
20977     * be bound to string values at present.
20978     * </div>
20979     *
20980     * @param {string} ngModel Assignable angular expression to data-bind to.
20981     * @param {string=} name Property name of the form under which the control is published.
20982     * @param {string=} required The control is considered valid only if value is entered.
20983     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
20984     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
20985     *    `required` when you want to data-bind to the `required` attribute.
20986     * @param {comprehension_expression=} ngOptions in one of the following forms:
20987     *
20988     *   * for array data sources:
20989     *     * `label` **`for`** `value` **`in`** `array`
20990     *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
20991     *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
20992     *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
20993     *   * for object data sources:
20994     *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20995     *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
20996     *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
20997     *     * `select` **`as`** `label` **`group by`** `group`
20998     *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
20999     *
21000     * Where:
21001     *
21002     *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
21003     *   * `value`: local variable which will refer to each item in the `array` or each property value
21004     *      of `object` during iteration.
21005     *   * `key`: local variable which will refer to a property name in `object` during iteration.
21006     *   * `label`: The result of this expression will be the label for `<option>` element. The
21007     *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
21008     *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
21009     *      element. If not specified, `select` expression will default to `value`.
21010     *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
21011     *      DOM element.
21012     *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
21013     *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
21014     *     `value` variable (e.g. `value.propertyName`).
21015     *
21016     * @example
21017     <example>
21018     <file name="index.jsp">
21019     <script>
21020     function MyCntrl($scope) {
21021          $scope.colors = [
21022            {name:'black', shade:'dark'},
21023            {name:'white', shade:'light'},
21024            {name:'red', shade:'dark'},
21025            {name:'blue', shade:'dark'},
21026            {name:'yellow', shade:'light'}
21027          ];
21028          $scope.color = $scope.colors[2]; // red
21029        }
21030     </script>
21031     <div ng-controller="MyCntrl">
21032     <ul>
21033     <li ng-repeat="color in colors">
21034     Name: <input ng-model="color.name">
21035     [<a href ng-click="colors.splice($index, 1)">X</a>]
21036     </li>
21037     <li>
21038     [<a href ng-click="colors.push({})">add</a>]
21039     </li>
21040     </ul>
21041     <hr/>
21042     Color (null not allowed):
21043     <select ng-model="color" ng-options="c.name for c in colors"></select><br>
21044
21045     Color (null allowed):
21046     <span  class="nullable">
21047     <select ng-model="color" ng-options="c.name for c in colors">
21048     <option value="">-- choose color --</option>
21049     </select>
21050     </span><br/>
21051
21052     Color grouped by shade:
21053     <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
21054     </select><br/>
21055
21056
21057     Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
21058     <hr/>
21059     Currently selected: {{ {selected_color:color}  }}
21060     <div style="border:solid 1px black; height:20px"
21061     ng-style="{'background-color':color.name}">
21062     </div>
21063     </div>
21064     </file>
21065     <file name="protractor.js" type="protractor">
21066     it('should check ng-options', function() {
21067           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('red');
21068           element.all(by.select('color')).first().click();
21069           element.all(by.css('select[ng-model="color"] option')).first().click();
21070           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('black');
21071           element(by.css('.nullable select[ng-model="color"]')).click();
21072           element.all(by.css('.nullable select[ng-model="color"] option')).first().click();
21073           expect(element(by.binding('{selected_color:color}')).getText()).toMatch('null');
21074         });
21075     </file>
21076     </example>
21077     */
21078
21079    var ngOptionsDirective = valueFn({ terminal: true });
21080// jshint maxlen: false
21081    var selectDirective = ['$compile', '$parse', function ($compile, $parse) {
21082        //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
21083        var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
21084            nullModelCtrl = {$setViewValue: noop};
21085// jshint maxlen: 100
21086
21087        return {
21088            restrict: 'E',
21089            require: ['select', '?ngModel'],
21090            controller: ['$element', '$scope', '$attrs', function ($element, $scope, $attrs) {
21091                var self = this,
21092                    optionsMap = {},
21093                    ngModelCtrl = nullModelCtrl,
21094                    nullOption,
21095                    unknownOption;
21096
21097
21098                self.databound = $attrs.ngModel;
21099
21100
21101                self.init = function (ngModelCtrl_, nullOption_, unknownOption_) {
21102                    ngModelCtrl = ngModelCtrl_;
21103                    nullOption = nullOption_;
21104                    unknownOption = unknownOption_;
21105                };
21106
21107
21108                self.addOption = function (value) {
21109                    assertNotHasOwnProperty(value, '"option value"');
21110                    optionsMap[value] = true;
21111
21112                    if (ngModelCtrl.$viewValue == value) {
21113                        $element.val(value);
21114                        if (unknownOption.parent()) unknownOption.remove();
21115                    }
21116                };
21117
21118
21119                self.removeOption = function (value) {
21120                    if (this.hasOption(value)) {
21121                        delete optionsMap[value];
21122                        if (ngModelCtrl.$viewValue == value) {
21123                            this.renderUnknownOption(value);
21124                        }
21125                    }
21126                };
21127
21128
21129                self.renderUnknownOption = function (val) {
21130                    var unknownVal = '? ' + hashKey(val) + ' ?';
21131                    unknownOption.val(unknownVal);
21132                    $element.prepend(unknownOption);
21133                    $element.val(unknownVal);
21134                    unknownOption.prop('selected', true); // needed for IE
21135                };
21136
21137
21138                self.hasOption = function (value) {
21139                    return optionsMap.hasOwnProperty(value);
21140                };
21141
21142                $scope.$on('$destroy', function () {
21143                    // disable unknown option so that we don't do work when the whole select is being destroyed
21144                    self.renderUnknownOption = noop;
21145                });
21146            }],
21147
21148            link: function (scope, element, attr, ctrls) {
21149                // if ngModel is not defined, we don't need to do anything
21150                if (!ctrls[1]) return;
21151
21152                var selectCtrl = ctrls[0],
21153                    ngModelCtrl = ctrls[1],
21154                    multiple = attr.multiple,
21155                    optionsExp = attr.ngOptions,
21156                    nullOption = false, // if false, user will not be able to select it (used by ngOptions)
21157                    emptyOption,
21158                // we can't just jqLite('<option>') since jqLite is not smart enough
21159                // to create it in <select> and IE barfs otherwise.
21160                    optionTemplate = jqLite(document.createElement('option')),
21161                    optGroupTemplate = jqLite(document.createElement('optgroup')),
21162                    unknownOption = optionTemplate.clone();
21163
21164                // find "null" option
21165                for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
21166                    if (children[i].value === '') {
21167                        emptyOption = nullOption = children.eq(i);
21168                        break;
21169                    }
21170                }
21171
21172                selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
21173
21174                // required validator
21175                if (multiple) {
21176                    ngModelCtrl.$isEmpty = function (value) {
21177                        return !value || value.length === 0;
21178                    };
21179                }
21180
21181                if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
21182                else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
21183                else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
21184
21185
21186                ////////////////////////////
21187
21188
21189                function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
21190                    ngModelCtrl.$render = function () {
21191                        var viewValue = ngModelCtrl.$viewValue;
21192
21193                        if (selectCtrl.hasOption(viewValue)) {
21194                            if (unknownOption.parent()) unknownOption.remove();
21195                            selectElement.val(viewValue);
21196                            if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
21197                        } else {
21198                            if (isUndefined(viewValue) && emptyOption) {
21199                                selectElement.val('');
21200                            } else {
21201                                selectCtrl.renderUnknownOption(viewValue);
21202                            }
21203                        }
21204                    };
21205
21206                    selectElement.on('change', function () {
21207                        scope.$apply(function () {
21208                            if (unknownOption.parent()) unknownOption.remove();
21209                            ngModelCtrl.$setViewValue(selectElement.val());
21210                        });
21211                    });
21212                }
21213
21214                function setupAsMultiple(scope, selectElement, ctrl) {
21215                    var lastView;
21216                    ctrl.$render = function () {
21217                        var items = new HashMap(ctrl.$viewValue);
21218                        forEach(selectElement.find('option'), function (option) {
21219                            option.selected = isDefined(items.get(option.value));
21220                        });
21221                    };
21222
21223                    // we have to do it on each watch since ngModel watches reference, but
21224                    // we need to work of an array, so we need to see if anything was inserted/removed
21225                    scope.$watch(function selectMultipleWatch() {
21226                        if (!equals(lastView, ctrl.$viewValue)) {
21227                            lastView = copy(ctrl.$viewValue);
21228                            ctrl.$render();
21229                        }
21230                    });
21231
21232                    selectElement.on('change', function () {
21233                        scope.$apply(function () {
21234                            var array = [];
21235                            forEach(selectElement.find('option'), function (option) {
21236                                if (option.selected) {
21237                                    array.push(option.value);
21238                                }
21239                            });
21240                            ctrl.$setViewValue(array);
21241                        });
21242                    });
21243                }
21244
21245                function setupAsOptions(scope, selectElement, ctrl) {
21246                    var match;
21247
21248                    if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
21249                        throw ngOptionsMinErr('iexp',
21250                            "Expected expression in form of " +
21251                                "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
21252                                " but got '{0}'. Element: {1}",
21253                            optionsExp, startingTag(selectElement));
21254                    }
21255
21256                    var displayFn = $parse(match[2] || match[1]),
21257                        valueName = match[4] || match[6],
21258                        keyName = match[5],
21259                        groupByFn = $parse(match[3] || ''),
21260                        valueFn = $parse(match[2] ? match[1] : valueName),
21261                        valuesFn = $parse(match[7]),
21262                        track = match[8],
21263                        trackFn = track ? $parse(match[8]) : null,
21264                    // This is an array of array of existing option groups in DOM.
21265                    // We try to reuse these if possible
21266                    // - optionGroupsCache[0] is the options with no option group
21267                    // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
21268                        optionGroupsCache = [
21269                            [
21270                                {element: selectElement, label: ''}
21271                            ]
21272                        ];
21273
21274                    if (nullOption) {
21275                        // compile the element since there might be bindings in it
21276                        $compile(nullOption)(scope);
21277
21278                        // remove the class, which is added automatically because we recompile the element and it
21279                        // becomes the compilation root
21280                        nullOption.removeClass('ng-scope');
21281
21282                        // we need to remove it before calling selectElement.empty() because otherwise IE will
21283                        // remove the label from the element. wtf?
21284                        nullOption.remove();
21285                    }
21286
21287                    // clear contents, we'll add what's needed based on the model
21288                    selectElement.empty();
21289
21290                    selectElement.on('change', function () {
21291                        scope.$apply(function () {
21292                            var optionGroup,
21293                                collection = valuesFn(scope) || [],
21294                                locals = {},
21295                                key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
21296
21297                            if (multiple) {
21298                                value = [];
21299                                for (groupIndex = 0, groupLength = optionGroupsCache.length;
21300                                     groupIndex < groupLength;
21301                                     groupIndex++) {
21302                                    // list of options for that group. (first item has the parent)
21303                                    optionGroup = optionGroupsCache[groupIndex];
21304
21305                                    for (index = 1, length = optionGroup.length; index < length; index++) {
21306                                        if ((optionElement = optionGroup[index].element)[0].selected) {
21307                                            key = optionElement.val();
21308                                            if (keyName) locals[keyName] = key;
21309                                            if (trackFn) {
21310                                                for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21311                                                    locals[valueName] = collection[trackIndex];
21312                                                    if (trackFn(scope, locals) == key) break;
21313                                                }
21314                                            } else {
21315                                                locals[valueName] = collection[key];
21316                                            }
21317                                            value.push(valueFn(scope, locals));
21318                                        }
21319                                    }
21320                                }
21321                            } else {
21322                                key = selectElement.val();
21323                                if (key == '?') {
21324                                    value = undefined;
21325                                } else if (key === '') {
21326                                    value = null;
21327                                } else {
21328                                    if (trackFn) {
21329                                        for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
21330                                            locals[valueName] = collection[trackIndex];
21331                                            if (trackFn(scope, locals) == key) {
21332                                                value = valueFn(scope, locals);
21333                                                break;
21334                                            }
21335                                        }
21336                                    } else {
21337                                        locals[valueName] = collection[key];
21338                                        if (keyName) locals[keyName] = key;
21339                                        value = valueFn(scope, locals);
21340                                    }
21341                                }
21342                                // Update the null option's selected property here so $render cleans it up correctly
21343                                if (optionGroupsCache[0].length > 1) {
21344                                    if (optionGroupsCache[0][1].id !== key) {
21345                                        optionGroupsCache[0][1].selected = false;
21346                                    }
21347                                }
21348                            }
21349                            ctrl.$setViewValue(value);
21350                        });
21351                    });
21352
21353                    ctrl.$render = render;
21354
21355                    // TODO(vojta): can't we optimize this ?
21356                    scope.$watch(render);
21357
21358                    function render() {
21359                        // Temporary location for the option groups before we render them
21360                        var optionGroups = {'': []},
21361                            optionGroupNames = [''],
21362                            optionGroupName,
21363                            optionGroup,
21364                            option,
21365                            existingParent, existingOptions, existingOption,
21366                            modelValue = ctrl.$modelValue,
21367                            values = valuesFn(scope) || [],
21368                            keys = keyName ? sortedKeys(values) : values,
21369                            key,
21370                            groupLength, length,
21371                            groupIndex, index,
21372                            locals = {},
21373                            selected,
21374                            selectedSet = false, // nothing is selected yet
21375                            lastElement,
21376                            element,
21377                            label;
21378
21379                        if (multiple) {
21380                            if (trackFn && isArray(modelValue)) {
21381                                selectedSet = new HashMap([]);
21382                                for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
21383                                    locals[valueName] = modelValue[trackIndex];
21384                                    selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
21385                                }
21386                            } else {
21387                                selectedSet = new HashMap(modelValue);
21388                            }
21389                        }
21390
21391                        // We now build up the list of options we need (we merge later)
21392                        for (index = 0; length = keys.length, index < length; index++) {
21393
21394                            key = index;
21395                            if (keyName) {
21396                                key = keys[index];
21397                                if (key.charAt(0) === '$') continue;
21398                                locals[keyName] = key;
21399                            }
21400
21401                            locals[valueName] = values[key];
21402
21403                            optionGroupName = groupByFn(scope, locals) || '';
21404                            if (!(optionGroup = optionGroups[optionGroupName])) {
21405                                optionGroup = optionGroups[optionGroupName] = [];
21406                                optionGroupNames.push(optionGroupName);
21407                            }
21408                            if (multiple) {
21409                                selected = isDefined(
21410                                    selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
21411                                );
21412                            } else {
21413                                if (trackFn) {
21414                                    var modelCast = {};
21415                                    modelCast[valueName] = modelValue;
21416                                    selected = trackFn(scope, modelCast) === trackFn(scope, locals);
21417                                } else {
21418                                    selected = modelValue === valueFn(scope, locals);
21419                                }
21420                                selectedSet = selectedSet || selected; // see if at least one item is selected
21421                            }
21422                            label = displayFn(scope, locals); // what will be seen by the user
21423
21424                            // doing displayFn(scope, locals) || '' overwrites zero values
21425                            label = isDefined(label) ? label : '';
21426                            optionGroup.push({
21427                                // either the index into array or key from object
21428                                id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
21429                                label: label,
21430                                selected: selected                   // determine if we should be selected
21431                            });
21432                        }
21433                        if (!multiple) {
21434                            if (nullOption || modelValue === null) {
21435                                // insert null option if we have a placeholder, or the model is null
21436                                optionGroups[''].unshift({id: '', label: '', selected: !selectedSet});
21437                            } else if (!selectedSet) {
21438                                // option could not be found, we have to insert the undefined item
21439                                optionGroups[''].unshift({id: '?', label: '', selected: true});
21440                            }
21441                        }
21442
21443                        // Now we need to update the list of DOM nodes to match the optionGroups we computed above
21444                        for (groupIndex = 0, groupLength = optionGroupNames.length;
21445                             groupIndex < groupLength;
21446                             groupIndex++) {
21447                            // current option group name or '' if no group
21448                            optionGroupName = optionGroupNames[groupIndex];
21449
21450                            // list of options for that group. (first item has the parent)
21451                            optionGroup = optionGroups[optionGroupName];
21452
21453                            if (optionGroupsCache.length <= groupIndex) {
21454                                // we need to grow the optionGroups
21455                                existingParent = {
21456                                    element: optGroupTemplate.clone().attr('label', optionGroupName),
21457                                    label: optionGroup.label
21458                                };
21459                                existingOptions = [existingParent];
21460                                optionGroupsCache.push(existingOptions);
21461                                selectElement.append(existingParent.element);
21462                            } else {
21463                                existingOptions = optionGroupsCache[groupIndex];
21464                                existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
21465
21466                                // update the OPTGROUP label if not the same.
21467                                if (existingParent.label != optionGroupName) {
21468                                    existingParent.element.attr('label', existingParent.label = optionGroupName);
21469                                }
21470                            }
21471
21472                            lastElement = null;  // start at the beginning
21473                            for (index = 0, length = optionGroup.length; index < length; index++) {
21474                                option = optionGroup[index];
21475                                if ((existingOption = existingOptions[index + 1])) {
21476                                    // reuse elements
21477                                    lastElement = existingOption.element;
21478                                    if (existingOption.label !== option.label) {
21479                                        lastElement.text(existingOption.label = option.label);
21480                                    }
21481                                    if (existingOption.id !== option.id) {
21482                                        lastElement.val(existingOption.id = option.id);
21483                                    }
21484                                    // lastElement.prop('selected') provided by jQuery has side-effects
21485                                    if (existingOption.selected !== option.selected) {
21486                                        lastElement.prop('selected', 
21486(existingOption.selected = option.selected));
21487                                    }
21488                                } else {
21489                                    // grow elements
21490
21491                                    // if it's a null option
21492                                    if (option.id === '' && nullOption) {
21493                                        // put back the pre-compiled element
21494                                        element = nullOption;
21495                                    } else {
21496                                        // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
21497                                        // in this version of jQuery on some browser the .text() returns a string
21498                                        // rather then the element.
21499                                        (element = optionTemplate.clone())
21500                                            .val(option.id)
21501                                            .attr('selected', option.selected)
21502                                            .text(option.label);
21503                                    }
21504
21505                                    existingOptions.push(existingOption = {
21506                                        element: element,
21507                                        label: option.label,
21508                                        id: option.id,
21509                                        selected: option.selected
21510                                    });
21511                                    if (lastElement) {
21512                                        lastElement.after(element);
21513                                    } else {
21514                                        existingParent.element.append(element);
21515                                    }
21516                                    lastElement = element;
21517                                }
21518                            }
21519                            // remove any excessive OPTIONs in a group
21520                            index++; // increment since the existingOptions[0] is parent element not OPTION
21521                            while (existingOptions.length > index) {
21522                                existingOptions.pop().element.remove();
21523                            }
21524                        }
21525                        // remove any excessive OPTGROUPs from select
21526                        while (optionGroupsCache.length > groupIndex) {
21527                            optionGroupsCache.pop()[0].element.remove();
21528                        }
21529                    }
21530                }
21531            }
21532        };
21533    }];
21534
21535    var optionDirective = ['$interpolate', function ($interpolate) {
21536        var nullSelectCtrl = {
21537            addOption: noop,
21538            removeOption: noop
21539        };
21540
21541        return {
21542            restrict: 'E',
21543            priority: 100,
21544            compile: function (element, attr) {
21545                if (isUndefined(attr.value)) {
21546                    var interpolateFn = $interpolate(element.text(), true);
21547                    if (!interpolateFn) {
21548                        attr.$set('value', element.text());
21549                    }
21550                }
21551
21552                return function (scope, element, attr) {
21553                    var selectCtrlName = '$selectController',
21554                        parent = element.parent(),
21555                        selectCtrl = parent.data(selectCtrlName) ||
21556                            parent.parent().data(selectCtrlName); // in case we are in optgroup
21557
21558                    if (selectCtrl && selectCtrl.databound) {
21559                        // For some reason Opera defaults to true and if not overridden this messes up the repeater.
21560                        // We don't want the view to drive the initialization of the model anyway.
21561                        element.prop('selected', false);
21562                    } else {
21563                        selectCtrl = nullSelectCtrl;
21564                    }
21565
21566                    if (interpolateFn) {
21567                        scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
21568                            attr.$set('value', newVal);
21569                            if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
21570                            selectCtrl.addOption(newVal);
21571                        });
21572                    } else {
21573                        selectCtrl.addOption(attr.value);
21574                    }
21575
21576                    element.on('$destroy', function () {
21577                        selectCtrl.removeOption(attr.value);
21578                    });
21579                };
21580            }
21581        };
21582    }];
21583
21584    var styleDirective = valueFn({
21585        restrict: 'E',
21586        terminal: true
21587    });
21588
21589    if (window.angular.bootstrap) {
21590        //AngularJS is already loaded, so we can return here...
21591        console.log('WARNING: Tried to load angular more than once.');
21592        return;
21593    }
21594
21595    //try to bind to jquery now so that one can write angular.element().read()
21596    //but we will rebind on bootstrap again.
21597    bindJQuery();
21598
21599    publishExternalAPI(angular);
21600
21601    jqLite(document).ready(function () {
21602        angularInit(document, bootstrap);
21603    });
21604
21605})(window, document);
21606
21607!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-block-transitions{transition:0s all!important;-webkit-transition:0s all!important;}</style>');

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