Built motion from commit 7767ffc.|0.0.132
[motion.git] / public / bower_components / angular-scenario / angular-scenario.js
1 /*!
2  * jQuery JavaScript Library v2.1.1
3  * http://jquery.com/
4  *
5  * Includes Sizzle.js
6  * http://sizzlejs.com/
7  *
8  * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
9  * Released under the MIT license
10  * http://jquery.org/license
11  *
12  * Date: 2014-05-01T17:11Z
13  */
14
15 (function( global, factory ) {'use strict';
16
17         if ( typeof module === "object" && typeof module.exports === "object" ) {
18                 // For CommonJS and CommonJS-like environments where a proper window is present,
19                 // execute the factory and get jQuery
20                 // For environments that do not inherently posses a window with a document
21                 // (such as Node.js), expose a jQuery-making factory as module.exports
22                 // This accentuates the need for the creation of a real window
23                 // e.g. var jQuery = require("jquery")(window);
24                 // See ticket #14549 for more info
25                 module.exports = global.document ?
26                         factory( global, true ) :
27                         function( w ) {
28                                 if ( !w.document ) {
29                                         throw new Error( "jQuery requires a window with a document" );
30                                 }
31                                 return factory( w );
32                         };
33         } else {
34                 factory( global );
35         }
36
37 // Pass this if window is not defined yet
38 }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
39
40 // Can't do this because several apps including ASP.NET trace
41 // the stack via arguments.caller.callee and Firefox dies if
42 // you try to trace through "use strict" call chains. (#13335)
43 // Support: Firefox 18+
44 //
45
46 var arr = [];
47
48 var slice = arr.slice;
49
50 var concat = arr.concat;
51
52 var push = arr.push;
53
54 var indexOf = arr.indexOf;
55
56 var class2type = {};
57
58 var toString = class2type.toString;
59
60 var hasOwn = class2type.hasOwnProperty;
61
62 var support = {};
63
64
65
66 var
67         // Use the correct document accordingly with window argument (sandbox)
68         document = window.document,
69
70         version = "2.1.1",
71
72         // Define a local copy of jQuery
73         jQuery = function( selector, context ) {
74                 // The jQuery object is actually just the init constructor 'enhanced'
75                 // Need init if jQuery is called (just allow error to be thrown if not included)
76                 return new jQuery.fn.init( selector, context );
77         },
78
79         // Support: Android<4.1
80         // Make sure we trim BOM and NBSP
81         rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
82
83         // Matches dashed string for camelizing
84         rmsPrefix = /^-ms-/,
85         rdashAlpha = /-([\da-z])/gi,
86
87         // Used by jQuery.camelCase as callback to replace()
88         fcamelCase = function( all, letter ) {
89                 return letter.toUpperCase();
90         };
91
92 jQuery.fn = jQuery.prototype = {
93         // The current version of jQuery being used
94         jquery: version,
95
96         constructor: jQuery,
97
98         // Start with an empty selector
99         selector: "",
100
101         // The default length of a jQuery object is 0
102         length: 0,
103
104         toArray: function() {
105                 return slice.call( this );
106         },
107
108         // Get the Nth element in the matched element set OR
109         // Get the whole matched element set as a clean array
110         get: function( num ) {
111                 return num != null ?
112
113                         // Return just the one element from the set
114                         ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
115
116                         // Return all the elements in a clean array
117                         slice.call( this );
118         },
119
120         // Take an array of elements and push it onto the stack
121         // (returning the new matched element set)
122         pushStack: function( elems ) {
123
124                 // Build a new jQuery matched element set
125                 var ret = jQuery.merge( this.constructor(), elems );
126
127                 // Add the old object onto the stack (as a reference)
128                 ret.prevObject = this;
129                 ret.context = this.context;
130
131                 // Return the newly-formed element set
132                 return ret;
133         },
134
135         // Execute a callback for every element in the matched set.
136         // (You can seed the arguments with an array of args, but this is
137         // only used internally.)
138         each: function( callback, args ) {
139                 return jQuery.each( this, callback, args );
140         },
141
142         map: function( callback ) {
143                 return this.pushStack( jQuery.map(this, function( elem, i ) {
144                         return callback.call( elem, i, elem );
145                 }));
146         },
147
148         slice: function() {
149                 return this.pushStack( slice.apply( this, arguments ) );
150         },
151
152         first: function() {
153                 return this.eq( 0 );
154         },
155
156         last: function() {
157                 return this.eq( -1 );
158         },
159
160         eq: function( i ) {
161                 var len = this.length,
162                         j = +i + ( i < 0 ? len : 0 );
163                 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
164         },
165
166         end: function() {
167                 return this.prevObject || this.constructor(null);
168         },
169
170         // For internal use only.
171         // Behaves like an Array's method, not like a jQuery method.
172         push: push,
173         sort: arr.sort,
174         splice: arr.splice
175 };
176
177 jQuery.extend = jQuery.fn.extend = function() {
178         var options, name, src, copy, copyIsArray, clone,
179                 target = arguments[0] || {},
180                 i = 1,
181                 length = arguments.length,
182                 deep = false;
183
184         // Handle a deep copy situation
185         if ( typeof target === "boolean" ) {
186                 deep = target;
187
188                 // skip the boolean and the target
189                 target = arguments[ i ] || {};
190                 i++;
191         }
192
193         // Handle case when target is a string or something (possible in deep copy)
194         if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
195                 target = {};
196         }
197
198         // extend jQuery itself if only one argument is passed
199         if ( i === length ) {
200                 target = this;
201                 i--;
202         }
203
204         for ( ; i < length; i++ ) {
205                 // Only deal with non-null/undefined values
206                 if ( (options = arguments[ i ]) != null ) {
207                         // Extend the base object
208                         for ( name in options ) {
209                                 src = target[ name ];
210                                 copy = options[ name ];
211
212                                 // Prevent never-ending loop
213                                 if ( target === copy ) {
214                                         continue;
215                                 }
216
217                                 // Recurse if we're merging plain objects or arrays
218                                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
219                                         if ( copyIsArray ) {
220                                                 copyIsArray = false;
221                                                 clone = src && jQuery.isArray(src) ? src : [];
222
223                                         } else {
224                                                 clone = src && jQuery.isPlainObject(src) ? src : {};
225                                         }
226
227                                         // Never move original objects, clone them
228                                         target[ name ] = jQuery.extend( deep, clone, copy );
229
230                                 // Don't bring in undefined values
231                                 } else if ( copy !== undefined ) {
232                                         target[ name ] = copy;
233                                 }
234                         }
235                 }
236         }
237
238         // Return the modified object
239         return target;
240 };
241
242 jQuery.extend({
243         // Unique for each copy of jQuery on the page
244         expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
245
246         // Assume jQuery is ready without the ready module
247         isReady: true,
248
249         error: function( msg ) {
250                 throw new Error( msg );
251         },
252
253         noop: function() {},
254
255         // See test/unit/core.js for details concerning isFunction.
256         // Since version 1.3, DOM methods and functions like alert
257         // aren't supported. They return false on IE (#2968).
258         isFunction: function( obj ) {
259                 return jQuery.type(obj) === "function";
260         },
261
262         isArray: Array.isArray,
263
264         isWindow: function( obj ) {
265                 return obj != null && obj === obj.window;
266         },
267
268         isNumeric: function( obj ) {
269                 // parseFloat NaNs numeric-cast false positives (null|true|false|"")
270                 // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
271                 // subtraction forces infinities to NaN
272                 return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
273         },
274
275         isPlainObject: function( obj ) {
276                 // Not plain objects:
277                 // - Any object or value whose internal [[Class]] property is not "[object Object]"
278                 // - DOM nodes
279                 // - window
280                 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
281                         return false;
282                 }
283
284                 if ( obj.constructor &&
285                                 !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
286                         return false;
287                 }
288
289                 // If the function hasn't returned already, we're confident that
290                 // |obj| is a plain object, created by {} or constructed with new Object
291                 return true;
292         },
293
294         isEmptyObject: function( obj ) {
295                 var name;
296                 for ( name in obj ) {
297                         return false;
298                 }
299                 return true;
300         },
301
302         type: function( obj ) {
303                 if ( obj == null ) {
304                         return obj + "";
305                 }
306                 // Support: Android < 4.0, iOS < 6 (functionish RegExp)
307                 return typeof obj === "object" || typeof obj === "function" ?
308                         class2type[ toString.call(obj) ] || "object" :
309                         typeof obj;
310         },
311
312         // Evaluates a script in a global context
313         globalEval: function( code ) {
314                 var script,
315                         indirect = eval;
316
317                 code = jQuery.trim( code );
318
319                 if ( code ) {
320                         // If the code includes a valid, prologue position
321                         // strict mode pragma, execute code by injecting a
322                         // script tag into the document.
323                         if ( code.indexOf("use strict") === 1 ) {
324                                 script = document.createElement("script");
325                                 script.text = code;
326                                 document.head.appendChild( script ).parentNode.removeChild( script );
327                         } else {
328                         // Otherwise, avoid the DOM node creation, insertion
329                         // and removal by using an indirect global eval
330                                 indirect( code );
331                         }
332                 }
333         },
334
335         // Convert dashed to camelCase; used by the css and data modules
336         // Microsoft forgot to hump their vendor prefix (#9572)
337         camelCase: function( string ) {
338                 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
339         },
340
341         nodeName: function( elem, name ) {
342                 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
343         },
344
345         // args is for internal usage only
346         each: function( obj, callback, args ) {
347                 var value,
348                         i = 0,
349                         length = obj.length,
350                         isArray = isArraylike( obj );
351
352                 if ( args ) {
353                         if ( isArray ) {
354                                 for ( ; i < length; i++ ) {
355                                         value = callback.apply( obj[ i ], args );
356
357                                         if ( value === false ) {
358                                                 break;
359                                         }
360                                 }
361                         } else {
362                                 for ( i in obj ) {
363                                         value = callback.apply( obj[ i ], args );
364
365                                         if ( value === false ) {
366                                                 break;
367                                         }
368                                 }
369                         }
370
371                 // A special, fast, case for the most common use of each
372                 } else {
373                         if ( isArray ) {
374                                 for ( ; i < length; i++ ) {
375                                         value = callback.call( obj[ i ], i, obj[ i ] );
376
377                                         if ( value === false ) {
378                                                 break;
379                                         }
380                                 }
381                         } else {
382                                 for ( i in obj ) {
383                                         value = callback.call( obj[ i ], i, obj[ i ] );
384
385                                         if ( value === false ) {
386                                                 break;
387                                         }
388                                 }
389                         }
390                 }
391
392                 return obj;
393         },
394
395         // Support: Android<4.1
396         trim: function( text ) {
397                 return text == null ?
398                         "" :
399                         ( text + "" ).replace( rtrim, "" );
400         },
401
402         // results is for internal usage only
403         makeArray: function( arr, results ) {
404                 var ret = results || [];
405
406                 if ( arr != null ) {
407                         if ( isArraylike( Object(arr) ) ) {
408                                 jQuery.merge( ret,
409                                         typeof arr === "string" ?
410                                         [ arr ] : arr
411                                 );
412                         } else {
413                                 push.call( ret, arr );
414                         }
415                 }
416
417                 return ret;
418         },
419
420         inArray: function( elem, arr, i ) {
421                 return arr == null ? -1 : indexOf.call( arr, elem, i );
422         },
423
424         merge: function( first, second ) {
425                 var len = +second.length,
426                         j = 0,
427                         i = first.length;
428
429                 for ( ; j < len; j++ ) {
430                         first[ i++ ] = second[ j ];
431                 }
432
433                 first.length = i;
434
435                 return first;
436         },
437
438         grep: function( elems, callback, invert ) {
439                 var callbackInverse,
440                         matches = [],
441                         i = 0,
442                         length = elems.length,
443                         callbackExpect = !invert;
444
445                 // Go through the array, only saving the items
446                 // that pass the validator function
447                 for ( ; i < length; i++ ) {
448                         callbackInverse = !callback( elems[ i ], i );
449                         if ( callbackInverse !== callbackExpect ) {
450                                 matches.push( elems[ i ] );
451                         }
452                 }
453
454                 return matches;
455         },
456
457         // arg is for internal usage only
458         map: function( elems, callback, arg ) {
459                 var value,
460                         i = 0,
461                         length = elems.length,
462                         isArray = isArraylike( elems ),
463                         ret = [];
464
465                 // Go through the array, translating each of the items to their new values
466                 if ( isArray ) {
467                         for ( ; i < length; i++ ) {
468                                 value = callback( elems[ i ], i, arg );
469
470                                 if ( value != null ) {
471                                         ret.push( value );
472                                 }
473                         }
474
475                 // Go through every key on the object,
476                 } else {
477                         for ( i in elems ) {
478                                 value = callback( elems[ i ], i, arg );
479
480                                 if ( value != null ) {
481                                         ret.push( value );
482                                 }
483                         }
484                 }
485
486                 // Flatten any nested arrays
487                 return concat.apply( [], ret );
488         },
489
490         // A global GUID counter for objects
491         guid: 1,
492
493         // Bind a function to a context, optionally partially applying any
494         // arguments.
495         proxy: function( fn, context ) {
496                 var tmp, args, proxy;
497
498                 if ( typeof context === "string" ) {
499                         tmp = fn[ context ];
500                         context = fn;
501                         fn = tmp;
502                 }
503
504                 // Quick check to determine if target is callable, in the spec
505                 // this throws a TypeError, but we will just return undefined.
506                 if ( !jQuery.isFunction( fn ) ) {
507                         return undefined;
508                 }
509
510                 // Simulated bind
511                 args = slice.call( arguments, 2 );
512                 proxy = function() {
513                         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
514                 };
515
516                 // Set the guid of unique handler to the same of original handler, so it can be removed
517                 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
518
519                 return proxy;
520         },
521
522         now: Date.now,
523
524         // jQuery.support is not used in Core but other projects attach their
525         // properties to it so it needs to exist.
526         support: support
527 });
528
529 // Populate the class2type map
530 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
531         class2type[ "[object " + name + "]" ] = name.toLowerCase();
532 });
533
534 function isArraylike( obj ) {
535         var length = obj.length,
536                 type = jQuery.type( obj );
537
538         if ( type === "function" || jQuery.isWindow( obj ) ) {
539                 return false;
540         }
541
542         if ( obj.nodeType === 1 && length ) {
543                 return true;
544         }
545
546         return type === "array" || length === 0 ||
547                 typeof length === "number" && length > 0 && ( length - 1 ) in obj;
548 }
549 var Sizzle =
550 /*!
551  * Sizzle CSS Selector Engine v1.10.19
552  * http://sizzlejs.com/
553  *
554  * Copyright 2013 jQuery Foundation, Inc. and other contributors
555  * Released under the MIT license
556  * http://jquery.org/license
557  *
558  * Date: 2014-04-18
559  */
560 (function( window ) {
561
562 var i,
563         support,
564         Expr,
565         getText,
566         isXML,
567         tokenize,
568         compile,
569         select,
570         outermostContext,
571         sortInput,
572         hasDuplicate,
573
574         // Local document vars
575         setDocument,
576         document,
577         docElem,
578         documentIsHTML,
579         rbuggyQSA,
580         rbuggyMatches,
581         matches,
582         contains,
583
584         // Instance-specific data
585         expando = "sizzle" + -(new Date()),
586         preferredDoc = window.document,
587         dirruns = 0,
588         done = 0,
589         classCache = createCache(),
590         tokenCache = createCache(),
591         compilerCache = createCache(),
592         sortOrder = function( a, b ) {
593                 if ( a === b ) {
594                         hasDuplicate = true;
595                 }
596                 return 0;
597         },
598
599         // General-purpose constants
600         strundefined = typeof undefined,
601         MAX_NEGATIVE = 1 << 31,
602
603         // Instance methods
604         hasOwn = ({}).hasOwnProperty,
605         arr = [],
606         pop = arr.pop,
607         push_native = arr.push,
608         push = arr.push,
609         slice = arr.slice,
610         // Use a stripped-down indexOf if we can't use a native one
611         indexOf = arr.indexOf || function( elem ) {
612                 var i = 0,
613                         len = this.length;
614                 for ( ; i < len; i++ ) {
615                         if ( this[i] === elem ) {
616                                 return i;
617                         }
618                 }
619                 return -1;
620         },
621
622         booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
623
624         // Regular expressions
625
626         // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
627         whitespace = "[\\x20\\t\\r\\n\\f]",
628         // http://www.w3.org/TR/css3-syntax/#characters
629         characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
630
631         // Loosely modeled on CSS identifier characters
632         // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
633         // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
634         identifier = characterEncoding.replace( "w", "w#" ),
635
636         // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
637         attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
638                 // Operator (capture 2)
639                 "*([*^$|!~]?=)" + whitespace +
640                 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
641                 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
642                 "*\\]",
643
644         pseudos = ":(" + characterEncoding + ")(?:\\((" +
645                 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
646                 // 1. quoted (capture 3; capture 4 or capture 5)
647                 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
648                 // 2. simple (capture 6)
649                 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
650                 // 3. anything else (capture 2)
651                 ".*" +
652                 ")\\)|)",
653
654         // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
655         rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
656
657         rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
658         rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
659
660         rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
661
662         rpseudo = new RegExp( pseudos ),
663         ridentifier = new RegExp( "^" + identifier + "$" ),
664
665         matchExpr = {
666                 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
667                 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
668                 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
669                 "ATTR": new RegExp( "^" + attributes ),
670                 "PSEUDO": new RegExp( "^" + pseudos ),
671                 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
672                         "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
673                         "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
674                 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
675                 // For use in libraries implementing .is()
676                 // We use this for POS matching in `select`
677                 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
678                         whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
679         },
680
681         rinputs = /^(?:input|select|textarea|button)$/i,
682         rheader = /^h\d$/i,
683
684         rnative = /^[^{]+\{\s*\[native \w/,
685
686         // Easily-parseable/retrievable ID or TAG or CLASS selectors
687         rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
688
689         rsibling = /[+~]/,
690         rescape = /'|\\/g,
691
692         // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
693         runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
694         funescape = function( _, escaped, escapedWhitespace ) {
695                 var high = "0x" + escaped - 0x10000;
696                 // NaN means non-codepoint
697                 // Support: Firefox<24
698                 // Workaround erroneous numeric interpretation of +"0x"
699                 return high !== high || escapedWhitespace ?
700                         escaped :
701                         high < 0 ?
702                                 // BMP codepoint
703                                 String.fromCharCode( high + 0x10000 ) :
704                                 // Supplemental Plane codepoint (surrogate pair)
705                                 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
706         };
707
708 // Optimize for push.apply( _, NodeList )
709 try {
710         push.apply(
711                 (arr = slice.call( preferredDoc.childNodes )),
712                 preferredDoc.childNodes
713         );
714         // Support: Android<4.0
715         // Detect silently failing push.apply
716         arr[ preferredDoc.childNodes.length ].nodeType;
717 } catch ( e ) {
718         push = { apply: arr.length ?
719
720                 // Leverage slice if possible
721                 function( target, els ) {
722                         push_native.apply( target, slice.call(els) );
723                 } :
724
725                 // Support: IE<9
726                 // Otherwise append directly
727                 function( target, els ) {
728                         var j = target.length,
729                                 i = 0;
730                         // Can't trust NodeList.length
731                         while ( (target[j++] = els[i++]) ) {}
732                         target.length = j - 1;
733                 }
734         };
735 }
736
737 function Sizzle( selector, context, results, seed ) {
738         var match, elem, m, nodeType,
739                 // QSA vars
740                 i, groups, old, nid, newContext, newSelector;
741
742         if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
743                 setDocument( context );
744         }
745
746         context = context || document;
747         results = results || [];
748
749         if ( !selector || typeof selector !== "string" ) {
750                 return results;
751         }
752
753         if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
754                 return [];
755         }
756
757         if ( documentIsHTML && !seed ) {
758
759                 // Shortcuts
760                 if ( (match = rquickExpr.exec( selector )) ) {
761                         // Speed-up: Sizzle("#ID")
762                         if ( (m = match[1]) ) {
763                                 if ( nodeType === 9 ) {
764                                         elem = context.getElementById( m );
765                                         // Check parentNode to catch when Blackberry 4.6 returns
766                                         // nodes that are no longer in the document (jQuery #6963)
767                                         if ( elem && elem.parentNode ) {
768                                                 // Handle the case where IE, Opera, and Webkit return items
769                                                 // by name instead of ID
770                                                 if ( elem.id === m ) {
771                                                         results.push( elem );
772                                                         return results;
773                                                 }
774                                         } else {
775                                                 return results;
776                                         }
777                                 } else {
778                                         // Context is not a document
779                                         if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
780                                                 contains( context, elem ) && elem.id === m ) {
781                                                 results.push( elem );
782                                                 return results;
783                                         }
784                                 }
785
786                         // Speed-up: Sizzle("TAG")
787                         } else if ( match[2] ) {
788                                 push.apply( results, context.getElementsByTagName( selector ) );
789                                 return results;
790
791                         // Speed-up: Sizzle(".CLASS")
792                         } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
793                                 push.apply( results, context.getElementsByClassName( m ) );
794                                 return results;
795                         }
796                 }
797
798                 // QSA path
799                 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
800                         nid = old = expando;
801                         newContext = context;
802                         newSelector = nodeType === 9 && selector;
803
804                         // qSA works strangely on Element-rooted queries
805                         // We can work around this by specifying an extra ID on the root
806                         // and working up from there (Thanks to Andrew Dupont for the technique)
807                         // IE 8 doesn't work on object elements
808                         if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
809                                 groups = tokenize( selector );
810
811                                 if ( (old = context.getAttribute("id")) ) {
812                                         nid = old.replace( rescape, "\\$&" );
813                                 } else {
814                                         context.setAttribute( "id", nid );
815                                 }
816                                 nid = "[id='" + nid + "'] ";
817
818                                 i = groups.length;
819                                 while ( i-- ) {
820                                         groups[i] = nid + toSelector( groups[i] );
821                                 }
822                                 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
823                                 newSelector = groups.join(",");
824                         }
825
826                         if ( newSelector ) {
827                                 try {
828                                         push.apply( results,
829                                                 newContext.querySelectorAll( newSelector )
830                                         );
831                                         return results;
832                                 } catch(qsaError) {
833                                 } finally {
834                                         if ( !old ) {
835                                                 context.removeAttribute("id");
836                                         }
837                                 }
838                         }
839                 }
840         }
841
842         // All others
843         return select( selector.replace( rtrim, "$1" ), context, results, seed );
844 }
845
846 /**
847  * Create key-value caches of limited size
848  * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
849  *      property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
850  *      deleting the oldest entry
851  */
852 function createCache() {
853         var keys = [];
854
855         function cache( key, value ) {
856                 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
857                 if ( keys.push( key + " " ) > Expr.cacheLength ) {
858                         // Only keep the most recent entries
859                         delete cache[ keys.shift() ];
860                 }
861                 return (cache[ key + " " ] = value);
862         }
863         return cache;
864 }
865
866 /**
867  * Mark a function for special use by Sizzle
868  * @param {Function} fn The function to mark
869  */
870 function markFunction( fn ) {
871         fn[ expando ] = true;
872         return fn;
873 }
874
875 /**
876  * Support testing using an element
877  * @param {Function} fn Passed the created div and expects a boolean result
878  */
879 function assert( fn ) {
880         var div = document.createElement("div");
881
882         try {
883                 return !!fn( div );
884         } catch (e) {
885                 return false;
886         } finally {
887                 // Remove from its parent by default
888                 if ( div.parentNode ) {
889                         div.parentNode.removeChild( div );
890                 }
891                 // release memory in IE
892                 div = null;
893         }
894 }
895
896 /**
897  * Adds the same handler for all of the specified attrs
898  * @param {String} attrs Pipe-separated list of attributes
899  * @param {Function} handler The method that will be applied
900  */
901 function addHandle( attrs, handler ) {
902         var arr = attrs.split("|"),
903                 i = attrs.length;
904
905         while ( i-- ) {
906                 Expr.attrHandle[ arr[i] ] = handler;
907         }
908 }
909
910 /**
911  * Checks document order of two siblings
912  * @param {Element} a
913  * @param {Element} b
914  * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
915  */
916 function siblingCheck( a, b ) {
917         var cur = b && a,
918                 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
919                         ( ~b.sourceIndex || MAX_NEGATIVE ) -
920                         ( ~a.sourceIndex || MAX_NEGATIVE );
921
922         // Use IE sourceIndex if available on both nodes
923         if ( diff ) {
924                 return diff;
925         }
926
927         // Check if b follows a
928         if ( cur ) {
929                 while ( (cur = cur.nextSibling) ) {
930                         if ( cur === b ) {
931                                 return -1;
932                         }
933                 }
934         }
935
936         return a ? 1 : -1;
937 }
938
939 /**
940  * Returns a function to use in pseudos for input types
941  * @param {String} type
942  */
943 function createInputPseudo( type ) {
944         return function( elem ) {
945                 var name = elem.nodeName.toLowerCase();
946                 return name === "input" && elem.type === type;
947         };
948 }
949
950 /**
951  * Returns a function to use in pseudos for buttons
952  * @param {String} type
953  */
954 function createButtonPseudo( type ) {
955         return function( elem ) {
956                 var name = elem.nodeName.toLowerCase();
957                 return (name === "input" || name === "button") && elem.type === type;
958         };
959 }
960
961 /**
962  * Returns a function to use in pseudos for positionals
963  * @param {Function} fn
964  */
965 function createPositionalPseudo( fn ) {
966         return markFunction(function( argument ) {
967                 argument = +argument;
968                 return markFunction(function( seed, matches ) {
969                         var j,
970                                 matchIndexes = fn( [], seed.length, argument ),
971                                 i = matchIndexes.length;
972
973                         // Match elements found at the specified indexes
974                         while ( i-- ) {
975                                 if ( seed[ (j = matchIndexes[i]) ] ) {
976                                         seed[j] = !(matches[j] = seed[j]);
977                                 }
978                         }
979                 });
980         });
981 }
982
983 /**
984  * Checks a node for validity as a Sizzle context
985  * @param {Element|Object=} context
986  * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
987  */
988 function testContext( context ) {
989         return context && typeof context.getElementsByTagName !== strundefined && context;
990 }
991
992 // Expose support vars for convenience
993 support = Sizzle.support = {};
994
995 /**
996  * Detects XML nodes
997  * @param {Element|Object} elem An element or a document
998  * @returns {Boolean} True iff elem is a non-HTML XML node
999  */
1000 isXML = Sizzle.isXML = function( elem ) {
1001         // documentElement is verified for cases where it doesn't yet exist
1002         // (such as loading iframes in IE - #4833)
1003         var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1004         return documentElement ? documentElement.nodeName !== "HTML" : false;
1005 };
1006
1007 /**
1008  * Sets document-related variables once based on the current document
1009  * @param {Element|Object} [doc] An element or document object to use to set the document
1010  * @returns {Object} Returns the current document
1011  */
1012 setDocument = Sizzle.setDocument = function( node ) {
1013         var hasCompare,
1014                 doc = node ? node.ownerDocument || node : preferredDoc,
1015                 parent = doc.defaultView;
1016
1017         // If no document and documentElement is available, return
1018         if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1019                 return document;
1020         }
1021
1022         // Set our document
1023         document = doc;
1024         docElem = doc.documentElement;
1025
1026         // Support tests
1027         documentIsHTML = !isXML( doc );
1028
1029         // Support: IE>8
1030         // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1031         // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1032         // IE6-8 do not support the defaultView property so parent will be undefined
1033         if ( parent && parent !== parent.top ) {
1034                 // IE11 does not have attachEvent, so all must suffer
1035                 if ( parent.addEventListener ) {
1036                         parent.addEventListener( "unload", function() {
1037                                 setDocument();
1038                         }, false );
1039                 } else if ( parent.attachEvent ) {
1040                         parent.attachEvent( "onunload", function() {
1041                                 setDocument();
1042                         });
1043                 }
1044         }
1045
1046         /* Attributes
1047         ---------------------------------------------------------------------- */
1048
1049         // Support: IE<8
1050         // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1051         support.attributes = assert(function( div ) {
1052                 div.className = "i";
1053                 return !div.getAttribute("className");
1054         });
1055
1056         /* getElement(s)By*
1057         ---------------------------------------------------------------------- */
1058
1059         // Check if getElementsByTagName("*") returns only elements
1060         support.getElementsByTagName = assert(function( div ) {
1061                 div.appendChild( doc.createComment("") );
1062                 return !div.getElementsByTagName("*").length;
1063         });
1064
1065         // Check if getElementsByClassName can be trusted
1066         support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
1067                 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1068
1069                 // Support: Safari<4
1070                 // Catch class over-caching
1071                 div.firstChild.className = "i";
1072                 // Support: Opera<10
1073                 // Catch gEBCN failure to find non-leading classes
1074                 return div.getElementsByClassName("i").length === 2;
1075         });
1076
1077         // Support: IE<10
1078         // Check if getElementById returns elements by name
1079         // The broken getElementById methods don't pick up programatically-set names,
1080         // so use a roundabout getElementsByName test
1081         support.getById = assert(function( div ) {
1082                 docElem.appendChild( div ).id = expando;
1083                 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1084         });
1085
1086         // ID find and filter
1087         if ( support.getById ) {
1088                 Expr.find["ID"] = function( id, context ) {
1089                         if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1090                                 var m = context.getElementById( id );
1091                                 // Check parentNode to catch when Blackberry 4.6 returns
1092                                 // nodes that are no longer in the document #6963
1093                                 return m && m.parentNode ? [ m ] : [];
1094                         }
1095                 };
1096                 Expr.filter["ID"] = function( id ) {
1097                         var attrId = id.replace( runescape, funescape );
1098                         return function( elem ) {
1099                                 return elem.getAttribute("id") === attrId;
1100                         };
1101                 };
1102         } else {
1103                 // Support: IE6/7
1104                 // getElementById is not reliable as a find shortcut
1105                 delete Expr.find["ID"];
1106
1107                 Expr.filter["ID"] =  function( id ) {
1108                         var attrId = id.replace( runescape, funescape );
1109                         return function( elem ) {
1110                                 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1111                                 return node && node.value === attrId;
1112                         };
1113                 };
1114         }
1115
1116         // Tag
1117         Expr.find["TAG"] = support.getElementsByTagName ?
1118                 function( tag, context ) {
1119                         if ( typeof context.getElementsByTagName !== strundefined ) {
1120                                 return context.getElementsByTagName( tag );
1121                         }
1122                 } :
1123                 function( tag, context ) {
1124                         var elem,
1125                                 tmp = [],
1126                                 i = 0,
1127                                 results = context.getElementsByTagName( tag );
1128
1129                         // Filter out possible comments
1130                         if ( tag === "*" ) {
1131                                 while ( (elem = results[i++]) ) {
1132                                         if ( elem.nodeType === 1 ) {
1133                                                 tmp.push( elem );
1134                                         }
1135                                 }
1136
1137                                 return tmp;
1138                         }
1139                         return results;
1140                 };
1141
1142         // Class
1143         Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1144                 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1145                         return context.getElementsByClassName( className );
1146                 }
1147         };
1148
1149         /* QSA/matchesSelector
1150         ---------------------------------------------------------------------- */
1151
1152         // QSA and matchesSelector support
1153
1154         // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1155         rbuggyMatches = [];
1156
1157         // qSa(:focus) reports false when true (Chrome 21)
1158         // We allow this because of a bug in IE8/9 that throws an error
1159         // whenever `document.activeElement` is accessed on an iframe
1160         // So, we allow :focus to pass through QSA all the time to avoid the IE error
1161         // See http://bugs.jquery.com/ticket/13378
1162         rbuggyQSA = [];
1163
1164         if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1165                 // Build QSA regex
1166                 // Regex strategy adopted from Diego Perini
1167                 assert(function( div ) {
1168                         // Select is set to empty string on purpose
1169                         // This is to test IE's treatment of not explicitly
1170                         // setting a boolean content attribute,
1171                         // since its presence should be enough
1172                         // http://bugs.jquery.com/ticket/12359
1173                         div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
1174
1175                         // Support: IE8, Opera 11-12.16
1176                         // Nothing should be selected when empty strings follow ^= or $= or *=
1177                         // The test attribute must be unknown in Opera but "safe" for WinRT
1178                         // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1179                         if ( div.querySelectorAll("[msallowclip^='']").length ) {
1180                                 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1181                         }
1182
1183                         // Support: IE8
1184                         // Boolean attributes and "value" are not treated correctly
1185                         if ( !div.querySelectorAll("[selected]").length ) {
1186                                 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1187                         }
1188
1189                         // Webkit/Opera - :checked should return selected option elements
1190                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1191                         // IE8 throws error here and will not see later tests
1192                         if ( !div.querySelectorAll(":checked").length ) {
1193                                 rbuggyQSA.push(":checked");
1194                         }
1195                 });
1196
1197                 assert(function( div ) {
1198                         // Support: Windows 8 Native Apps
1199                         // The type and name attributes are restricted during .innerHTML assignment
1200                         var input = doc.createElement("input");
1201                         input.setAttribute( "type", "hidden" );
1202                         div.appendChild( input ).setAttribute( "name", "D" );
1203
1204                         // Support: IE8
1205                         // Enforce case-sensitivity of name attribute
1206                         if ( div.querySelectorAll("[name=d]").length ) {
1207                                 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1208                         }
1209
1210                         // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1211                         // IE8 throws error here and will not see later tests
1212                         if ( !div.querySelectorAll(":enabled").length ) {
1213                                 rbuggyQSA.push( ":enabled", ":disabled" );
1214                         }
1215
1216                         // Opera 10-11 does not throw on post-comma invalid pseudos
1217                         div.querySelectorAll("*,:x");
1218                         rbuggyQSA.push(",.*:");
1219                 });
1220         }
1221
1222         if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1223                 docElem.webkitMatchesSelector ||
1224                 docElem.mozMatchesSelector ||
1225                 docElem.oMatchesSelector ||
1226                 docElem.msMatchesSelector) )) ) {
1227
1228                 assert(function( div ) {
1229                         // Check to see if it's possible to do matchesSelector
1230                         // on a disconnected node (IE 9)
1231                         support.disconnectedMatch = matches.call( div, "div" );
1232
1233                         // This should fail with an exception
1234                         // Gecko does not error, returns false instead
1235                         matches.call( div, "[s!='']:x" );
1236                         rbuggyMatches.push( "!=", pseudos );
1237                 });
1238         }
1239
1240         rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1241         rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1242
1243         /* Contains
1244         ---------------------------------------------------------------------- */
1245         hasCompare = rnative.test( docElem.compareDocumentPosition );
1246
1247         // Element contains another
1248         // Purposefully does not implement inclusive descendent
1249         // As in, an element does not contain itself
1250         contains = hasCompare || rnative.test( docElem.contains ) ?
1251                 function( a, b ) {
1252                         var adown = a.nodeType === 9 ? a.documentElement : a,
1253                                 bup = b && b.parentNode;
1254                         return a === bup || !!( bup && bup.nodeType === 1 && (
1255                                 adown.contains ?
1256                                         adown.contains( bup ) :
1257                                         a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1258                         ));
1259                 } :
1260                 function( a, b ) {
1261                         if ( b ) {
1262                                 while ( (b = b.parentNode) ) {
1263                                         if ( b === a ) {
1264                                                 return true;
1265                                         }
1266                                 }
1267                         }
1268                         return false;
1269                 };
1270
1271         /* Sorting
1272         ---------------------------------------------------------------------- */
1273
1274         // Document order sorting
1275         sortOrder = hasCompare ?
1276         function( a, b ) {
1277
1278                 // Flag for duplicate removal
1279                 if ( a === b ) {
1280                         hasDuplicate = true;
1281                         return 0;
1282                 }
1283
1284                 // Sort on method existence if only one input has compareDocumentPosition
1285                 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1286                 if ( compare ) {
1287                         return compare;
1288                 }
1289
1290                 // Calculate position if both inputs belong to the same document
1291                 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1292                         a.compareDocumentPosition( b ) :
1293
1294                         // Otherwise we know they are disconnected
1295                         1;
1296
1297                 // Disconnected nodes
1298                 if ( compare & 1 ||
1299                         (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1300
1301                         // Choose the first element that is related to our preferred document
1302                         if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1303                                 return -1;
1304                         }
1305                         if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1306                                 return 1;
1307                         }
1308
1309                         // Maintain original order
1310                         return sortInput ?
1311                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1312                                 0;
1313                 }
1314
1315                 return compare & 4 ? -1 : 1;
1316         } :
1317         function( a, b ) {
1318                 // Exit early if the nodes are identical
1319                 if ( a === b ) {
1320                         hasDuplicate = true;
1321                         return 0;
1322                 }
1323
1324                 var cur,
1325                         i = 0,
1326                         aup = a.parentNode,
1327                         bup = b.parentNode,
1328                         ap = [ a ],
1329                         bp = [ b ];
1330
1331                 // Parentless nodes are either documents or disconnected
1332                 if ( !aup || !bup ) {
1333                         return a === doc ? -1 :
1334                                 b === doc ? 1 :
1335                                 aup ? -1 :
1336                                 bup ? 1 :
1337                                 sortInput ?
1338                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1339                                 0;
1340
1341                 // If the nodes are siblings, we can do a quick check
1342                 } else if ( aup === bup ) {
1343                         return siblingCheck( a, b );
1344                 }
1345
1346                 // Otherwise we need full lists of their ancestors for comparison
1347                 cur = a;
1348                 while ( (cur = cur.parentNode) ) {
1349                         ap.unshift( cur );
1350                 }
1351                 cur = b;
1352                 while ( (cur = cur.parentNode) ) {
1353                         bp.unshift( cur );
1354                 }
1355
1356                 // Walk down the tree looking for a discrepancy
1357                 while ( ap[i] === bp[i] ) {
1358                         i++;
1359                 }
1360
1361                 return i ?
1362                         // Do a sibling check if the nodes have a common ancestor
1363                         siblingCheck( ap[i], bp[i] ) :
1364
1365                         // Otherwise nodes in our document sort first
1366                         ap[i] === preferredDoc ? -1 :
1367                         bp[i] === preferredDoc ? 1 :
1368                         0;
1369         };
1370
1371         return doc;
1372 };
1373
1374 Sizzle.matches = function( expr, elements ) {
1375         return Sizzle( expr, null, null, elements );
1376 };
1377
1378 Sizzle.matchesSelector = function( elem, expr ) {
1379         // Set document vars if needed
1380         if ( ( elem.ownerDocument || elem ) !== document ) {
1381                 setDocument( elem );
1382         }
1383
1384         // Make sure that attribute selectors are quoted
1385         expr = expr.replace( rattributeQuotes, "='$1']" );
1386
1387         if ( support.matchesSelector && documentIsHTML &&
1388                 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1389                 ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1390
1391                 try {
1392                         var ret = matches.call( elem, expr );
1393
1394                         // IE 9's matchesSelector returns false on disconnected nodes
1395                         if ( ret || support.disconnectedMatch ||
1396                                         // As well, disconnected nodes are said to be in a document
1397                                         // fragment in IE 9
1398                                         elem.document && elem.document.nodeType !== 11 ) {
1399                                 return ret;
1400                         }
1401                 } catch(e) {}
1402         }
1403
1404         return Sizzle( expr, document, null, [ elem ] ).length > 0;
1405 };
1406
1407 Sizzle.contains = function( context, elem ) {
1408         // Set document vars if needed
1409         if ( ( context.ownerDocument || context ) !== document ) {
1410                 setDocument( context );
1411         }
1412         return contains( context, elem );
1413 };
1414
1415 Sizzle.attr = function( elem, name ) {
1416         // Set document vars if needed
1417         if ( ( elem.ownerDocument || elem ) !== document ) {
1418                 setDocument( elem );
1419         }
1420
1421         var fn = Expr.attrHandle[ name.toLowerCase() ],
1422                 // Don't get fooled by Object.prototype properties (jQuery #13807)
1423                 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1424                         fn( elem, name, !documentIsHTML ) :
1425                         undefined;
1426
1427         return val !== undefined ?
1428                 val :
1429                 support.attributes || !documentIsHTML ?
1430                         elem.getAttribute( name ) :
1431                         (val = elem.getAttributeNode(name)) && val.specified ?
1432                                 val.value :
1433                                 null;
1434 };
1435
1436 Sizzle.error = function( msg ) {
1437         throw new Error( "Syntax error, unrecognized expression: " + msg );
1438 };
1439
1440 /**
1441  * Document sorting and removing duplicates
1442  * @param {ArrayLike} results
1443  */
1444 Sizzle.uniqueSort = function( results ) {
1445         var elem,
1446                 duplicates = [],
1447                 j = 0,
1448                 i = 0;
1449
1450         // Unless we *know* we can detect duplicates, assume their presence
1451         hasDuplicate = !support.detectDuplicates;
1452         sortInput = !support.sortStable && results.slice( 0 );
1453         results.sort( sortOrder );
1454
1455         if ( hasDuplicate ) {
1456                 while ( (elem = results[i++]) ) {
1457                         if ( elem === results[ i ] ) {
1458                                 j = duplicates.push( i );
1459                         }
1460                 }
1461                 while ( j-- ) {
1462                         results.splice( duplicates[ j ], 1 );
1463                 }
1464         }
1465
1466         // Clear input after sorting to release objects
1467         // See https://github.com/jquery/sizzle/pull/225
1468         sortInput = null;
1469
1470         return results;
1471 };
1472
1473 /**
1474  * Utility function for retrieving the text value of an array of DOM nodes
1475  * @param {Array|Element} elem
1476  */
1477 getText = Sizzle.getText = function( elem ) {
1478         var node,
1479                 ret = "",
1480                 i = 0,
1481                 nodeType = elem.nodeType;
1482
1483         if ( !nodeType ) {
1484                 // If no nodeType, this is expected to be an array
1485                 while ( (node = elem[i++]) ) {
1486                         // Do not traverse comment nodes
1487                         ret += getText( node );
1488                 }
1489         } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1490                 // Use textContent for elements
1491                 // innerText usage removed for consistency of new lines (jQuery #11153)
1492                 if ( typeof elem.textContent === "string" ) {
1493                         return elem.textContent;
1494                 } else {
1495                         // Traverse its children
1496                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1497                                 ret += getText( elem );
1498                         }
1499                 }
1500         } else if ( nodeType === 3 || nodeType === 4 ) {
1501                 return elem.nodeValue;
1502         }
1503         // Do not include comment or processing instruction nodes
1504
1505         return ret;
1506 };
1507
1508 Expr = Sizzle.selectors = {
1509
1510         // Can be adjusted by the user
1511         cacheLength: 50,
1512
1513         createPseudo: markFunction,
1514
1515         match: matchExpr,
1516
1517         attrHandle: {},
1518
1519         find: {},
1520
1521         relative: {
1522                 ">": { dir: "parentNode", first: true },
1523                 " ": { dir: "parentNode" },
1524                 "+": { dir: "previousSibling", first: true },
1525                 "~": { dir: "previousSibling" }
1526         },
1527
1528         preFilter: {
1529                 "ATTR": function( match ) {
1530                         match[1] = match[1].replace( runescape, funescape );
1531
1532                         // Move the given value to match[3] whether quoted or unquoted
1533                         match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1534
1535                         if ( match[2] === "~=" ) {
1536                                 match[3] = " " + match[3] + " ";
1537                         }
1538
1539                         return match.slice( 0, 4 );
1540                 },
1541
1542                 "CHILD": function( match ) {
1543                         /* matches from matchExpr["CHILD"]
1544                                 1 type (only|nth|...)
1545                                 2 what (child|of-type)
1546                                 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1547                                 4 xn-component of xn+y argument ([+-]?\d*n|)
1548                                 5 sign of xn-component
1549                                 6 x of xn-component
1550                                 7 sign of y-component
1551                                 8 y of y-component
1552                         */
1553                         match[1] = match[1].toLowerCase();
1554
1555                         if ( match[1].slice( 0, 3 ) === "nth" ) {
1556                                 // nth-* requires argument
1557                                 if ( !match[3] ) {
1558                                         Sizzle.error( match[0] );
1559                                 }
1560
1561                                 // numeric x and y parameters for Expr.filter.CHILD
1562                                 // remember that false/true cast respectively to 0/1
1563                                 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1564                                 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1565
1566                         // other types prohibit arguments
1567                         } else if ( match[3] ) {
1568                                 Sizzle.error( match[0] );
1569                         }
1570
1571                         return match;
1572                 },
1573
1574                 "PSEUDO": function( match ) {
1575                         var excess,
1576                                 unquoted = !match[6] && match[2];
1577
1578                         if ( matchExpr["CHILD"].test( match[0] ) ) {
1579                                 return null;
1580                         }
1581
1582                         // Accept quoted arguments as-is
1583                         if ( match[3] ) {
1584                                 match[2] = match[4] || match[5] || "";
1585
1586                         // Strip excess characters from unquoted arguments
1587                         } else if ( unquoted && rpseudo.test( unquoted ) &&
1588                                 // Get excess from tokenize (recursively)
1589                                 (excess = tokenize( unquoted, true )) &&
1590                                 // advance to the next closing parenthesis
1591                                 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1592
1593                                 // excess is a negative index
1594                                 match[0] = match[0].slice( 0, excess );
1595                                 match[2] = unquoted.slice( 0, excess );
1596                         }
1597
1598                         // Return only captures needed by the pseudo filter method (type and argument)
1599                         return match.slice( 0, 3 );
1600                 }
1601         },
1602
1603         filter: {
1604
1605                 "TAG": function( nodeNameSelector ) {
1606                         var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1607                         return nodeNameSelector === "*" ?
1608                                 function() { return true; } :
1609                                 function( elem ) {
1610                                         return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1611                                 };
1612                 },
1613
1614                 "CLASS": function( className ) {
1615                         var pattern = classCache[ className + " " ];
1616
1617                         return pattern ||
1618                                 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1619                                 classCache( className, function( elem ) {
1620                                         return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
1621                                 });
1622                 },
1623
1624                 "ATTR": function( name, operator, check ) {
1625                         return function( elem ) {
1626                                 var result = Sizzle.attr( elem, name );
1627
1628                                 if ( result == null ) {
1629                                         return operator === "!=";
1630                                 }
1631                                 if ( !operator ) {
1632                                         return true;
1633                                 }
1634
1635                                 result += "";
1636
1637                                 return operator === "=" ? result === check :
1638                                         operator === "!=" ? result !== check :
1639                                         operator === "^=" ? check && result.indexOf( check ) === 0 :
1640                                         operator === "*=" ? check && result.indexOf( check ) > -1 :
1641                                         operator === "$=" ? check && result.slice( -check.length ) === check :
1642                                         operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1643                                         operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1644                                         false;
1645                         };
1646                 },
1647
1648                 "CHILD": function( type, what, argument, first, last ) {
1649                         var simple = type.slice( 0, 3 ) !== "nth",
1650                                 forward = type.slice( -4 ) !== "last",
1651                                 ofType = what === "of-type";
1652
1653                         return first === 1 && last === 0 ?
1654
1655                                 // Shortcut for :nth-*(n)
1656                                 function( elem ) {
1657                                         return !!elem.parentNode;
1658                                 } :
1659
1660                                 function( elem, context, xml ) {
1661                                         var cache, outerCache, node, diff, nodeIndex, start,
1662                                                 dir = simple !== forward ? "nextSibling" : "previousSibling",
1663                                                 parent = elem.parentNode,
1664                                                 name = ofType && elem.nodeName.toLowerCase(),
1665                                                 useCache = !xml && !ofType;
1666
1667                                         if ( parent ) {
1668
1669                                                 // :(first|last|only)-(child|of-type)
1670                                                 if ( simple ) {
1671                                                         while ( dir ) {
1672                                                                 node = elem;
1673                                                                 while ( (node = node[ dir ]) ) {
1674                                                                         if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1675                                                                                 return false;
1676                                                                         }
1677                                                                 }
1678                                                                 // Reverse direction for :only-* (if we haven't yet done so)
1679                                                                 start = dir = type === "only" && !start && "nextSibling";
1680                                                         }
1681                                                         return true;
1682                                                 }
1683
1684                                                 start = [ forward ? parent.firstChild : parent.lastChild ];
1685
1686                                                 // non-xml :nth-child(...) stores cache data on `parent`
1687                                                 if ( forward && useCache ) {
1688                                                         // Seek `elem` from a previously-cached index
1689                                                         outerCache = parent[ expando ] || (parent[ expando ] = {});
1690                                                         cache = outerCache[ type ] || [];
1691                                                         nodeIndex = cache[0] === dirruns && cache[1];
1692                                                         diff = cache[0] === dirruns && cache[2];
1693                                                         node = nodeIndex && parent.childNodes[ nodeIndex ];
1694
1695                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1696
1697                                                                 // Fallback to seeking `elem` from the start
1698                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1699
1700                                                                 // When found, cache indexes on `parent` and break
1701                                                                 if ( node.nodeType === 1 && ++diff && node === elem ) {
1702                                                                         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1703                                                                         break;
1704                                                                 }
1705                                                         }
1706
1707                                                 // Use previously-cached element index if available
1708                                                 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1709                                                         diff = cache[1];
1710
1711                                                 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1712                                                 } else {
1713                                                         // Use the same loop as above to seek `elem` from the start
1714                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1715                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1716
1717                                                                 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1718                                                                         // Cache the index of each encountered element
1719                                                                         if ( useCache ) {
1720                                                                                 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
1721                                                                         }
1722
1723                                                                         if ( node === elem ) {
1724                                                                                 break;
1725                                                                         }
1726                                                                 }
1727                                                         }
1728                                                 }
1729
1730                                                 // Incorporate the offset, then check against cycle size
1731                                                 diff -= last;
1732                                                 return diff === first || ( diff % first === 0 && diff / first >= 0 );
1733                                         }
1734                                 };
1735                 },
1736
1737                 "PSEUDO": function( pseudo, argument ) {
1738                         // pseudo-class names are case-insensitive
1739                         // http://www.w3.org/TR/selectors/#pseudo-classes
1740                         // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1741                         // Remember that setFilters inherits from pseudos
1742                         var args,
1743                                 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1744                                         Sizzle.error( "unsupported pseudo: " + pseudo );
1745
1746                         // The user may use createPseudo to indicate that
1747                         // arguments are needed to create the filter function
1748                         // just as Sizzle does
1749                         if ( fn[ expando ] ) {
1750                                 return fn( argument );
1751                         }
1752
1753                         // But maintain support for old signatures
1754                         if ( fn.length > 1 ) {
1755                                 args = [ pseudo, pseudo, "", argument ];
1756                                 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1757                                         markFunction(function( seed, matches ) {
1758                                                 var idx,
1759                                                         matched = fn( seed, argument ),
1760                                                         i = matched.length;
1761                                                 while ( i-- ) {
1762                                                         idx = indexOf.call( seed, matched[i] );
1763                                                         seed[ idx ] = !( matches[ idx ] = matched[i] );
1764                                                 }
1765                                         }) :
1766                                         function( elem ) {
1767                                                 return fn( elem, 0, args );
1768                                         };
1769                         }
1770
1771                         return fn;
1772                 }
1773         },
1774
1775         pseudos: {
1776                 // Potentially complex pseudos
1777                 "not": markFunction(function( selector ) {
1778                         // Trim the selector passed to compile
1779                         // to avoid treating leading and trailing
1780                         // spaces as combinators
1781                         var input = [],
1782                                 results = [],
1783                                 matcher = compile( selector.replace( rtrim, "$1" ) );
1784
1785                         return matcher[ expando ] ?
1786                                 markFunction(function( seed, matches, context, xml ) {
1787                                         var elem,
1788                                                 unmatched = matcher( seed, null, xml, [] ),
1789                                                 i = seed.length;
1790
1791                                         // Match elements unmatched by `matcher`
1792                                         while ( i-- ) {
1793                                                 if ( (elem = unmatched[i]) ) {
1794                                                         seed[i] = !(matches[i] = elem);
1795                                                 }
1796                                         }
1797                                 }) :
1798                                 function( elem, context, xml ) {
1799                                         input[0] = elem;
1800                                         matcher( input, null, xml, results );
1801                                         return !results.pop();
1802                                 };
1803                 }),
1804
1805                 "has": markFunction(function( selector ) {
1806                         return function( elem ) {
1807                                 return Sizzle( selector, elem ).length > 0;
1808                         };
1809                 }),
1810
1811                 "contains": markFunction(function( text ) {
1812                         return function( elem ) {
1813                                 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
1814                         };
1815                 }),
1816
1817                 // "Whether an element is represented by a :lang() selector
1818                 // is based solely on the element's language value
1819                 // being equal to the identifier C,
1820                 // or beginning with the identifier C immediately followed by "-".
1821                 // The matching of C against the element's language value is performed case-insensitively.
1822                 // The identifier C does not have to be a valid language name."
1823                 // http://www.w3.org/TR/selectors/#lang-pseudo
1824                 "lang": markFunction( function( lang ) {
1825                         // lang value must be a valid identifier
1826                         if ( !ridentifier.test(lang || "") ) {
1827                                 Sizzle.error( "unsupported lang: " + lang );
1828                         }
1829                         lang = lang.replace( runescape, funescape ).toLowerCase();
1830                         return function( elem ) {
1831                                 var elemLang;
1832                                 do {
1833                                         if ( (elemLang = documentIsHTML ?
1834                                                 elem.lang :
1835                                                 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
1836
1837                                                 elemLang = elemLang.toLowerCase();
1838                                                 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
1839                                         }
1840                                 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
1841                                 return false;
1842                         };
1843                 }),
1844
1845                 // Miscellaneous
1846                 "target": function( elem ) {
1847                         var hash = window.location && window.location.hash;
1848                         return hash && hash.slice( 1 ) === elem.id;
1849                 },
1850
1851                 "root": function( elem ) {
1852                         return elem === docElem;
1853                 },
1854
1855                 "focus": function( elem ) {
1856                         return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
1857                 },
1858
1859                 // Boolean properties
1860                 "enabled": function( elem ) {
1861                         return elem.disabled === false;
1862                 },
1863
1864                 "disabled": function( elem ) {
1865                         return elem.disabled === true;
1866                 },
1867
1868                 "checked": function( elem ) {
1869                         // In CSS3, :checked should return both checked and selected elements
1870                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1871                         var nodeName = elem.nodeName.toLowerCase();
1872                         return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
1873                 },
1874
1875                 "selected": function( elem ) {
1876                         // Accessing this property makes selected-by-default
1877                         // options in Safari work properly
1878                         if ( elem.parentNode ) {
1879                                 elem.parentNode.selectedIndex;
1880                         }
1881
1882                         return elem.selected === true;
1883                 },
1884
1885                 // Contents
1886                 "empty": function( elem ) {
1887                         // http://www.w3.org/TR/selectors/#empty-pseudo
1888                         // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
1889                         //   but not by others (comment: 8; processing instruction: 7; etc.)
1890                         // nodeType < 6 works because attributes (2) do not appear as children
1891                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1892                                 if ( elem.nodeType < 6 ) {
1893                                         return false;
1894                                 }
1895                         }
1896                         return true;
1897                 },
1898
1899                 "parent": function( elem ) {
1900                         return !Expr.pseudos["empty"]( elem );
1901                 },
1902
1903                 // Element/input types
1904                 "header": function( elem ) {
1905                         return rheader.test( elem.nodeName );
1906                 },
1907
1908                 "input": function( elem ) {
1909                         return rinputs.test( elem.nodeName );
1910                 },
1911
1912                 "button": function( elem ) {
1913                         var name = elem.nodeName.toLowerCase();
1914                         return name === "input" && elem.type === "button" || name === "button";
1915                 },
1916
1917                 "text": function( elem ) {
1918                         var attr;
1919                         return elem.nodeName.toLowerCase() === "input" &&
1920                                 elem.type === "text" &&
1921
1922                                 // Support: IE<8
1923                                 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
1924                                 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
1925                 },
1926
1927                 // Position-in-collection
1928                 "first": createPositionalPseudo(function() {
1929                         return [ 0 ];
1930                 }),
1931
1932                 "last": createPositionalPseudo(function( matchIndexes, length ) {
1933                         return [ length - 1 ];
1934                 }),
1935
1936                 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
1937                         return [ argument < 0 ? argument + length : argument ];
1938                 }),
1939
1940                 "even": createPositionalPseudo(function( matchIndexes, length ) {
1941                         var i = 0;
1942                         for ( ; i < length; i += 2 ) {
1943                                 matchIndexes.push( i );
1944                         }
1945                         return matchIndexes;
1946                 }),
1947
1948                 "odd": createPositionalPseudo(function( matchIndexes, length ) {
1949                         var i = 1;
1950                         for ( ; i < length; i += 2 ) {
1951                                 matchIndexes.push( i );
1952                         }
1953                         return matchIndexes;
1954                 }),
1955
1956                 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1957                         var i = argument < 0 ? argument + length : argument;
1958                         for ( ; --i >= 0; ) {
1959                                 matchIndexes.push( i );
1960                         }
1961                         return matchIndexes;
1962                 }),
1963
1964                 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1965                         var i = argument < 0 ? argument + length : argument;
1966                         for ( ; ++i < length; ) {
1967                                 matchIndexes.push( i );
1968                         }
1969                         return matchIndexes;
1970                 })
1971         }
1972 };
1973
1974 Expr.pseudos["nth"] = Expr.pseudos["eq"];
1975
1976 // Add button/input type pseudos
1977 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
1978         Expr.pseudos[ i ] = createInputPseudo( i );
1979 }
1980 for ( i in { submit: true, reset: true } ) {
1981         Expr.pseudos[ i ] = createButtonPseudo( i );
1982 }
1983
1984 // Easy API for creating new setFilters
1985 function setFilters() {}
1986 setFilters.prototype = Expr.filters = Expr.pseudos;
1987 Expr.setFilters = new setFilters();
1988
1989 tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
1990         var matched, match, tokens, type,
1991                 soFar, groups, preFilters,
1992                 cached = tokenCache[ selector + " " ];
1993
1994         if ( cached ) {
1995                 return parseOnly ? 0 : cached.slice( 0 );
1996         }
1997
1998         soFar = selector;
1999         groups = [];
2000         preFilters = Expr.preFilter;
2001
2002         while ( soFar ) {
2003
2004                 // Comma and first run
2005                 if ( !matched || (match = rcomma.exec( soFar )) ) {
2006                         if ( match ) {
2007                                 // Don't consume trailing commas as valid
2008                                 soFar = soFar.slice( match[0].length ) || soFar;
2009                         }
2010                         groups.push( (tokens = []) );
2011                 }
2012
2013                 matched = false;
2014
2015                 // Combinators
2016                 if ( (match = rcombinators.exec( soFar )) ) {
2017                         matched = match.shift();
2018                         tokens.push({
2019                                 value: matched,
2020                                 // Cast descendant combinators to space
2021                                 type: match[0].replace( rtrim, " " )
2022                         });
2023                         soFar = soFar.slice( matched.length );
2024                 }
2025
2026                 // Filters
2027                 for ( type in Expr.filter ) {
2028                         if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2029                                 (match = preFilters[ type ]( match ))) ) {
2030                                 matched = match.shift();
2031                                 tokens.push({
2032                                         value: matched,
2033                                         type: type,
2034                                         matches: match
2035                                 });
2036                                 soFar = soFar.slice( matched.length );
2037                         }
2038                 }
2039
2040                 if ( !matched ) {
2041                         break;
2042                 }
2043         }
2044
2045         // Return the length of the invalid excess
2046         // if we're just parsing
2047         // Otherwise, throw an error or return tokens
2048         return parseOnly ?
2049                 soFar.length :
2050                 soFar ?
2051                         Sizzle.error( selector ) :
2052                         // Cache the tokens
2053                         tokenCache( selector, groups ).slice( 0 );
2054 };
2055
2056 function toSelector( tokens ) {
2057         var i = 0,
2058                 len = tokens.length,
2059                 selector = "";
2060         for ( ; i < len; i++ ) {
2061                 selector += tokens[i].value;
2062         }
2063         return selector;
2064 }
2065
2066 function addCombinator( matcher, combinator, base ) {
2067         var dir = combinator.dir,
2068                 checkNonElements = base && dir === "parentNode",
2069                 doneName = done++;
2070
2071         return combinator.first ?
2072                 // Check against closest ancestor/preceding element
2073                 function( elem, context, xml ) {
2074                         while ( (elem = elem[ dir ]) ) {
2075                                 if ( elem.nodeType === 1 || checkNonElements ) {
2076                                         return matcher( elem, context, xml );
2077                                 }
2078                         }
2079                 } :
2080
2081                 // Check against all ancestor/preceding elements
2082                 function( elem, context, xml ) {
2083                         var oldCache, outerCache,
2084                                 newCache = [ dirruns, doneName ];
2085
2086                         // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2087                         if ( xml ) {
2088                                 while ( (elem = elem[ dir ]) ) {
2089                                         if ( elem.nodeType === 1 || checkNonElements ) {
2090                                                 if ( matcher( elem, context, xml ) ) {
2091                                                         return true;
2092                                                 }
2093                                         }
2094                                 }
2095                         } else {
2096                                 while ( (elem = elem[ dir ]) ) {
2097                                         if ( elem.nodeType === 1 || checkNonElements ) {
2098                                                 outerCache = elem[ expando ] || (elem[ expando ] = {});
2099                                                 if ( (oldCache = outerCache[ dir ]) &&
2100                                                         oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2101
2102                                                         // Assign to newCache so results back-propagate to previous elements
2103                                                         return (newCache[ 2 ] = oldCache[ 2 ]);
2104                                                 } else {
2105                                                         // Reuse newcache so results back-propagate to previous elements
2106                                                         outerCache[ dir ] = newCache;
2107
2108                                                         // A match means we're done; a fail means we have to keep checking
2109                                                         if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2110                                                                 return true;
2111                                                         }
2112                                                 }
2113                                         }
2114                                 }
2115                         }
2116                 };
2117 }
2118
2119 function elementMatcher( matchers ) {
2120         return matchers.length > 1 ?
2121                 function( elem, context, xml ) {
2122                         var i = matchers.length;
2123                         while ( i-- ) {
2124                                 if ( !matchers[i]( elem, context, xml ) ) {
2125                                         return false;
2126                                 }
2127                         }
2128                         return true;
2129                 } :
2130                 matchers[0];
2131 }
2132
2133 function multipleContexts( selector, contexts, results ) {
2134         var i = 0,
2135                 len = contexts.length;
2136         for ( ; i < len; i++ ) {
2137                 Sizzle( selector, contexts[i], results );
2138         }
2139         return results;
2140 }
2141
2142 function condense( unmatched, map, filter, context, xml ) {
2143         var elem,
2144                 newUnmatched = [],
2145                 i = 0,
2146                 len = unmatched.length,
2147                 mapped = map != null;
2148
2149         for ( ; i < len; i++ ) {
2150                 if ( (elem = unmatched[i]) ) {
2151                         if ( !filter || filter( elem, context, xml ) ) {
2152                                 newUnmatched.push( elem );
2153                                 if ( mapped ) {
2154                                         map.push( i );
2155                                 }
2156                         }
2157                 }
2158         }
2159
2160         return newUnmatched;
2161 }
2162
2163 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2164         if ( postFilter && !postFilter[ expando ] ) {
2165                 postFilter = setMatcher( postFilter );
2166         }
2167         if ( postFinder && !postFinder[ expando ] ) {
2168                 postFinder = setMatcher( postFinder, postSelector );
2169         }
2170         return markFunction(function( seed, results, context, xml ) {
2171                 var temp, i, elem,
2172                         preMap = [],
2173                         postMap = [],
2174                         preexisting = results.length,
2175
2176                         // Get initial elements from seed or context
2177                         elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2178
2179                         // Prefilter to get matcher input, preserving a map for seed-results synchronization
2180                         matcherIn = preFilter && ( seed || !selector ) ?
2181                                 condense( elems, preMap, preFilter, context, xml ) :
2182                                 elems,
2183
2184                         matcherOut = matcher ?
2185                                 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2186                                 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2187
2188                                         // ...intermediate processing is necessary
2189                                         [] :
2190
2191                                         // ...otherwise use results directly
2192                                         results :
2193                                 matcherIn;
2194
2195                 // Find primary matches
2196                 if ( matcher ) {
2197                         matcher( matcherIn, matcherOut, context, xml );
2198                 }
2199
2200                 // Apply postFilter
2201                 if ( postFilter ) {
2202                         temp = condense( matcherOut, postMap );
2203                         postFilter( temp, [], context, xml );
2204
2205                         // Un-match failing elements by moving them back to matcherIn
2206                         i = temp.length;
2207                         while ( i-- ) {
2208                                 if ( (elem = temp[i]) ) {
2209                                         matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2210                                 }
2211                         }
2212                 }
2213
2214                 if ( seed ) {
2215                         if ( postFinder || preFilter ) {
2216                                 if ( postFinder ) {
2217                                         // Get the final matcherOut by condensing this intermediate into postFinder contexts
2218                                         temp = [];
2219                                         i = matcherOut.length;
2220                                         while ( i-- ) {
2221                                                 if ( (elem = matcherOut[i]) ) {
2222                                                         // Restore matcherIn since elem is not yet a final match
2223                                                         temp.push( (matcherIn[i] = elem) );
2224                                                 }
2225                                         }
2226                                         postFinder( null, (matcherOut = []), temp, xml );
2227                                 }
2228
2229                                 // Move matched elements from seed to results to keep them synchronized
2230                                 i = matcherOut.length;
2231                                 while ( i-- ) {
2232                                         if ( (elem = matcherOut[i]) &&
2233                                                 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2234
2235                                                 seed[temp] = !(results[temp] = elem);
2236                                         }
2237                                 }
2238                         }
2239
2240                 // Add elements to results, through postFinder if defined
2241                 } else {
2242                         matcherOut = condense(
2243                                 matcherOut === results ?
2244                                         matcherOut.splice( preexisting, matcherOut.length ) :
2245                                         matcherOut
2246                         );
2247                         if ( postFinder ) {
2248                                 postFinder( null, results, matcherOut, xml );
2249                         } else {
2250                                 push.apply( results, matcherOut );
2251                         }
2252                 }
2253         });
2254 }
2255
2256 function matcherFromTokens( tokens ) {
2257         var checkContext, matcher, j,
2258                 len = tokens.length,
2259                 leadingRelative = Expr.relative[ tokens[0].type ],
2260                 implicitRelative = leadingRelative || Expr.relative[" "],
2261                 i = leadingRelative ? 1 : 0,
2262
2263                 // The foundational matcher ensures that elements are reachable from top-level context(s)
2264                 matchContext = addCombinator( function( elem ) {
2265                         return elem === checkContext;
2266                 }, implicitRelative, true ),
2267                 matchAnyContext = addCombinator( function( elem ) {
2268                         return indexOf.call( checkContext, elem ) > -1;
2269                 }, implicitRelative, true ),
2270                 matchers = [ function( elem, context, xml ) {
2271                         return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2272                                 (checkContext = context).nodeType ?
2273                                         matchContext( elem, context, xml ) :
2274                                         matchAnyContext( elem, context, xml ) );
2275                 } ];
2276
2277         for ( ; i < len; i++ ) {
2278                 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2279                         matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2280                 } else {
2281                         matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2282
2283                         // Return special upon seeing a positional matcher
2284                         if ( matcher[ expando ] ) {
2285                                 // Find the next relative operator (if any) for proper handling
2286                                 j = ++i;
2287                                 for ( ; j < len; j++ ) {
2288                                         if ( Expr.relative[ tokens[j].type ] ) {
2289                                                 break;
2290                                         }
2291                                 }
2292                                 return setMatcher(
2293                                         i > 1 && elementMatcher( matchers ),
2294                                         i > 1 && toSelector(
2295                                                 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2296                                                 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2297                                         ).replace( rtrim, "$1" ),
2298                                         matcher,
2299                                         i < j && matcherFromTokens( tokens.slice( i, j ) ),
2300                                         j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2301                                         j < len && toSelector( tokens )
2302                                 );
2303                         }
2304                         matchers.push( matcher );
2305                 }
2306         }
2307
2308         return elementMatcher( matchers );
2309 }
2310
2311 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2312         var bySet = setMatchers.length > 0,
2313                 byElement = elementMatchers.length > 0,
2314                 superMatcher = function( seed, context, xml, results, outermost ) {
2315                         var elem, j, matcher,
2316                                 matchedCount = 0,
2317                                 i = "0",
2318                                 unmatched = seed && [],
2319                                 setMatched = [],
2320                                 contextBackup = outermostContext,
2321                                 // We must always have either seed elements or outermost context
2322                                 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2323                                 // Use integer dirruns iff this is the outermost matcher
2324                                 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2325                                 len = elems.length;
2326
2327                         if ( outermost ) {
2328                                 outermostContext = context !== document && context;
2329                         }
2330
2331                         // Add elements passing elementMatchers directly to results
2332                         // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2333                         // Support: IE<9, Safari
2334                         // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2335                         for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2336                                 if ( byElement && elem ) {
2337                                         j = 0;
2338                                         while ( (matcher = elementMatchers[j++]) ) {
2339                                                 if ( matcher( elem, context, xml ) ) {
2340                                                         results.push( elem );
2341                                                         break;
2342                                                 }
2343                                         }
2344                                         if ( outermost ) {
2345                                                 dirruns = dirrunsUnique;
2346                                         }
2347                                 }
2348
2349                                 // Track unmatched elements for set filters
2350                                 if ( bySet ) {
2351                                         // They will have gone through all possible matchers
2352                                         if ( (elem = !matcher && elem) ) {
2353                                                 matchedCount--;
2354                                         }
2355
2356                                         // Lengthen the array for every element, matched or not
2357                                         if ( seed ) {
2358                                                 unmatched.push( elem );
2359                                         }
2360                                 }
2361                         }
2362
2363                         // Apply set filters to unmatched elements
2364                         matchedCount += i;
2365                         if ( bySet && i !== matchedCount ) {
2366                                 j = 0;
2367                                 while ( (matcher = setMatchers[j++]) ) {
2368                                         matcher( unmatched, setMatched, context, xml );
2369                                 }
2370
2371                                 if ( seed ) {
2372                                         // Reintegrate element matches to eliminate the need for sorting
2373                                         if ( matchedCount > 0 ) {
2374                                                 while ( i-- ) {
2375                                                         if ( !(unmatched[i] || setMatched[i]) ) {
2376                                                                 setMatched[i] = pop.call( results );
2377                                                         }
2378                                                 }
2379                                         }
2380
2381                                         // Discard index placeholder values to get only actual matches
2382                                         setMatched = condense( setMatched );
2383                                 }
2384
2385                                 // Add matches to results
2386                                 push.apply( results, setMatched );
2387
2388                                 // Seedless set matches succeeding multiple successful matchers stipulate sorting
2389                                 if ( outermost && !seed && setMatched.length > 0 &&
2390                                         ( matchedCount + setMatchers.length ) > 1 ) {
2391
2392                                         Sizzle.uniqueSort( results );
2393                                 }
2394                         }
2395
2396                         // Override manipulation of globals by nested matchers
2397                         if ( outermost ) {
2398                                 dirruns = dirrunsUnique;
2399                                 outermostContext = contextBackup;
2400                         }
2401
2402                         return unmatched;
2403                 };
2404
2405         return bySet ?
2406                 markFunction( superMatcher ) :
2407                 superMatcher;
2408 }
2409
2410 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2411         var i,
2412                 setMatchers = [],
2413                 elementMatchers = [],
2414                 cached = compilerCache[ selector + " " ];
2415
2416         if ( !cached ) {
2417                 // Generate a function of recursive functions that can be used to check each element
2418                 if ( !match ) {
2419                         match = tokenize( selector );
2420                 }
2421                 i = match.length;
2422                 while ( i-- ) {
2423                         cached = matcherFromTokens( match[i] );
2424                         if ( cached[ expando ] ) {
2425                                 setMatchers.push( cached );
2426                         } else {
2427                                 elementMatchers.push( cached );
2428                         }
2429                 }
2430
2431                 // Cache the compiled function
2432                 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2433
2434                 // Save selector and tokenization
2435                 cached.selector = selector;
2436         }
2437         return cached;
2438 };
2439
2440 /**
2441  * A low-level selection function that works with Sizzle's compiled
2442  *  selector functions
2443  * @param {String|Function} selector A selector or a pre-compiled
2444  *  selector function built with Sizzle.compile
2445  * @param {Element} context
2446  * @param {Array} [results]
2447  * @param {Array} [seed] A set of elements to match against
2448  */
2449 select = Sizzle.select = function( selector, context, results, seed ) {
2450         var i, tokens, token, type, find,
2451                 compiled = typeof selector === "function" && selector,
2452                 match = !seed && tokenize( (selector = compiled.selector || selector) );
2453
2454         results = results || [];
2455
2456         // Try to minimize operations if there is no seed and only one group
2457         if ( match.length === 1 ) {
2458
2459                 // Take a shortcut and set the context if the root selector is an ID
2460                 tokens = match[0] = match[0].slice( 0 );
2461                 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2462                                 support.getById && context.nodeType === 9 && documentIsHTML &&
2463                                 Expr.relative[ tokens[1].type ] ) {
2464
2465                         context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2466                         if ( !context ) {
2467                                 return results;
2468
2469                         // Precompiled matchers will still verify ancestry, so step up a level
2470                         } else if ( compiled ) {
2471                                 context = context.parentNode;
2472                         }
2473
2474                         selector = selector.slice( tokens.shift().value.length );
2475                 }
2476
2477                 // Fetch a seed set for right-to-left matching
2478                 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2479                 while ( i-- ) {
2480                         token = tokens[i];
2481
2482                         // Abort if we hit a combinator
2483                         if ( Expr.relative[ (type = token.type) ] ) {
2484                                 break;
2485                         }
2486                         if ( (find = Expr.find[ type ]) ) {
2487                                 // Search, expanding context for leading sibling combinators
2488                                 if ( (seed = find(
2489                                         token.matches[0].replace( runescape, funescape ),
2490                                         rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2491                                 )) ) {
2492
2493                                         // If seed is empty or no tokens remain, we can return early
2494                                         tokens.splice( i, 1 );
2495                                         selector = seed.length && toSelector( tokens );
2496                                         if ( !selector ) {
2497                                                 push.apply( results, seed );
2498                                                 return results;
2499                                         }
2500
2501                                         break;
2502                                 }
2503                         }
2504                 }
2505         }
2506
2507         // Compile and execute a filtering function if one is not provided
2508         // Provide `match` to avoid retokenization if we modified the selector above
2509         ( compiled || compile( selector, match ) )(
2510                 seed,
2511                 context,
2512                 !documentIsHTML,
2513                 results,
2514                 rsibling.test( selector ) && testContext( context.parentNode ) || context
2515         );
2516         return results;
2517 };
2518
2519 // One-time assignments
2520
2521 // Sort stability
2522 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2523
2524 // Support: Chrome<14
2525 // Always assume duplicates if they aren't passed to the comparison function
2526 support.detectDuplicates = !!hasDuplicate;
2527
2528 // Initialize against the default document
2529 setDocument();
2530
2531 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2532 // Detached nodes confoundingly follow *each other*
2533 support.sortDetached = assert(function( div1 ) {
2534         // Should return 1, but returns 4 (following)
2535         return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2536 });
2537
2538 // Support: IE<8
2539 // Prevent attribute/property "interpolation"
2540 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2541 if ( !assert(function( div ) {
2542         div.innerHTML = "<a href='#'></a>";
2543         return div.firstChild.getAttribute("href") === "#" ;
2544 }) ) {
2545         addHandle( "type|href|height|width", function( elem, name, isXML ) {
2546                 if ( !isXML ) {
2547                         return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2548                 }
2549         });
2550 }
2551
2552 // Support: IE<9
2553 // Use defaultValue in place of getAttribute("value")
2554 if ( !support.attributes || !assert(function( div ) {
2555         div.innerHTML = "<input/>";
2556         div.firstChild.setAttribute( "value", "" );
2557         return div.firstChild.getAttribute( "value" ) === "";
2558 }) ) {
2559         addHandle( "value", function( elem, name, isXML ) {
2560                 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2561                         return elem.defaultValue;
2562                 }
2563         });
2564 }
2565
2566 // Support: IE<9
2567 // Use getAttributeNode to fetch booleans when getAttribute lies
2568 if ( !assert(function( div ) {
2569         return div.getAttribute("disabled") == null;
2570 }) ) {
2571         addHandle( booleans, function( elem, name, isXML ) {
2572                 var val;
2573                 if ( !isXML ) {
2574                         return elem[ name ] === true ? name.toLowerCase() :
2575                                         (val = elem.getAttributeNode( name )) && val.specified ?
2576                                         val.value :
2577                                 null;
2578                 }
2579         });
2580 }
2581
2582 return Sizzle;
2583
2584 })( window );
2585
2586
2587
2588 jQuery.find = Sizzle;
2589 jQuery.expr = Sizzle.selectors;
2590 jQuery.expr[":"] = jQuery.expr.pseudos;
2591 jQuery.unique = Sizzle.uniqueSort;
2592 jQuery.text = Sizzle.getText;
2593 jQuery.isXMLDoc = Sizzle.isXML;
2594 jQuery.contains = Sizzle.contains;
2595
2596
2597
2598 var rneedsContext = jQuery.expr.match.needsContext;
2599
2600 var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
2601
2602
2603
2604 var risSimple = /^.[^:#\[\.,]*$/;
2605
2606 // Implement the identical functionality for filter and not
2607 function winnow( elements, qualifier, not ) {
2608         if ( jQuery.isFunction( qualifier ) ) {
2609                 return jQuery.grep( elements, function( elem, i ) {
2610                         /* jshint -W018 */
2611                         return !!qualifier.call( elem, i, elem ) !== not;
2612                 });
2613
2614         }
2615
2616         if ( qualifier.nodeType ) {
2617                 return jQuery.grep( elements, function( elem ) {
2618                         return ( elem === qualifier ) !== not;
2619                 });
2620
2621         }
2622
2623         if ( typeof qualifier === "string" ) {
2624                 if ( risSimple.test( qualifier ) ) {
2625                         return jQuery.filter( qualifier, elements, not );
2626                 }
2627
2628                 qualifier = jQuery.filter( qualifier, elements );
2629         }
2630
2631         return jQuery.grep( elements, function( elem ) {
2632                 return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
2633         });
2634 }
2635
2636 jQuery.filter = function( expr, elems, not ) {
2637         var elem = elems[ 0 ];
2638
2639         if ( not ) {
2640                 expr = ":not(" + expr + ")";
2641         }
2642
2643         return elems.length === 1 && elem.nodeType === 1 ?
2644                 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
2645                 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
2646                         return elem.nodeType === 1;
2647                 }));
2648 };
2649
2650 jQuery.fn.extend({
2651         find: function( selector ) {
2652                 var i,
2653                         len = this.length,
2654                         ret = [],
2655                         self = this;
2656
2657                 if ( typeof selector !== "string" ) {
2658                         return this.pushStack( jQuery( selector ).filter(function() {
2659                                 for ( i = 0; i < len; i++ ) {
2660                                         if ( jQuery.contains( self[ i ], this ) ) {
2661                                                 return true;
2662                                         }
2663                                 }
2664                         }) );
2665                 }
2666
2667                 for ( i = 0; i < len; i++ ) {
2668                         jQuery.find( selector, self[ i ], ret );
2669                 }
2670
2671                 // Needed because $( selector, context ) becomes $( context ).find( selector )
2672                 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
2673                 ret.selector = this.selector ? this.selector + " " + selector : selector;
2674                 return ret;
2675         },
2676         filter: function( selector ) {
2677                 return this.pushStack( winnow(this, selector || [], false) );
2678         },
2679         not: function( selector ) {
2680                 return this.pushStack( winnow(this, selector || [], true) );
2681         },
2682         is: function( selector ) {
2683                 return !!winnow(
2684                         this,
2685
2686                         // If this is a positional/relative selector, check membership in the returned set
2687                         // so $("p:first").is("p:last") won't return true for a doc with two "p".
2688                         typeof selector === "string" && rneedsContext.test( selector ) ?
2689                                 jQuery( selector ) :
2690                                 selector || [],
2691                         false
2692                 ).length;
2693         }
2694 });
2695
2696
2697 // Initialize a jQuery object
2698
2699
2700 // A central reference to the root jQuery(document)
2701 var rootjQuery,
2702
2703         // A simple way to check for HTML strings
2704         // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
2705         // Strict HTML recognition (#11290: must start with <)
2706         rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
2707
2708         init = jQuery.fn.init = function( selector, context ) {
2709                 var match, elem;
2710
2711                 // HANDLE: $(""), $(null), $(undefined), $(false)
2712                 if ( !selector ) {
2713                         return this;
2714                 }
2715
2716                 // Handle HTML strings
2717                 if ( typeof selector === "string" ) {
2718                         if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
2719                                 // Assume that strings that start and end with <> are HTML and skip the regex check
2720                                 match = [ null, selector, null ];
2721
2722                         } else {
2723                                 match = rquickExpr.exec( selector );
2724                         }
2725
2726                         // Match html or make sure no context is specified for #id
2727                         if ( match && (match[1] || !context) ) {
2728
2729                                 // HANDLE: $(html) -> $(array)
2730                                 if ( match[1] ) {
2731                                         context = context instanceof jQuery ? context[0] : context;
2732
2733                                         // scripts is true for back-compat
2734                                         // Intentionally let the error be thrown if parseHTML is not present
2735                                         jQuery.merge( this, jQuery.parseHTML(
2736                                                 match[1],
2737                                                 context && context.nodeType ? context.ownerDocument || context : document,
2738                                                 true
2739                                         ) );
2740
2741                                         // HANDLE: $(html, props)
2742                                         if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
2743                                                 for ( match in context ) {
2744                                                         // Properties of context are called as methods if possible
2745                                                         if ( jQuery.isFunction( this[ match ] ) ) {
2746                                                                 this[ match ]( context[ match ] );
2747
2748                                                         // ...and otherwise set as attributes
2749                                                         } else {
2750                                                                 this.attr( match, context[ match ] );
2751                                                         }
2752                                                 }
2753                                         }
2754
2755                                         return this;
2756
2757                                 // HANDLE: $(#id)
2758                                 } else {
2759                                         elem = document.getElementById( match[2] );
2760
2761                                         // Check parentNode to catch when Blackberry 4.6 returns
2762                                         // nodes that are no longer in the document #6963
2763                                         if ( elem && elem.parentNode ) {
2764                                                 // Inject the element directly into the jQuery object
2765                                                 this.length = 1;
2766                                                 this[0] = elem;
2767                                         }
2768
2769                                         this.context = document;
2770                                         this.selector = selector;
2771                                         return this;
2772                                 }
2773
2774                         // HANDLE: $(expr, $(...))
2775                         } else if ( !context || context.jquery ) {
2776                                 return ( context || rootjQuery ).find( selector );
2777
2778                         // HANDLE: $(expr, context)
2779                         // (which is just equivalent to: $(context).find(expr)
2780                         } else {
2781                                 return this.constructor( context ).find( selector );
2782                         }
2783
2784                 // HANDLE: $(DOMElement)
2785                 } else if ( selector.nodeType ) {
2786                         this.context = this[0] = selector;
2787                         this.length = 1;
2788                         return this;
2789
2790                 // HANDLE: $(function)
2791                 // Shortcut for document ready
2792                 } else if ( jQuery.isFunction( selector ) ) {
2793                         return typeof rootjQuery.ready !== "undefined" ?
2794                                 rootjQuery.ready( selector ) :
2795                                 // Execute immediately if ready is not present
2796                                 selector( jQuery );
2797                 }
2798
2799                 if ( selector.selector !== undefined ) {
2800                         this.selector = selector.selector;
2801                         this.context = selector.context;
2802                 }
2803
2804                 return jQuery.makeArray( selector, this );
2805         };
2806
2807 // Give the init function the jQuery prototype for later instantiation
2808 init.prototype = jQuery.fn;
2809
2810 // Initialize central reference
2811 rootjQuery = jQuery( document );
2812
2813
2814 var rparentsprev = /^(?:parents|prev(?:Until|All))/,
2815         // methods guaranteed to produce a unique set when starting from a unique set
2816         guaranteedUnique = {
2817                 children: true,
2818                 contents: true,
2819                 next: true,
2820                 prev: true
2821         };
2822
2823 jQuery.extend({
2824         dir: function( elem, dir, until ) {
2825                 var matched = [],
2826                         truncate = until !== undefined;
2827
2828                 while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
2829                         if ( elem.nodeType === 1 ) {
2830                                 if ( truncate && jQuery( elem ).is( until ) ) {
2831                                         break;
2832                                 }
2833                                 matched.push( elem );
2834                         }
2835                 }
2836                 return matched;
2837         },
2838
2839         sibling: function( n, elem ) {
2840                 var matched = [];
2841
2842                 for ( ; n; n = n.nextSibling ) {
2843                         if ( n.nodeType === 1 && n !== elem ) {
2844                                 matched.push( n );
2845                         }
2846                 }
2847
2848                 return matched;
2849         }
2850 });
2851
2852 jQuery.fn.extend({
2853         has: function( target ) {
2854                 var targets = jQuery( target, this ),
2855                         l = targets.length;
2856
2857                 return this.filter(function() {
2858                         var i = 0;
2859                         for ( ; i < l; i++ ) {
2860                                 if ( jQuery.contains( this, targets[i] ) ) {
2861                                         return true;
2862                                 }
2863                         }
2864                 });
2865         },
2866
2867         closest: function( selectors, context ) {
2868                 var cur,
2869                         i = 0,
2870                         l = this.length,
2871                         matched = [],
2872                         pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
2873                                 jQuery( selectors, context || this.context ) :
2874                                 0;
2875
2876                 for ( ; i < l; i++ ) {
2877                         for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
2878                                 // Always skip document fragments
2879                                 if ( cur.nodeType < 11 && (pos ?
2880                                         pos.index(cur) > -1 :
2881
2882                                         // Don't pass non-elements to Sizzle
2883                                         cur.nodeType === 1 &&
2884                                                 jQuery.find.matchesSelector(cur, selectors)) ) {
2885
2886                                         matched.push( cur );
2887                                         break;
2888                                 }
2889                         }
2890                 }
2891
2892                 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
2893         },
2894
2895         // Determine the position of an element within
2896         // the matched set of elements
2897         index: function( elem ) {
2898
2899                 // No argument, return index in parent
2900                 if ( !elem ) {
2901                         return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
2902                 }
2903
2904                 // index in selector
2905                 if ( typeof elem === "string" ) {
2906                         return indexOf.call( jQuery( elem ), this[ 0 ] );
2907                 }
2908
2909                 // Locate the position of the desired element
2910                 return indexOf.call( this,
2911
2912                         // If it receives a jQuery object, the first element is used
2913                         elem.jquery ? elem[ 0 ] : elem
2914                 );
2915         },
2916
2917         add: function( selector, context ) {
2918                 return this.pushStack(
2919                         jQuery.unique(
2920                                 jQuery.merge( this.get(), jQuery( selector, context ) )
2921                         )
2922                 );
2923         },
2924
2925         addBack: function( selector ) {
2926                 return this.add( selector == null ?
2927                         this.prevObject : this.prevObject.filter(selector)
2928                 );
2929         }
2930 });
2931
2932 function sibling( cur, dir ) {
2933         while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
2934         return cur;
2935 }
2936
2937 jQuery.each({
2938         parent: function( elem ) {
2939                 var parent = elem.parentNode;
2940                 return parent && parent.nodeType !== 11 ? parent : null;
2941         },
2942         parents: function( elem ) {
2943                 return jQuery.dir( elem, "parentNode" );
2944         },
2945         parentsUntil: function( elem, i, until ) {
2946                 return jQuery.dir( elem, "parentNode", until );
2947         },
2948         next: function( elem ) {
2949                 return sibling( elem, "nextSibling" );
2950         },
2951         prev: function( elem ) {
2952                 return sibling( elem, "previousSibling" );
2953         },
2954         nextAll: function( elem ) {
2955                 return jQuery.dir( elem, "nextSibling" );
2956         },
2957         prevAll: function( elem ) {
2958                 return jQuery.dir( elem, "previousSibling" );
2959         },
2960         nextUntil: function( elem, i, until ) {
2961                 return jQuery.dir( elem, "nextSibling", until );
2962         },
2963         prevUntil: function( elem, i, until ) {
2964                 return jQuery.dir( elem, "previousSibling", until );
2965         },
2966         siblings: function( elem ) {
2967                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
2968         },
2969         children: function( elem ) {
2970                 return jQuery.sibling( elem.firstChild );
2971         },
2972         contents: function( elem ) {
2973                 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
2974         }
2975 }, function( name, fn ) {
2976         jQuery.fn[ name ] = function( until, selector ) {
2977                 var matched = jQuery.map( this, fn, until );
2978
2979                 if ( name.slice( -5 ) !== "Until" ) {
2980                         selector = until;
2981                 }
2982
2983                 if ( selector && typeof selector === "string" ) {
2984                         matched = jQuery.filter( selector, matched );
2985                 }
2986
2987                 if ( this.length > 1 ) {
2988                         // Remove duplicates
2989                         if ( !guaranteedUnique[ name ] ) {
2990                                 jQuery.unique( matched );
2991                         }
2992
2993                         // Reverse order for parents* and prev-derivatives
2994                         if ( rparentsprev.test( name ) ) {
2995                                 matched.reverse();
2996                         }
2997                 }
2998
2999                 return this.pushStack( matched );
3000         };
3001 });
3002 var rnotwhite = (/\S+/g);
3003
3004
3005
3006 // String to Object options format cache
3007 var optionsCache = {};
3008
3009 // Convert String-formatted options into Object-formatted ones and store in cache
3010 function createOptions( options ) {
3011         var object = optionsCache[ options ] = {};
3012         jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
3013                 object[ flag ] = true;
3014         });
3015         return object;
3016 }
3017
3018 /*
3019  * Create a callback list using the following parameters:
3020  *
3021  *      options: an optional list of space-separated options that will change how
3022  *                      the callback list behaves or a more traditional option object
3023  *
3024  * By default a callback list will act like an event callback list and can be
3025  * "fired" multiple times.
3026  *
3027  * Possible options:
3028  *
3029  *      once:                   will ensure the callback list can only be fired once (like a Deferred)
3030  *
3031  *      memory:                 will keep track of previous values and will call any callback added
3032  *                                      after the list has been fired right away with the latest "memorized"
3033  *                                      values (like a Deferred)
3034  *
3035  *      unique:                 will ensure a callback can only be added once (no duplicate in the list)
3036  *
3037  *      stopOnFalse:    interrupt callings when a callback returns false
3038  *
3039  */
3040 jQuery.Callbacks = function( options ) {
3041
3042         // Convert options from String-formatted to Object-formatted if needed
3043         // (we check in cache first)
3044         options = typeof options === "string" ?
3045                 ( optionsCache[ options ] || createOptions( options ) ) :
3046                 jQuery.extend( {}, options );
3047
3048         var // Last fire value (for non-forgettable lists)
3049                 memory,
3050                 // Flag to know if list was already fired
3051                 fired,
3052                 // Flag to know if list is currently firing
3053                 firing,
3054                 // First callback to fire (used internally by add and fireWith)
3055                 firingStart,
3056                 // End of the loop when firing
3057                 firingLength,
3058                 // Index of currently firing callback (modified by remove if needed)
3059                 firingIndex,
3060                 // Actual callback list
3061                 list = [],
3062                 // Stack of fire calls for repeatable lists
3063                 stack = !options.once && [],
3064                 // Fire callbacks
3065                 fire = function( data ) {
3066                         memory = options.memory && data;
3067                         fired = true;
3068                         firingIndex = firingStart || 0;
3069                         firingStart = 0;
3070                         firingLength = list.length;
3071                         firing = true;
3072                         for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3073                                 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3074                                         memory = false; // To prevent further calls using add
3075                                         break;
3076                                 }
3077                         }
3078                         firing = false;
3079                         if ( list ) {
3080                                 if ( stack ) {
3081                                         if ( stack.length ) {
3082                                                 fire( stack.shift() );
3083                                         }
3084                                 } else if ( memory ) {
3085                                         list = [];
3086                                 } else {
3087                                         self.disable();
3088                                 }
3089                         }
3090                 },
3091                 // Actual Callbacks object
3092                 self = {
3093                         // Add a callback or a collection of callbacks to the list
3094                         add: function() {
3095                                 if ( list ) {
3096                                         // First, we save the current length
3097                                         var start = list.length;
3098                                         (function add( args ) {
3099                                                 jQuery.each( args, function( _, arg ) {
3100                                                         var type = jQuery.type( arg );
3101                                                         if ( type === "function" ) {
3102                                                                 if ( !options.unique || !self.has( arg ) ) {
3103                                                                         list.push( arg );
3104                                                                 }
3105                                                         } else if ( arg && arg.length && type !== "string" ) {
3106                                                                 // Inspect recursively
3107                                                                 add( arg );
3108                                                         }
3109                                                 });
3110                                         })( arguments );
3111                                         // Do we need to add the callbacks to the
3112                                         // current firing batch?
3113                                         if ( firing ) {
3114                                                 firingLength = list.length;
3115                                         // With memory, if we're not firing then
3116                                         // we should call right away
3117                                         } else if ( memory ) {
3118                                                 firingStart = start;
3119                                                 fire( memory );
3120                                         }
3121                                 }
3122                                 return this;
3123                         },
3124                         // Remove a callback from the list
3125                         remove: function() {
3126                                 if ( list ) {
3127                                         jQuery.each( arguments, function( _, arg ) {
3128                                                 var index;
3129                                                 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3130                                                         list.splice( index, 1 );
3131                                                         // Handle firing indexes
3132                                                         if ( firing ) {
3133                                                                 if ( index <= firingLength ) {
3134                                                                         firingLength--;
3135                                                                 }
3136                                                                 if ( index <= firingIndex ) {
3137                                                                         firingIndex--;
3138                                                                 }
3139                                                         }
3140                                                 }
3141                                         });
3142                                 }
3143                                 return this;
3144                         },
3145                         // Check if a given callback is in the list.
3146                         // If no argument is given, return whether or not list has callbacks attached.
3147                         has: function( fn ) {
3148                                 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3149                         },
3150                         // Remove all callbacks from the list
3151                         empty: function() {
3152                                 list = [];
3153                                 firingLength = 0;
3154                                 return this;
3155                         },
3156                         // Have the list do nothing anymore
3157                         disable: function() {
3158                                 list = stack = memory = undefined;
3159                                 return this;
3160                         },
3161                         // Is it disabled?
3162                         disabled: function() {
3163                                 return !list;
3164                         },
3165                         // Lock the list in its current state
3166                         lock: function() {
3167                                 stack = undefined;
3168                                 if ( !memory ) {
3169                                         self.disable();
3170                                 }
3171                                 return this;
3172                         },
3173                         // Is it locked?
3174                         locked: function() {
3175                                 return !stack;
3176                         },
3177                         // Call all callbacks with the given context and arguments
3178                         fireWith: function( context, args ) {
3179                                 if ( list && ( !fired || stack ) ) {
3180                                         args = args || [];
3181                                         args = [ context, args.slice ? args.slice() : args ];
3182                                         if ( firing ) {
3183                                                 stack.push( args );
3184                                         } else {
3185                                                 fire( args );
3186                                         }
3187                                 }
3188                                 return this;
3189                         },
3190                         // Call all the callbacks with the given arguments
3191                         fire: function() {
3192                                 self.fireWith( this, arguments );
3193                                 return this;
3194                         },
3195                         // To know if the callbacks have already been called at least once
3196                         fired: function() {
3197                                 return !!fired;
3198                         }
3199                 };
3200
3201         return self;
3202 };
3203
3204
3205 jQuery.extend({
3206
3207         Deferred: function( func ) {
3208                 var tuples = [
3209                                 // action, add listener, listener list, final state
3210                                 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3211                                 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3212                                 [ "notify", "progress", jQuery.Callbacks("memory") ]
3213                         ],
3214                         state = "pending",
3215                         promise = {
3216                                 state: function() {
3217                                         return state;
3218                                 },
3219                                 always: function() {
3220                                         deferred.done( arguments ).fail( arguments );
3221                                         return this;
3222                                 },
3223                                 then: function( /* fnDone, fnFail, fnProgress */ ) {
3224                                         var fns = arguments;
3225                                         return jQuery.Deferred(function( newDefer ) {
3226                                                 jQuery.each( tuples, function( i, tuple ) {
3227                                                         var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3228                                                         // deferred[ done | fail | progress ] for forwarding actions to newDefer
3229                                                         deferred[ tuple[1] ](function() {
3230                                                                 var returned = fn && fn.apply( this, arguments );
3231                                                                 if ( returned && jQuery.isFunction( returned.promise ) ) {
3232                                                                         returned.promise()
3233                                                                                 .done( newDefer.resolve )
3234                                                                                 .fail( newDefer.reject )
3235                                                                                 .progress( newDefer.notify );
3236                                                                 } else {
3237                                                                         newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3238                                                                 }
3239                                                         });
3240                                                 });
3241                                                 fns = null;
3242                                         }).promise();
3243                                 },
3244                                 // Get a promise for this deferred
3245                                 // If obj is provided, the promise aspect is added to the object
3246                                 promise: function( obj ) {
3247                                         return obj != null ? jQuery.extend( obj, promise ) : promise;
3248                                 }
3249                         },
3250                         deferred = {};
3251
3252                 // Keep pipe for back-compat
3253                 promise.pipe = promise.then;
3254
3255                 // Add list-specific methods
3256                 jQuery.each( tuples, function( i, tuple ) {
3257                         var list = tuple[ 2 ],
3258                                 stateString = tuple[ 3 ];
3259
3260                         // promise[ done | fail | progress ] = list.add
3261                         promise[ tuple[1] ] = list.add;
3262
3263                         // Handle state
3264                         if ( stateString ) {
3265                                 list.add(function() {
3266                                         // state = [ resolved | rejected ]
3267                                         state = stateString;
3268
3269                                 // [ reject_list | resolve_list ].disable; progress_list.lock
3270                                 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3271                         }
3272
3273                         // deferred[ resolve | reject | notify ]
3274                         deferred[ tuple[0] ] = function() {
3275                                 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3276                                 return this;
3277                         };
3278                         deferred[ tuple[0] + "With" ] = list.fireWith;
3279                 });
3280
3281                 // Make the deferred a promise
3282                 promise.promise( deferred );
3283
3284                 // Call given func if any
3285                 if ( func ) {
3286                         func.call( deferred, deferred );
3287                 }
3288
3289                 // All done!
3290                 return deferred;
3291         },
3292
3293         // Deferred helper
3294         when: function( subordinate /* , ..., subordinateN */ ) {
3295                 var i = 0,
3296                         resolveValues = slice.call( arguments ),
3297                         length = resolveValues.length,
3298
3299                         // the count of uncompleted subordinates
3300                         remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3301
3302                         // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3303                         deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3304
3305                         // Update function for both resolve and progress values
3306                         updateFunc = function( i, contexts, values ) {
3307                                 return function( value ) {
3308                                         contexts[ i ] = this;
3309                                         values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3310                                         if ( values === progressValues ) {
3311                                                 deferred.notifyWith( contexts, values );
3312                                         } else if ( !( --remaining ) ) {
3313                                                 deferred.resolveWith( contexts, values );
3314                                         }
3315                                 };
3316                         },
3317
3318                         progressValues, progressContexts, resolveContexts;
3319
3320                 // add listeners to Deferred subordinates; treat others as resolved
3321                 if ( length > 1 ) {
3322                         progressValues = new Array( length );
3323                         progressContexts = new Array( length );
3324                         resolveContexts = new Array( length );
3325                         for ( ; i < length; i++ ) {
3326                                 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3327                                         resolveValues[ i ].promise()
3328                                                 .done( updateFunc( i, resolveContexts, resolveValues ) )
3329                                                 .fail( deferred.reject )
3330                                                 .progress( updateFunc( i, progressContexts, progressValues ) );
3331                                 } else {
3332                                         --remaining;
3333                                 }
3334                         }
3335                 }
3336
3337                 // if we're not waiting on anything, resolve the master
3338                 if ( !remaining ) {
3339                         deferred.resolveWith( resolveContexts, resolveValues );
3340                 }
3341
3342                 return deferred.promise();
3343         }
3344 });
3345
3346
3347 // The deferred used on DOM ready
3348 var readyList;
3349
3350 jQuery.fn.ready = function( fn ) {
3351         // Add the callback
3352         jQuery.ready.promise().done( fn );
3353
3354         return this;
3355 };
3356
3357 jQuery.extend({
3358         // Is the DOM ready to be used? Set to true once it occurs.
3359         isReady: false,
3360
3361         // A counter to track how many items to wait for before
3362         // the ready event fires. See #6781
3363         readyWait: 1,
3364
3365         // Hold (or release) the ready event
3366         holdReady: function( hold ) {
3367                 if ( hold ) {
3368                         jQuery.readyWait++;
3369                 } else {
3370                         jQuery.ready( true );
3371                 }
3372         },
3373
3374         // Handle when the DOM is ready
3375         ready: function( wait ) {
3376
3377                 // Abort if there are pending holds or we're already ready
3378                 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3379                         return;
3380                 }
3381
3382                 // Remember that the DOM is ready
3383                 jQuery.isReady = true;
3384
3385                 // If a normal DOM Ready event fired, decrement, and wait if need be
3386                 if ( wait !== true && --jQuery.readyWait > 0 ) {
3387                         return;
3388                 }
3389
3390                 // If there are functions bound, to execute
3391                 readyList.resolveWith( document, [ jQuery ] );
3392
3393                 // Trigger any bound ready events
3394                 if ( jQuery.fn.triggerHandler ) {
3395                         jQuery( document ).triggerHandler( "ready" );
3396                         jQuery( document ).off( "ready" );
3397                 }
3398         }
3399 });
3400
3401 /**
3402  * The ready event handler and self cleanup method
3403  */
3404 function completed() {
3405         document.removeEventListener( "DOMContentLoaded", completed, false );
3406         window.removeEventListener( "load", completed, false );
3407         jQuery.ready();
3408 }
3409
3410 jQuery.ready.promise = function( obj ) {
3411         if ( !readyList ) {
3412
3413                 readyList = jQuery.Deferred();
3414
3415                 // Catch cases where $(document).ready() is called after the browser event has already occurred.
3416                 // we once tried to use readyState "interactive" here, but it caused issues like the one
3417                 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
3418                 if ( document.readyState === "complete" ) {
3419                         // Handle it asynchronously to allow scripts the opportunity to delay ready
3420                         setTimeout( jQuery.ready );
3421
3422                 } else {
3423
3424                         // Use the handy event callback
3425                         document.addEventListener( "DOMContentLoaded", completed, false );
3426
3427                         // A fallback to window.onload, that will always work
3428                         window.addEventListener( "load", completed, false );
3429                 }
3430         }
3431         return readyList.promise( obj );
3432 };
3433
3434 // Kick off the DOM ready check even if the user does not
3435 jQuery.ready.promise();
3436
3437
3438
3439
3440 // Multifunctional method to get and set values of a collection
3441 // The value/s can optionally be executed if it's a function
3442 var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
3443         var i = 0,
3444                 len = elems.length,
3445                 bulk = key == null;
3446
3447         // Sets many values
3448         if ( jQuery.type( key ) === "object" ) {
3449                 chainable = true;
3450                 for ( i in key ) {
3451                         jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
3452                 }
3453
3454         // Sets one value
3455         } else if ( value !== undefined ) {
3456                 chainable = true;
3457
3458                 if ( !jQuery.isFunction( value ) ) {
3459                         raw = true;
3460                 }
3461
3462                 if ( bulk ) {
3463                         // Bulk operations run against the entire set
3464                         if ( raw ) {
3465                                 fn.call( elems, value );
3466                                 fn = null;
3467
3468                         // ...except when executing function values
3469                         } else {
3470                                 bulk = fn;
3471                                 fn = function( elem, key, value ) {
3472                                         return bulk.call( jQuery( elem ), value );
3473                                 };
3474                         }
3475                 }
3476
3477                 if ( fn ) {
3478                         for ( ; i < len; i++ ) {
3479                                 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
3480                         }
3481                 }
3482         }
3483
3484         return chainable ?
3485                 elems :
3486
3487                 // Gets
3488                 bulk ?
3489                         fn.call( elems ) :
3490                         len ? fn( elems[0], key ) : emptyGet;
3491 };
3492
3493
3494 /**
3495  * Determines whether an object can have data
3496  */
3497 jQuery.acceptData = function( owner ) {
3498         // Accepts only:
3499         //  - Node
3500         //    - Node.ELEMENT_NODE
3501         //    - Node.DOCUMENT_NODE
3502         //  - Object
3503         //    - Any
3504         /* jshint -W018 */
3505         return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
3506 };
3507
3508
3509 function Data() {
3510         // Support: Android < 4,
3511         // Old WebKit does not have Object.preventExtensions/freeze method,
3512         // return new empty object instead with no [[set]] accessor
3513         Object.defineProperty( this.cache = {}, 0, {
3514                 get: function() {
3515                         return {};
3516                 }
3517         });
3518
3519         this.expando = jQuery.expando + Math.random();
3520 }
3521
3522 Data.uid = 1;
3523 Data.accepts = jQuery.acceptData;
3524
3525 Data.prototype = {
3526         key: function( owner ) {
3527                 // We can accept data for non-element nodes in modern browsers,
3528                 // but we should not, see #8335.
3529                 // Always return the key for a frozen object.
3530                 if ( !Data.accepts( owner ) ) {
3531                         return 0;
3532                 }
3533
3534                 var descriptor = {},
3535                         // Check if the owner object already has a cache key
3536                         unlock = owner[ this.expando ];
3537
3538                 // If not, create one
3539                 if ( !unlock ) {
3540                         unlock = Data.uid++;
3541
3542                         // Secure it in a non-enumerable, non-writable property
3543                         try {
3544                                 descriptor[ this.expando ] = { value: unlock };
3545                                 Object.defineProperties( owner, descriptor );
3546
3547                         // Support: Android < 4
3548                         // Fallback to a less secure definition
3549                         } catch ( e ) {
3550                                 descriptor[ this.expando ] = unlock;
3551                                 jQuery.extend( owner, descriptor );
3552                         }
3553                 }
3554
3555                 // Ensure the cache object
3556                 if ( !this.cache[ unlock ] ) {
3557                         this.cache[ unlock ] = {};
3558                 }
3559
3560                 return unlock;
3561         },
3562         set: function( owner, data, value ) {
3563                 var prop,
3564                         // There may be an unlock assigned to this node,
3565                         // if there is no entry for this "owner", create one inline
3566                         // and set the unlock as though an owner entry had always existed
3567                         unlock = this.key( owner ),
3568                         cache = this.cache[ unlock ];
3569
3570                 // Handle: [ owner, key, value ] args
3571                 if ( typeof data === "string" ) {
3572                         cache[ data ] = value;
3573
3574                 // Handle: [ owner, { properties } ] args
3575                 } else {
3576                         // Fresh assignments by object are shallow copied
3577                         if ( jQuery.isEmptyObject( cache ) ) {
3578                                 jQuery.extend( this.cache[ unlock ], data );
3579                         // Otherwise, copy the properties one-by-one to the cache object
3580                         } else {
3581                                 for ( prop in data ) {
3582                                         cache[ prop ] = data[ prop ];
3583                                 }
3584                         }
3585                 }
3586                 return cache;
3587         },
3588         get: function( owner, key ) {
3589                 // Either a valid cache is found, or will be created.
3590                 // New caches will be created and the unlock returned,
3591                 // allowing direct access to the newly created
3592                 // empty data object. A valid owner object must be provided.
3593                 var cache = this.cache[ this.key( owner ) ];
3594
3595                 return key === undefined ?
3596                         cache : cache[ key ];
3597         },
3598         access: function( owner, key, value ) {
3599                 var stored;
3600                 // In cases where either:
3601                 //
3602                 //   1. No key was specified
3603                 //   2. A string key was specified, but no value provided
3604                 //
3605                 // Take the "read" path and allow the get method to determine
3606                 // which value to return, respectively either:
3607                 //
3608                 //   1. The entire cache object
3609                 //   2. The data stored at the key
3610                 //
3611                 if ( key === undefined ||
3612                                 ((key && typeof key === "string") && value === undefined) ) {
3613
3614                         stored = this.get( owner, key );
3615
3616                         return stored !== undefined ?
3617                                 stored : this.get( owner, jQuery.camelCase(key) );
3618                 }
3619
3620                 // [*]When the key is not a string, or both a key and value
3621                 // are specified, set or extend (existing objects) with either:
3622                 //
3623                 //   1. An object of properties
3624                 //   2. A key and value
3625                 //
3626                 this.set( owner, key, value );
3627
3628                 // Since the "set" path can have two possible entry points
3629                 // return the expected data based on which path was taken[*]
3630                 return value !== undefined ? value : key;
3631         },
3632         remove: function( owner, key ) {
3633                 var i, name, camel,
3634                         unlock = this.key( owner ),
3635                         cache = this.cache[ unlock ];
3636
3637                 if ( key === undefined ) {
3638                         this.cache[ unlock ] = {};
3639
3640                 } else {
3641                         // Support array or space separated string of keys
3642                         if ( jQuery.isArray( key ) ) {
3643                                 // If "name" is an array of keys...
3644                                 // When data is initially created, via ("key", "val") signature,
3645                                 // keys will be converted to camelCase.
3646                                 // Since there is no way to tell _how_ a key was added, remove
3647                                 // both plain key and camelCase key. #12786
3648                                 // This will only penalize the array argument path.
3649                                 name = key.concat( key.map( jQuery.camelCase ) );
3650                         } else {
3651                                 camel = jQuery.camelCase( key );
3652                                 // Try the string as a key before any manipulation
3653                                 if ( key in cache ) {
3654                                         name = [ key, camel ];
3655                                 } else {
3656                                         // If a key with the spaces exists, use it.
3657                                         // Otherwise, create an array by matching non-whitespace
3658                                         name = camel;
3659                                         name = name in cache ?
3660                                                 [ name ] : ( name.match( rnotwhite ) || [] );
3661                                 }
3662                         }
3663
3664                         i = name.length;
3665                         while ( i-- ) {
3666                                 delete cache[ name[ i ] ];
3667                         }
3668                 }
3669         },
3670         hasData: function( owner ) {
3671                 return !jQuery.isEmptyObject(
3672                         this.cache[ owner[ this.expando ] ] || {}
3673                 );
3674         },
3675         discard: function( owner ) {
3676                 if ( owner[ this.expando ] ) {
3677                         delete this.cache[ owner[ this.expando ] ];
3678                 }
3679         }
3680 };
3681 var data_priv = new Data();
3682
3683 var data_user = new Data();
3684
3685
3686
3687 /*
3688         Implementation Summary
3689
3690         1. Enforce API surface and semantic compatibility with 1.9.x branch
3691         2. Improve the module's maintainability by reducing the storage
3692                 paths to a single mechanism.
3693         3. Use the same single mechanism to support "private" and "user" data.
3694         4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
3695         5. Avoid exposing implementation details on user objects (eg. expando properties)
3696         6. Provide a clear path for implementation upgrade to WeakMap in 2014
3697 */
3698 var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
3699         rmultiDash = /([A-Z])/g;
3700
3701 function dataAttr( elem, key, data ) {
3702         var name;
3703
3704         // If nothing was found internally, try to fetch any
3705         // data from the HTML5 data-* attribute
3706         if ( data === undefined && elem.nodeType === 1 ) {
3707                 name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3708                 data = elem.getAttribute( name );
3709
3710                 if ( typeof data === "string" ) {
3711                         try {
3712                                 data = data === "true" ? true :
3713                                         data === "false" ? false :
3714                                         data === "null" ? null :
3715                                         // Only convert to a number if it doesn't change the string
3716                                         +data + "" === data ? +data :
3717                                         rbrace.test( data ) ? jQuery.parseJSON( data ) :
3718                                         data;
3719                         } catch( e ) {}
3720
3721                         // Make sure we set the data so it isn't changed later
3722                         data_user.set( elem, key, data );
3723                 } else {
3724                         data = undefined;
3725                 }
3726         }
3727         return data;
3728 }
3729
3730 jQuery.extend({
3731         hasData: function( elem ) {
3732                 return data_user.hasData( elem ) || data_priv.hasData( elem );
3733         },
3734
3735         data: function( elem, name, data ) {
3736                 return data_user.access( elem, name, data );
3737         },
3738
3739         removeData: function( elem, name ) {
3740                 data_user.remove( elem, name );
3741         },
3742
3743         // TODO: Now that all calls to _data and _removeData have been replaced
3744         // with direct calls to data_priv methods, these can be deprecated.
3745         _data: function( elem, name, data ) {
3746                 return data_priv.access( elem, name, data );
3747         },
3748
3749         _removeData: function( elem, name ) {
3750                 data_priv.remove( elem, name );
3751         }
3752 });
3753
3754 jQuery.fn.extend({
3755         data: function( key, value ) {
3756                 var i, name, data,
3757                         elem = this[ 0 ],
3758                         attrs = elem && elem.attributes;
3759
3760                 // Gets all values
3761                 if ( key === undefined ) {
3762                         if ( this.length ) {
3763                                 data = data_user.get( elem );
3764
3765                                 if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
3766                                         i = attrs.length;
3767                                         while ( i-- ) {
3768
3769                                                 // Support: IE11+
3770                                                 // The attrs elements can be null (#14894)
3771                                                 if ( attrs[ i ] ) {
3772                                                         name = attrs[ i ].name;
3773                                                         if ( name.indexOf( "data-" ) === 0 ) {
3774                                                                 name = jQuery.camelCase( name.slice(5) );
3775                                                                 dataAttr( elem, name, data[ name ] );
3776                                                         }
3777                                                 }
3778                                         }
3779                                         data_priv.set( elem, "hasDataAttrs", true );
3780                                 }
3781                         }
3782
3783                         return data;
3784                 }
3785
3786                 // Sets multiple values
3787                 if ( typeof key === "object" ) {
3788                         return this.each(function() {
3789                                 data_user.set( this, key );
3790                         });
3791                 }
3792
3793                 return access( this, function( value ) {
3794                         var data,
3795                                 camelKey = jQuery.camelCase( key );
3796
3797                         // The calling jQuery object (element matches) is not empty
3798                         // (and therefore has an element appears at this[ 0 ]) and the
3799                         // `value` parameter was not undefined. An empty jQuery object
3800                         // will result in `undefined` for elem = this[ 0 ] which will
3801                         // throw an exception if an attempt to read a data cache is made.
3802                         if ( elem && value === undefined ) {
3803                                 // Attempt to get data from the cache
3804                                 // with the key as-is
3805                                 data = data_user.get( elem, key );
3806                                 if ( data !== undefined ) {
3807                                         return data;
3808                                 }
3809
3810                                 // Attempt to get data from the cache
3811                                 // with the key camelized
3812                                 data = data_user.get( elem, camelKey );
3813                                 if ( data !== undefined ) {
3814                                         return data;
3815                                 }
3816
3817                                 // Attempt to "discover" the data in
3818                                 // HTML5 custom data-* attrs
3819                                 data = dataAttr( elem, camelKey, undefined );
3820                                 if ( data !== undefined ) {
3821                                         return data;
3822                                 }
3823
3824                                 // We tried really hard, but the data doesn't exist.
3825                                 return;
3826                         }
3827
3828                         // Set the data...
3829                         this.each(function() {
3830                                 // First, attempt to store a copy or reference of any
3831                                 // data that might've been store with a camelCased key.
3832                                 var data = data_user.get( this, camelKey );
3833
3834                                 // For HTML5 data-* attribute interop, we have to
3835                                 // store property names with dashes in a camelCase form.
3836                                 // This might not apply to all properties...*
3837                                 data_user.set( this, camelKey, value );
3838
3839                                 // *... In the case of properties that might _actually_
3840                                 // have dashes, we need to also store a copy of that
3841                                 // unchanged property.
3842                                 if ( key.indexOf("-") !== -1 && data !== undefined ) {
3843                                         data_user.set( this, key, value );
3844                                 }
3845                         });
3846                 }, null, value, arguments.length > 1, null, true );
3847         },
3848
3849         removeData: function( key ) {
3850                 return this.each(function() {
3851                         data_user.remove( this, key );
3852                 });
3853         }
3854 });
3855
3856
3857 jQuery.extend({
3858         queue: function( elem, type, data ) {
3859                 var queue;
3860
3861                 if ( elem ) {
3862                         type = ( type || "fx" ) + "queue";
3863                         queue = data_priv.get( elem, type );
3864
3865                         // Speed up dequeue by getting out quickly if this is just a lookup
3866                         if ( data ) {
3867                                 if ( !queue || jQuery.isArray( data ) ) {
3868                                         queue = data_priv.access( elem, type, jQuery.makeArray(data) );
3869                                 } else {
3870                                         queue.push( data );
3871                                 }
3872                         }
3873                         return queue || [];
3874                 }
3875         },
3876
3877         dequeue: function( elem, type ) {
3878                 type = type || "fx";
3879
3880                 var queue = jQuery.queue( elem, type ),
3881                         startLength = queue.length,
3882                         fn = queue.shift(),
3883                         hooks = jQuery._queueHooks( elem, type ),
3884                         next = function() {
3885                                 jQuery.dequeue( elem, type );
3886                         };
3887
3888                 // If the fx queue is dequeued, always remove the progress sentinel
3889                 if ( fn === "inprogress" ) {
3890                         fn = queue.shift();
3891                         startLength--;
3892                 }
3893
3894                 if ( fn ) {
3895
3896                         // Add a progress sentinel to prevent the fx queue from being
3897                         // automatically dequeued
3898                         if ( type === "fx" ) {
3899                                 queue.unshift( "inprogress" );
3900                         }
3901
3902                         // clear up the last queue stop function
3903                         delete hooks.stop;
3904                         fn.call( elem, next, hooks );
3905                 }
3906
3907                 if ( !startLength && hooks ) {
3908                         hooks.empty.fire();
3909                 }
3910         },
3911
3912         // not intended for public consumption - generates a queueHooks object, or returns the current one
3913         _queueHooks: function( elem, type ) {
3914                 var key = type + "queueHooks";
3915                 return data_priv.get( elem, key ) || data_priv.access( elem, key, {
3916                         empty: jQuery.Callbacks("once memory").add(function() {
3917                                 data_priv.remove( elem, [ type + "queue", key ] );
3918                         })
3919                 });
3920         }
3921 });
3922
3923 jQuery.fn.extend({
3924         queue: function( type, data ) {
3925                 var setter = 2;
3926
3927                 if ( typeof type !== "string" ) {
3928                         data = type;
3929                         type = "fx";
3930                         setter--;
3931                 }
3932
3933                 if ( arguments.length < setter ) {
3934                         return jQuery.queue( this[0], type );
3935                 }
3936
3937                 return data === undefined ?
3938                         this :
3939                         this.each(function() {
3940                                 var queue = jQuery.queue( this, type, data );
3941
3942                                 // ensure a hooks for this queue
3943                                 jQuery._queueHooks( this, type );
3944
3945                                 if ( type === "fx" && queue[0] !== "inprogress" ) {
3946                                         jQuery.dequeue( this, type );
3947                                 }
3948                         });
3949         },
3950         dequeue: function( type ) {
3951                 return this.each(function() {
3952                         jQuery.dequeue( this, type );
3953                 });
3954         },
3955         clearQueue: function( type ) {
3956                 return this.queue( type || "fx", [] );
3957         },
3958         // Get a promise resolved when queues of a certain type
3959         // are emptied (fx is the type by default)
3960         promise: function( type, obj ) {
3961                 var tmp,
3962                         count = 1,
3963                         defer = jQuery.Deferred(),
3964                         elements = this,
3965                         i = this.length,
3966                         resolve = function() {
3967                                 if ( !( --count ) ) {
3968                                         defer.resolveWith( elements, [ elements ] );
3969                                 }
3970                         };
3971
3972                 if ( typeof type !== "string" ) {
3973                         obj = type;
3974                         type = undefined;
3975                 }
3976                 type = type || "fx";
3977
3978                 while ( i-- ) {
3979                         tmp = data_priv.get( elements[ i ], type + "queueHooks" );
3980                         if ( tmp && tmp.empty ) {
3981                                 count++;
3982                                 tmp.empty.add( resolve );
3983                         }
3984                 }
3985                 resolve();
3986                 return defer.promise( obj );
3987         }
3988 });
3989 var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
3990
3991 var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
3992
3993 var isHidden = function( elem, el ) {
3994                 // isHidden might be called from jQuery#filter function;
3995                 // in that case, element will be second argument
3996                 elem = el || elem;
3997                 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
3998         };
3999
4000 var rcheckableType = (/^(?:checkbox|radio)$/i);
4001
4002
4003
4004 (function() {
4005         var fragment = document.createDocumentFragment(),
4006                 div = fragment.appendChild( document.createElement( "div" ) ),
4007                 input = document.createElement( "input" );
4008
4009         // #11217 - WebKit loses check when the name is after the checked attribute
4010         // Support: Windows Web Apps (WWA)
4011         // `name` and `type` need .setAttribute for WWA
4012         input.setAttribute( "type", "radio" );
4013         input.setAttribute( "checked", "checked" );
4014         input.setAttribute( "name", "t" );
4015
4016         div.appendChild( input );
4017
4018         // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
4019         // old WebKit doesn't clone checked state correctly in fragments
4020         support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4021
4022         // Make sure textarea (and checkbox) defaultValue is properly cloned
4023         // Support: IE9-IE11+
4024         div.innerHTML = "<textarea>x</textarea>";
4025         support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4026 })();
4027 var strundefined = typeof undefined;
4028
4029
4030
4031 support.focusinBubbles = "onfocusin" in window;
4032
4033
4034 var
4035         rkeyEvent = /^key/,
4036         rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
4037         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4038         rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4039
4040 function returnTrue() {
4041         return true;
4042 }
4043
4044 function returnFalse() {
4045         return false;
4046 }
4047
4048 function safeActiveElement() {
4049         try {
4050                 return document.activeElement;
4051         } catch ( err ) { }
4052 }
4053
4054 /*
4055  * Helper functions for managing events -- not part of the public interface.
4056  * Props to Dean Edwards' addEvent library for many of the ideas.
4057  */
4058 jQuery.event = {
4059
4060         global: {},
4061
4062         add: function( elem, types, handler, data, selector ) {
4063
4064                 var handleObjIn, eventHandle, tmp,
4065                         events, t, handleObj,
4066                         special, handlers, type, namespaces, origType,
4067                         elemData = data_priv.get( elem );
4068
4069                 // Don't attach events to noData or text/comment nodes (but allow plain objects)
4070                 if ( !elemData ) {
4071                         return;
4072                 }
4073
4074                 // Caller can pass in an object of custom data in lieu of the handler
4075                 if ( handler.handler ) {
4076                         handleObjIn = handler;
4077                         handler = handleObjIn.handler;
4078                         selector = handleObjIn.selector;
4079                 }
4080
4081                 // Make sure that the handler has a unique ID, used to find/remove it later
4082                 if ( !handler.guid ) {
4083                         handler.guid = jQuery.guid++;
4084                 }
4085
4086                 // Init the element's event structure and main handler, if this is the first
4087                 if ( !(events = elemData.events) ) {
4088                         events = elemData.events = {};
4089                 }
4090                 if ( !(eventHandle = elemData.handle) ) {
4091                         eventHandle = elemData.handle = function( e ) {
4092                                 // Discard the second event of a jQuery.event.trigger() and
4093                                 // when an event is called after a page has unloaded
4094                                 return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
4095                                         jQuery.event.dispatch.apply( elem, arguments ) : undefined;
4096                         };
4097                 }
4098
4099                 // Handle multiple events separated by a space
4100                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
4101                 t = types.length;
4102                 while ( t-- ) {
4103                         tmp = rtypenamespace.exec( types[t] ) || [];
4104                         type = origType = tmp[1];
4105                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4106
4107                         // There *must* be a type, no attaching namespace-only handlers
4108                         if ( !type ) {
4109                                 continue;
4110                         }
4111
4112                         // If event changes its type, use the special event handlers for the changed type
4113                         special = jQuery.event.special[ type ] || {};
4114
4115                         // If selector defined, determine special event api type, otherwise given type
4116                         type = ( selector ? special.delegateType : special.bindType ) || type;
4117
4118                         // Update special based on newly reset type
4119                         special = jQuery.event.special[ type ] || {};
4120
4121                         // handleObj is passed to all event handlers
4122                         handleObj = jQuery.extend({
4123                                 type: type,
4124                                 origType: origType,
4125                                 data: data,
4126                                 handler: handler,
4127                                 guid: handler.guid,
4128                                 selector: selector,
4129                                 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4130                                 namespace: namespaces.join(".")
4131                         }, handleObjIn );
4132
4133                         // Init the event handler queue if we're the first
4134                         if ( !(handlers = events[ type ]) ) {
4135                                 handlers = events[ type ] = [];
4136                                 handlers.delegateCount = 0;
4137
4138                                 // Only use addEventListener if the special events handler returns false
4139                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4140                                         if ( elem.addEventListener ) {
4141                                                 elem.addEventListener( type, eventHandle, false );
4142                                         }
4143                                 }
4144                         }
4145
4146                         if ( special.add ) {
4147                                 special.add.call( elem, handleObj );
4148
4149                                 if ( !handleObj.handler.guid ) {
4150                                         handleObj.handler.guid = handler.guid;
4151                                 }
4152                         }
4153
4154                         // Add to the element's handler list, delegates in front
4155                         if ( selector ) {
4156                                 handlers.splice( handlers.delegateCount++, 0, handleObj );
4157                         } else {
4158                                 handlers.push( handleObj );
4159                         }
4160
4161                         // Keep track of which events have ever been used, for event optimization
4162                         jQuery.event.global[ type ] = true;
4163                 }
4164
4165         },
4166
4167         // Detach an event or set of events from an element
4168         remove: function( elem, types, handler, selector, mappedTypes ) {
4169
4170                 var j, origCount, tmp,
4171                         events, t, handleObj,
4172                         special, handlers, type, namespaces, origType,
4173                         elemData = data_priv.hasData( elem ) && data_priv.get( elem );
4174
4175                 if ( !elemData || !(events = elemData.events) ) {
4176                         return;
4177                 }
4178
4179                 // Once for each type.namespace in types; type may be omitted
4180                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
4181                 t = types.length;
4182                 while ( t-- ) {
4183                         tmp = rtypenamespace.exec( types[t] ) || [];
4184                         type = origType = tmp[1];
4185                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4186
4187                         // Unbind all events (on this namespace, if provided) for the element
4188                         if ( !type ) {
4189                                 for ( type in events ) {
4190                                         jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4191                                 }
4192                                 continue;
4193                         }
4194
4195                         special = jQuery.event.special[ type ] || {};
4196                         type = ( selector ? special.delegateType : special.bindType ) || type;
4197                         handlers = events[ type ] || [];
4198                         tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4199
4200                         // Remove matching events
4201                         origCount = j = handlers.length;
4202                         while ( j-- ) {
4203                                 handleObj = handlers[ j ];
4204
4205                                 if ( ( mappedTypes || origType === handleObj.origType ) &&
4206                                         ( !handler || handler.guid === handleObj.guid ) &&
4207                                         ( !tmp || tmp.test( handleObj.namespace ) ) &&
4208                                         ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4209                                         handlers.splice( j, 1 );
4210
4211                                         if ( handleObj.selector ) {
4212                                                 handlers.delegateCount--;
4213                                         }
4214                                         if ( special.remove ) {
4215                                                 special.remove.call( elem, handleObj );
4216                                         }
4217                                 }
4218                         }
4219
4220                         // Remove generic event handler if we removed something and no more handlers exist
4221                         // (avoids potential for endless recursion during removal of special event handlers)
4222                         if ( origCount && !handlers.length ) {
4223                                 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4224                                         jQuery.removeEvent( elem, type, elemData.handle );
4225                                 }
4226
4227                                 delete events[ type ];
4228                         }
4229                 }
4230
4231                 // Remove the expando if it's no longer used
4232                 if ( jQuery.isEmptyObject( events ) ) {
4233                         delete elemData.handle;
4234                         data_priv.remove( elem, "events" );
4235                 }
4236         },
4237
4238         trigger: function( event, data, elem, onlyHandlers ) {
4239
4240                 var i, cur, tmp, bubbleType, ontype, handle, special,
4241                         eventPath = [ elem || document ],
4242                         type = hasOwn.call( event, "type" ) ? event.type : event,
4243                         namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4244
4245                 cur = tmp = elem = elem || document;
4246
4247                 // Don't do events on text and comment nodes
4248                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4249                         return;
4250                 }
4251
4252                 // focus/blur morphs to focusin/out; ensure we're not firing them right now
4253                 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4254                         return;
4255                 }
4256
4257                 if ( type.indexOf(".") >= 0 ) {
4258                         // Namespaced trigger; create a regexp to match event type in handle()
4259                         namespaces = type.split(".");
4260                         type = namespaces.shift();
4261                         namespaces.sort();
4262                 }
4263                 ontype = type.indexOf(":") < 0 && "on" + type;
4264
4265                 // Caller can pass in a jQuery.Event object, Object, or just an event type string
4266                 event = event[ jQuery.expando ] ?
4267                         event :
4268                         new jQuery.Event( type, typeof event === "object" && event );
4269
4270                 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4271                 event.isTrigger = onlyHandlers ? 2 : 3;
4272                 event.namespace = namespaces.join(".");
4273                 event.namespace_re = event.namespace ?
4274                         new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4275                         null;
4276
4277                 // Clean up the event in case it is being reused
4278                 event.result = undefined;
4279                 if ( !event.target ) {
4280                         event.target = elem;
4281                 }
4282
4283                 // Clone any incoming data and prepend the event, creating the handler arg list
4284                 data = data == null ?
4285                         [ event ] :
4286                         jQuery.makeArray( data, [ event ] );
4287
4288                 // Allow special events to draw outside the lines
4289                 special = jQuery.event.special[ type ] || {};
4290                 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4291                         return;
4292                 }
4293
4294                 // Determine event propagation path in advance, per W3C events spec (#9951)
4295                 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4296                 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4297
4298                         bubbleType = special.delegateType || type;
4299                         if ( !rfocusMorph.test( bubbleType + type ) ) {
4300                                 cur = cur.parentNode;
4301                         }
4302                         for ( ; cur; cur = cur.parentNode ) {
4303                                 eventPath.push( cur );
4304                                 tmp = cur;
4305                         }
4306
4307                         // Only add window if we got to document (e.g., not plain obj or detached DOM)
4308                         if ( tmp === (elem.ownerDocument || document) ) {
4309                                 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4310                         }
4311                 }
4312
4313                 // Fire handlers on the event path
4314                 i = 0;
4315                 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4316
4317                         event.type = i > 1 ?
4318                                 bubbleType :
4319                                 special.bindType || type;
4320
4321                         // jQuery handler
4322                         handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
4323                         if ( handle ) {
4324                                 handle.apply( cur, data );
4325                         }
4326
4327                         // Native handler
4328                         handle = ontype && cur[ ontype ];
4329                         if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
4330                                 event.result = handle.apply( cur, data );
4331                                 if ( event.result === false ) {
4332                                         event.preventDefault();
4333                                 }
4334                         }
4335                 }
4336                 event.type = type;
4337
4338                 // If nobody prevented the default action, do it now
4339                 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
4340
4341                         if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
4342                                 jQuery.acceptData( elem ) ) {
4343
4344                                 // Call a native DOM method on the target with the same name name as the event.
4345                                 // Don't do default actions on window, that's where global variables be (#6170)
4346                                 if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
4347
4348                                         // Don't re-trigger an onFOO event when we call its FOO() method
4349                                         tmp = elem[ ontype ];
4350
4351                                         if ( tmp ) {
4352                                                 elem[ ontype ] = null;
4353                                         }
4354
4355                                         // Prevent re-triggering of the same event, since we already bubbled it above
4356                                         jQuery.event.triggered = type;
4357                                         elem[ type ]();
4358                                         jQuery.event.triggered = undefined;
4359
4360                                         if ( tmp ) {
4361                                                 elem[ ontype ] = tmp;
4362                                         }
4363                                 }
4364                         }
4365                 }
4366
4367                 return event.result;
4368         },
4369
4370         dispatch: function( event ) {
4371
4372                 // Make a writable jQuery.Event from the native event object
4373                 event = jQuery.event.fix( event );
4374
4375                 var i, j, ret, matched, handleObj,
4376                         handlerQueue = [],
4377                         args = slice.call( arguments ),
4378                         handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
4379                         special = jQuery.event.special[ event.type ] || {};
4380
4381                 // Use the fix-ed jQuery.Event rather than the (read-only) native event
4382                 args[0] = event;
4383                 event.delegateTarget = this;
4384
4385                 // Call the preDispatch hook for the mapped type, and let it bail if desired
4386                 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
4387                         return;
4388                 }
4389
4390                 // Determine handlers
4391                 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
4392
4393                 // Run delegates first; they may want to stop propagation beneath us
4394                 i = 0;
4395                 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
4396                         event.currentTarget = matched.elem;
4397
4398                         j = 0;
4399                         while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
4400
4401                                 // Triggered event must either 1) have no namespace, or
4402                                 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
4403                                 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
4404
4405                                         event.handleObj = handleObj;
4406                                         event.data = handleObj.data;
4407
4408                                         ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
4409                                                         .apply( matched.elem, args );
4410
4411                                         if ( ret !== undefined ) {
4412                                                 if ( (event.result = ret) === false ) {
4413                                                         event.preventDefault();
4414                                                         event.stopPropagation();
4415                                                 }
4416                                         }
4417                                 }
4418                         }
4419                 }
4420
4421                 // Call the postDispatch hook for the mapped type
4422                 if ( special.postDispatch ) {
4423                         special.postDispatch.call( this, event );
4424                 }
4425
4426                 return event.result;
4427         },
4428
4429         handlers: function( event, handlers ) {
4430                 var i, matches, sel, handleObj,
4431                         handlerQueue = [],
4432                         delegateCount = handlers.delegateCount,
4433                         cur = event.target;
4434
4435                 // Find delegate handlers
4436                 // Black-hole SVG <use> instance trees (#13180)
4437                 // Avoid non-left-click bubbling in Firefox (#3861)
4438                 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
4439
4440                         for ( ; cur !== this; cur = cur.parentNode || this ) {
4441
4442                                 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
4443                                 if ( cur.disabled !== true || event.type !== "click" ) {
4444                                         matches = [];
4445                                         for ( i = 0; i < delegateCount; i++ ) {
4446                                                 handleObj = handlers[ i ];
4447
4448                                                 // Don't conflict with Object.prototype properties (#13203)
4449                                                 sel = handleObj.selector + " ";
4450
4451                                                 if ( matches[ sel ] === undefined ) {
4452                                                         matches[ sel ] = handleObj.needsContext ?
4453                                                                 jQuery( sel, this ).index( cur ) >= 0 :
4454                                                                 jQuery.find( sel, this, null, [ cur ] ).length;
4455                                                 }
4456                                                 if ( matches[ sel ] ) {
4457                                                         matches.push( handleObj );
4458                                                 }
4459                                         }
4460                                         if ( matches.length ) {
4461                                                 handlerQueue.push({ elem: cur, handlers: matches });
4462                                         }
4463                                 }
4464                         }
4465                 }
4466
4467                 // Add the remaining (directly-bound) handlers
4468                 if ( delegateCount < handlers.length ) {
4469                         handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
4470                 }
4471
4472                 return handlerQueue;
4473         },
4474
4475         // Includes some event props shared by KeyEvent and MouseEvent
4476         props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
4477
4478         fixHooks: {},
4479
4480         keyHooks: {
4481                 props: "char charCode key keyCode".split(" "),
4482                 filter: function( event, original ) {
4483
4484                         // Add which for key events
4485                         if ( event.which == null ) {
4486                                 event.which = original.charCode != null ? original.charCode : original.keyCode;
4487                         }
4488
4489                         return event;
4490                 }
4491         },
4492
4493         mouseHooks: {
4494                 props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
4495                 filter: function( event, original ) {
4496                         var eventDoc, doc, body,
4497                                 button = original.button;
4498
4499                         // Calculate pageX/Y if missing and clientX/Y available
4500                         if ( event.pageX == null && original.clientX != null ) {
4501                                 eventDoc = event.target.ownerDocument || document;
4502                                 doc = eventDoc.documentElement;
4503                                 body = eventDoc.body;
4504
4505                                 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
4506                                 event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
4507                         }
4508
4509                         // Add which for click: 1 === left; 2 === middle; 3 === right
4510                         // Note: button is not normalized, so don't use it
4511                         if ( !event.which && button !== undefined ) {
4512                                 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4513                         }
4514
4515                         return event;
4516                 }
4517         },
4518
4519         fix: function( event ) {
4520                 if ( event[ jQuery.expando ] ) {
4521                         return event;
4522                 }
4523
4524                 // Create a writable copy of the event object and normalize some properties
4525                 var i, prop, copy,
4526                         type = event.type,
4527                         originalEvent = event,
4528                         fixHook = this.fixHooks[ type ];
4529
4530                 if ( !fixHook ) {
4531                         this.fixHooks[ type ] = fixHook =
4532                                 rmouseEvent.test( type ) ? this.mouseHooks :
4533                                 rkeyEvent.test( type ) ? this.keyHooks :
4534                                 {};
4535                 }
4536                 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4537
4538                 event = new jQuery.Event( originalEvent );
4539
4540                 i = copy.length;
4541                 while ( i-- ) {
4542                         prop = copy[ i ];
4543                         event[ prop ] = originalEvent[ prop ];
4544                 }
4545
4546                 // Support: Cordova 2.5 (WebKit) (#13255)
4547                 // All events should have a target; Cordova deviceready doesn't
4548                 if ( !event.target ) {
4549                         event.target = document;
4550                 }
4551
4552                 // Support: Safari 6.0+, Chrome < 28
4553                 // Target should not be a text node (#504, #13143)
4554                 if ( event.target.nodeType === 3 ) {
4555                         event.target = event.target.parentNode;
4556                 }
4557
4558                 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
4559         },
4560
4561         special: {
4562                 load: {
4563                         // Prevent triggered image.load events from bubbling to window.load
4564                         noBubble: true
4565                 },
4566                 focus: {
4567                         // Fire native event if possible so blur/focus sequence is correct
4568                         trigger: function() {
4569                                 if ( this !== safeActiveElement() && this.focus ) {
4570                                         this.focus();
4571                                         return false;
4572                                 }
4573                         },
4574                         delegateType: "focusin"
4575                 },
4576                 blur: {
4577                         trigger: function() {
4578                                 if ( this === safeActiveElement() && this.blur ) {
4579                                         this.blur();
4580                                         return false;
4581                                 }
4582                         },
4583                         delegateType: "focusout"
4584                 },
4585                 click: {
4586                         // For checkbox, fire native event so checked state will be right
4587                         trigger: function() {
4588                                 if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
4589                                         this.click();
4590                                         return false;
4591                                 }
4592                         },
4593
4594                         // For cross-browser consistency, don't fire native .click() on links
4595                         _default: function( event ) {
4596                                 return jQuery.nodeName( event.target, "a" );
4597                         }
4598                 },
4599
4600                 beforeunload: {
4601                         postDispatch: function( event ) {
4602
4603                                 // Support: Firefox 20+
4604                                 // Firefox doesn't alert if the returnValue field is not set.
4605                                 if ( event.result !== undefined && event.originalEvent ) {
4606                                         event.originalEvent.returnValue = event.result;
4607                                 }
4608                         }
4609                 }
4610         },
4611
4612         simulate: function( type, elem, event, bubble ) {
4613                 // Piggyback on a donor event to simulate a different one.
4614                 // Fake originalEvent to avoid donor's stopPropagation, but if the
4615                 // simulated event prevents default then we do the same on the donor.
4616                 var e = jQuery.extend(
4617                         new jQuery.Event(),
4618                         event,
4619                         {
4620                                 type: type,
4621                                 isSimulated: true,
4622                                 originalEvent: {}
4623                         }
4624                 );
4625                 if ( bubble ) {
4626                         jQuery.event.trigger( e, null, elem );
4627                 } else {
4628                         jQuery.event.dispatch.call( elem, e );
4629                 }
4630                 if ( e.isDefaultPrevented() ) {
4631                         event.preventDefault();
4632                 }
4633         }
4634 };
4635
4636 jQuery.removeEvent = function( elem, type, handle ) {
4637         if ( elem.removeEventListener ) {
4638                 elem.removeEventListener( type, handle, false );
4639         }
4640 };
4641
4642 jQuery.Event = function( src, props ) {
4643         // Allow instantiation without the 'new' keyword
4644         if ( !(this instanceof jQuery.Event) ) {
4645                 return new jQuery.Event( src, props );
4646         }
4647
4648         // Event object
4649         if ( src && src.type ) {
4650                 this.originalEvent = src;
4651                 this.type = src.type;
4652
4653                 // Events bubbling up the document may have been marked as prevented
4654                 // by a handler lower down the tree; reflect the correct value.
4655                 this.isDefaultPrevented = src.defaultPrevented ||
4656                                 src.defaultPrevented === undefined &&
4657                                 // Support: Android < 4.0
4658                                 src.returnValue === false ?
4659                         returnTrue :
4660                         returnFalse;
4661
4662         // Event type
4663         } else {
4664                 this.type = src;
4665         }
4666
4667         // Put explicitly provided properties onto the event object
4668         if ( props ) {
4669                 jQuery.extend( this, props );
4670         }
4671
4672         // Create a timestamp if incoming event doesn't have one
4673         this.timeStamp = src && src.timeStamp || jQuery.now();
4674
4675         // Mark it as fixed
4676         this[ jQuery.expando ] = true;
4677 };
4678
4679 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4680 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4681 jQuery.Event.prototype = {
4682         isDefaultPrevented: returnFalse,
4683         isPropagationStopped: returnFalse,
4684         isImmediatePropagationStopped: returnFalse,
4685
4686         preventDefault: function() {
4687                 var e = this.originalEvent;
4688
4689                 this.isDefaultPrevented = returnTrue;
4690
4691                 if ( e && e.preventDefault ) {
4692                         e.preventDefault();
4693                 }
4694         },
4695         stopPropagation: function() {
4696                 var e = this.originalEvent;
4697
4698                 this.isPropagationStopped = returnTrue;
4699
4700                 if ( e && e.stopPropagation ) {
4701                         e.stopPropagation();
4702                 }
4703         },
4704         stopImmediatePropagation: function() {
4705                 var e = this.originalEvent;
4706
4707                 this.isImmediatePropagationStopped = returnTrue;
4708
4709                 if ( e && e.stopImmediatePropagation ) {
4710                         e.stopImmediatePropagation();
4711                 }
4712
4713                 this.stopPropagation();
4714         }
4715 };
4716
4717 // Create mouseenter/leave events using mouseover/out and event-time checks
4718 // Support: Chrome 15+
4719 jQuery.each({
4720         mouseenter: "mouseover",
4721         mouseleave: "mouseout",
4722         pointerenter: "pointerover",
4723         pointerleave: "pointerout"
4724 }, function( orig, fix ) {
4725         jQuery.event.special[ orig ] = {
4726                 delegateType: fix,
4727                 bindType: fix,
4728
4729                 handle: function( event ) {
4730                         var ret,
4731                                 target = this,
4732                                 related = event.relatedTarget,
4733                                 handleObj = event.handleObj;
4734
4735                         // For mousenter/leave call the handler if related is outside the target.
4736                         // NB: No relatedTarget if the mouse left/entered the browser window
4737                         if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
4738                                 event.type = handleObj.origType;
4739                                 ret = handleObj.handler.apply( this, arguments );
4740                                 event.type = fix;
4741                         }
4742                         return ret;
4743                 }
4744         };
4745 });
4746
4747 // Create "bubbling" focus and blur events
4748 // Support: Firefox, Chrome, Safari
4749 if ( !support.focusinBubbles ) {
4750         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
4751
4752                 // Attach a single capturing handler on the document while someone wants focusin/focusout
4753                 var handler = function( event ) {
4754                                 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
4755                         };
4756
4757                 jQuery.event.special[ fix ] = {
4758                         setup: function() {
4759                                 var doc = this.ownerDocument || this,
4760                                         attaches = data_priv.access( doc, fix );
4761
4762                                 if ( !attaches ) {
4763                                         doc.addEventListener( orig, handler, true );
4764                                 }
4765                                 data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
4766                         },
4767                         teardown: function() {
4768                                 var doc = this.ownerDocument || this,
4769                                         attaches = data_priv.access( doc, fix ) - 1;
4770
4771                                 if ( !attaches ) {
4772                                         doc.removeEventListener( orig, handler, true );
4773                                         data_priv.remove( doc, fix );
4774
4775                                 } else {
4776                                         data_priv.access( doc, fix, attaches );
4777                                 }
4778                         }
4779                 };
4780         });
4781 }
4782
4783 jQuery.fn.extend({
4784
4785         on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
4786                 var origFn, type;
4787
4788                 // Types can be a map of types/handlers
4789                 if ( typeof types === "object" ) {
4790                         // ( types-Object, selector, data )
4791                         if ( typeof selector !== "string" ) {
4792                                 // ( types-Object, data )
4793                                 data = data || selector;
4794                                 selector = undefined;
4795                         }
4796                         for ( type in types ) {
4797                                 this.on( type, selector, data, types[ type ], one );
4798                         }
4799                         return this;
4800                 }
4801
4802                 if ( data == null && fn == null ) {
4803                         // ( types, fn )
4804                         fn = selector;
4805                         data = selector = undefined;
4806                 } else if ( fn == null ) {
4807                         if ( typeof selector === "string" ) {
4808                                 // ( types, selector, fn )
4809                                 fn = data;
4810                                 data = undefined;
4811                         } else {
4812                                 // ( types, data, fn )
4813                                 fn = data;
4814                                 data = selector;
4815                                 selector = undefined;
4816                         }
4817                 }
4818                 if ( fn === false ) {
4819                         fn = returnFalse;
4820                 } else if ( !fn ) {
4821                         return this;
4822                 }
4823
4824                 if ( one === 1 ) {
4825                         origFn = fn;
4826                         fn = function( event ) {
4827                                 // Can use an empty set, since event contains the info
4828                                 jQuery().off( event );
4829                                 return origFn.apply( this, arguments );
4830                         };
4831                         // Use same guid so caller can remove using origFn
4832                         fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4833                 }
4834                 return this.each( function() {
4835                         jQuery.event.add( this, types, fn, data, selector );
4836                 });
4837         },
4838         one: function( types, selector, data, fn ) {
4839                 return this.on( types, selector, data, fn, 1 );
4840         },
4841         off: function( types, selector, fn ) {
4842                 var handleObj, type;
4843                 if ( types && types.preventDefault && types.handleObj ) {
4844                         // ( event )  dispatched jQuery.Event
4845                         handleObj = types.handleObj;
4846                         jQuery( types.delegateTarget ).off(
4847                                 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
4848                                 handleObj.selector,
4849                                 handleObj.handler
4850                         );
4851                         return this;
4852                 }
4853                 if ( typeof types === "object" ) {
4854                         // ( types-object [, selector] )
4855                         for ( type in types ) {
4856                                 this.off( type, selector, types[ type ] );
4857                         }
4858                         return this;
4859                 }
4860                 if ( selector === false || typeof selector === "function" ) {
4861                         // ( types [, fn] )
4862                         fn = selector;
4863                         selector = undefined;
4864                 }
4865                 if ( fn === false ) {
4866                         fn = returnFalse;
4867                 }
4868                 return this.each(function() {
4869                         jQuery.event.remove( this, types, fn, selector );
4870                 });
4871         },
4872
4873         trigger: function( type, data ) {
4874                 return this.each(function() {
4875                         jQuery.event.trigger( type, data, this );
4876                 });
4877         },
4878         triggerHandler: function( type, data ) {
4879                 var elem = this[0];
4880                 if ( elem ) {
4881                         return jQuery.event.trigger( type, data, elem, true );
4882                 }
4883         }
4884 });
4885
4886
4887 var
4888         rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
4889         rtagName = /<([\w:]+)/,
4890         rhtml = /<|&#?\w+;/,
4891         rnoInnerhtml = /<(?:script|style|link)/i,
4892         // checked="checked" or checked
4893         rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
4894         rscriptType = /^$|\/(?:java|ecma)script/i,
4895         rscriptTypeMasked = /^true\/(.*)/,
4896         rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
4897
4898         // We have to close these tags to support XHTML (#13200)
4899         wrapMap = {
4900
4901                 // Support: IE 9
4902                 option: [ 1, "<select multiple='multiple'>", "</select>" ],
4903
4904                 thead: [ 1, "<table>", "</table>" ],
4905                 col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
4906                 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4907                 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4908
4909                 _default: [ 0, "", "" ]
4910         };
4911
4912 // Support: IE 9
4913 wrapMap.optgroup = wrapMap.option;
4914
4915 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4916 wrapMap.th = wrapMap.td;
4917
4918 // Support: 1.x compatibility
4919 // Manipulating tables requires a tbody
4920 function manipulationTarget( elem, content ) {
4921         return jQuery.nodeName( elem, "table" ) &&
4922                 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
4923
4924                 elem.getElementsByTagName("tbody")[0] ||
4925                         elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
4926                 elem;
4927 }
4928
4929 // Replace/restore the type attribute of script elements for safe DOM manipulation
4930 function disableScript( elem ) {
4931         elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
4932         return elem;
4933 }
4934 function restoreScript( elem ) {
4935         var match = rscriptTypeMasked.exec( elem.type );
4936
4937         if ( match ) {
4938                 elem.type = match[ 1 ];
4939         } else {
4940                 elem.removeAttribute("type");
4941         }
4942
4943         return elem;
4944 }
4945
4946 // Mark scripts as having already been evaluated
4947 function setGlobalEval( elems, refElements ) {
4948         var i = 0,
4949                 l = elems.length;
4950
4951         for ( ; i < l; i++ ) {
4952                 data_priv.set(
4953                         elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
4954                 );
4955         }
4956 }
4957
4958 function cloneCopyEvent( src, dest ) {
4959         var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
4960
4961         if ( dest.nodeType !== 1 ) {
4962                 return;
4963         }
4964
4965         // 1. Copy private data: events, handlers, etc.
4966         if ( data_priv.hasData( src ) ) {
4967                 pdataOld = data_priv.access( src );
4968                 pdataCur = data_priv.set( dest, pdataOld );
4969                 events = pdataOld.events;
4970
4971                 if ( events ) {
4972                         delete pdataCur.handle;
4973                         pdataCur.events = {};
4974
4975                         for ( type in events ) {
4976                                 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
4977                                         jQuery.event.add( dest, type, events[ type ][ i ] );
4978                                 }
4979                         }
4980                 }
4981         }
4982
4983         // 2. Copy user data
4984         if ( data_user.hasData( src ) ) {
4985                 udataOld = data_user.access( src );
4986                 udataCur = jQuery.extend( {}, udataOld );
4987
4988                 data_user.set( dest, udataCur );
4989         }
4990 }
4991
4992 function getAll( context, tag ) {
4993         var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
4994                         context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
4995                         [];
4996
4997         return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
4998                 jQuery.merge( [ context ], ret ) :
4999                 ret;
5000 }
5001
5002 // Support: IE >= 9
5003 function fixInput( src, dest ) {
5004         var nodeName = dest.nodeName.toLowerCase();
5005
5006         // Fails to persist the checked state of a cloned checkbox or radio button.
5007         if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5008                 dest.checked = src.checked;
5009
5010         // Fails to return the selected option to the default selected state when cloning options
5011         } else if ( nodeName === "input" || nodeName === "textarea" ) {
5012                 dest.defaultValue = src.defaultValue;
5013         }
5014 }
5015
5016 jQuery.extend({
5017         clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5018                 var i, l, srcElements, destElements,
5019                         clone = elem.cloneNode( true ),
5020                         inPage = jQuery.contains( elem.ownerDocument, elem );
5021
5022                 // Support: IE >= 9
5023                 // Fix Cloning issues
5024                 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
5025                                 !jQuery.isXMLDoc( elem ) ) {
5026
5027                         // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5028                         destElements = getAll( clone );
5029                         srcElements = getAll( elem );
5030
5031                         for ( i = 0, l = srcElements.length; i < l; i++ ) {
5032                                 fixInput( srcElements[ i ], destElements[ i ] );
5033                         }
5034                 }
5035
5036                 // Copy the events from the original to the clone
5037                 if ( dataAndEvents ) {
5038                         if ( deepDataAndEvents ) {
5039                                 srcElements = srcElements || getAll( elem );
5040                                 destElements = destElements || getAll( clone );
5041
5042                                 for ( i = 0, l = srcElements.length; i < l; i++ ) {
5043                                         cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5044                                 }
5045                         } else {
5046                                 cloneCopyEvent( elem, clone );
5047                         }
5048                 }
5049
5050                 // Preserve script evaluation history
5051                 destElements = getAll( clone, "script" );
5052                 if ( destElements.length > 0 ) {
5053                         setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5054                 }
5055
5056                 // Return the cloned set
5057                 return clone;
5058         },
5059
5060         buildFragment: function( elems, context, scripts, selection ) {
5061                 var elem, tmp, tag, wrap, contains, j,
5062                         fragment = context.createDocumentFragment(),
5063                         nodes = [],
5064                         i = 0,
5065                         l = elems.length;
5066
5067                 for ( ; i < l; i++ ) {
5068                         elem = elems[ i ];
5069
5070                         if ( elem || elem === 0 ) {
5071
5072                                 // Add nodes directly
5073                                 if ( jQuery.type( elem ) === "object" ) {
5074                                         // Support: QtWebKit
5075                                         // jQuery.merge because push.apply(_, arraylike) throws
5076                                         jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
5077
5078                                 // Convert non-html into a text node
5079                                 } else if ( !rhtml.test( elem ) ) {
5080                                         nodes.push( context.createTextNode( elem ) );
5081
5082                                 // Convert html into DOM nodes
5083                                 } else {
5084                                         tmp = tmp || fragment.appendChild( context.createElement("div") );
5085
5086                                         // Deserialize a standard representation
5087                                         tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
5088                                         wrap = wrapMap[ tag ] || wrapMap._default;
5089                                         tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
5090
5091                                         // Descend through wrappers to the right content
5092                                         j = wrap[ 0 ];
5093                                         while ( j-- ) {
5094                                                 tmp = tmp.lastChild;
5095                                         }
5096
5097                                         // Support: QtWebKit
5098                                         // jQuery.merge because push.apply(_, arraylike) throws
5099                                         jQuery.merge( nodes, tmp.childNodes );
5100
5101                                         // Remember the top-level container
5102                                         tmp = fragment.firstChild;
5103
5104                                         // Fixes #12346
5105                                         // Support: Webkit, IE
5106                                         tmp.textContent = "";
5107                                 }
5108                         }
5109                 }
5110
5111                 // Remove wrapper from fragment
5112                 fragment.textContent = "";
5113
5114                 i = 0;
5115                 while ( (elem = nodes[ i++ ]) ) {
5116
5117                         // #4087 - If origin and destination elements are the same, and this is
5118                         // that element, do not do anything
5119                         if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
5120                                 continue;
5121                         }
5122
5123                         contains = jQuery.contains( elem.ownerDocument, elem );
5124
5125                         // Append to fragment
5126                         tmp = getAll( fragment.appendChild( elem ), "script" );
5127
5128                         // Preserve script evaluation history
5129                         if ( contains ) {
5130                                 setGlobalEval( tmp );
5131                         }
5132
5133                         // Capture executables
5134                         if ( scripts ) {
5135                                 j = 0;
5136                                 while ( (elem = tmp[ j++ ]) ) {
5137                                         if ( rscriptType.test( elem.type || "" ) ) {
5138                                                 scripts.push( elem );
5139                                         }
5140                                 }
5141                         }
5142                 }
5143
5144                 return fragment;
5145         },
5146
5147         cleanData: function( elems ) {
5148                 var data, elem, type, key,
5149                         special = jQuery.event.special,
5150                         i = 0;
5151
5152                 for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
5153                         if ( jQuery.acceptData( elem ) ) {
5154                                 key = elem[ data_priv.expando ];
5155
5156                                 if ( key && (data = data_priv.cache[ key ]) ) {
5157                                         if ( data.events ) {
5158                                                 for ( type in data.events ) {
5159                                                         if ( special[ type ] ) {
5160                                                                 jQuery.event.remove( elem, type );
5161
5162                                                         // This is a shortcut to avoid jQuery.event.remove's overhead
5163                                                         } else {
5164                                                                 jQuery.removeEvent( elem, type, data.handle );
5165                                                         }
5166                                                 }
5167                                         }
5168                                         if ( data_priv.cache[ key ] ) {
5169                                                 // Discard any remaining `private` data
5170                                                 delete data_priv.cache[ key ];
5171                                         }
5172                                 }
5173                         }
5174                         // Discard any remaining `user` data
5175                         delete data_user.cache[ elem[ data_user.expando ] ];
5176                 }
5177         }
5178 });
5179
5180 jQuery.fn.extend({
5181         text: function( value ) {
5182                 return access( this, function( value ) {
5183                         return value === undefined ?
5184                                 jQuery.text( this ) :
5185                                 this.empty().each(function() {
5186                                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5187                                                 this.textContent = value;
5188                                         }
5189                                 });
5190                 }, null, value, arguments.length );
5191         },
5192
5193         append: function() {
5194                 return this.domManip( arguments, function( elem ) {
5195                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5196                                 var target = manipulationTarget( this, elem );
5197                                 target.appendChild( elem );
5198                         }
5199                 });
5200         },
5201
5202         prepend: function() {
5203                 return this.domManip( arguments, function( elem ) {
5204                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5205                                 var target = manipulationTarget( this, elem );
5206                                 target.insertBefore( elem, target.firstChild );
5207                         }
5208                 });
5209         },
5210
5211         before: function() {
5212                 return this.domManip( arguments, function( elem ) {
5213                         if ( this.parentNode ) {
5214                                 this.parentNode.insertBefore( elem, this );
5215                         }
5216                 });
5217         },
5218
5219         after: function() {
5220                 return this.domManip( arguments, function( elem ) {
5221                         if ( this.parentNode ) {
5222                                 this.parentNode.insertBefore( elem, this.nextSibling );
5223                         }
5224                 });
5225         },
5226
5227         remove: function( selector, keepData /* Internal Use Only */ ) {
5228                 var elem,
5229                         elems = selector ? jQuery.filter( selector, this ) : this,
5230                         i = 0;
5231
5232                 for ( ; (elem = elems[i]) != null; i++ ) {
5233                         if ( !keepData && elem.nodeType === 1 ) {
5234                                 jQuery.cleanData( getAll( elem ) );
5235                         }
5236
5237                         if ( elem.parentNode ) {
5238                                 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5239                                         setGlobalEval( getAll( elem, "script" ) );
5240                                 }
5241                                 elem.parentNode.removeChild( elem );
5242                         }
5243                 }
5244
5245                 return this;
5246         },
5247
5248         empty: function() {
5249                 var elem,
5250                         i = 0;
5251
5252                 for ( ; (elem = this[i]) != null; i++ ) {
5253                         if ( elem.nodeType === 1 ) {
5254
5255                                 // Prevent memory leaks
5256                                 jQuery.cleanData( getAll( elem, false ) );
5257
5258                                 // Remove any remaining nodes
5259                                 elem.textContent = "";
5260                         }
5261                 }
5262
5263                 return this;
5264         },
5265
5266         clone: function( dataAndEvents, deepDataAndEvents ) {
5267                 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5268                 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5269
5270                 return this.map(function() {
5271                         return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5272                 });
5273         },
5274
5275         html: function( value ) {
5276                 return access( this, function( value ) {
5277                         var elem = this[ 0 ] || {},
5278                                 i = 0,
5279                                 l = this.length;
5280
5281                         if ( value === undefined && elem.nodeType === 1 ) {
5282                                 return elem.innerHTML;
5283                         }
5284
5285                         // See if we can take a shortcut and just use innerHTML
5286                         if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5287                                 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5288
5289                                 value = value.replace( rxhtmlTag, "<$1></$2>" );
5290
5291                                 try {
5292                                         for ( ; i < l; i++ ) {
5293                                                 elem = this[ i ] || {};
5294
5295                                                 // Remove element nodes and prevent memory leaks
5296                                                 if ( elem.nodeType === 1 ) {
5297                                                         jQuery.cleanData( getAll( elem, false ) );
5298                                                         elem.innerHTML = value;
5299                                                 }
5300                                         }
5301
5302                                         elem = 0;
5303
5304                                 // If using innerHTML throws an exception, use the fallback method
5305                                 } catch( e ) {}
5306                         }
5307
5308                         if ( elem ) {
5309                                 this.empty().append( value );
5310                         }
5311                 }, null, value, arguments.length );
5312         },
5313
5314         replaceWith: function() {
5315                 var arg = arguments[ 0 ];
5316
5317                 // Make the changes, replacing each context element with the new content
5318                 this.domManip( arguments, function( elem ) {
5319                         arg = this.parentNode;
5320
5321                         jQuery.cleanData( getAll( this ) );
5322
5323                         if ( arg ) {
5324                                 arg.replaceChild( elem, this );
5325                         }
5326                 });
5327
5328                 // Force removal if there was no new content (e.g., from empty arguments)
5329                 return arg && (arg.length || arg.nodeType) ? this : this.remove();
5330         },
5331
5332         detach: function( selector ) {
5333                 return this.remove( selector, true );
5334         },
5335
5336         domManip: function( args, callback ) {
5337
5338                 // Flatten any nested arrays
5339                 args = concat.apply( [], args );
5340
5341                 var fragment, first, scripts, hasScripts, node, doc,
5342                         i = 0,
5343                         l = this.length,
5344                         set = this,
5345                         iNoClone = l - 1,
5346                         value = args[ 0 ],
5347                         isFunction = jQuery.isFunction( value );
5348
5349                 // We can't cloneNode fragments that contain checked, in WebKit
5350                 if ( isFunction ||
5351                                 ( l > 1 && typeof value === "string" &&
5352                                         !support.checkClone && rchecked.test( value ) ) ) {
5353                         return this.each(function( index ) {
5354                                 var self = set.eq( index );
5355                                 if ( isFunction ) {
5356                                         args[ 0 ] = value.call( this, index, self.html() );
5357                                 }
5358                                 self.domManip( args, callback );
5359                         });
5360                 }
5361
5362                 if ( l ) {
5363                         fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
5364                         first = fragment.firstChild;
5365
5366                         if ( fragment.childNodes.length === 1 ) {
5367                                 fragment = first;
5368                         }
5369
5370                         if ( first ) {
5371                                 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5372                                 hasScripts = scripts.length;
5373
5374                                 // Use the original fragment for the last item instead of the first because it can end up
5375                                 // being emptied incorrectly in certain situations (#8070).
5376                                 for ( ; i < l; i++ ) {
5377                                         node = fragment;
5378
5379                                         if ( i !== iNoClone ) {
5380                                                 node = jQuery.clone( node, true, true );
5381
5382                                                 // Keep references to cloned scripts for later restoration
5383                                                 if ( hasScripts ) {
5384                                                         // Support: QtWebKit
5385                                                         // jQuery.merge because push.apply(_, arraylike) throws
5386                                                         jQuery.merge( scripts, getAll( node, "script" ) );
5387                                                 }
5388                                         }
5389
5390                                         callback.call( this[ i ], node, i );
5391                                 }
5392
5393                                 if ( hasScripts ) {
5394                                         doc = scripts[ scripts.length - 1 ].ownerDocument;
5395
5396                                         // Reenable scripts
5397                                         jQuery.map( scripts, restoreScript );
5398
5399                                         // Evaluate executable scripts on first document insertion
5400                                         for ( i = 0; i < hasScripts; i++ ) {
5401                                                 node = scripts[ i ];
5402                                                 if ( rscriptType.test( node.type || "" ) &&
5403                                                         !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
5404
5405                                                         if ( node.src ) {
5406                                                                 // Optional AJAX dependency, but won't run scripts if not present
5407                                                                 if ( jQuery._evalUrl ) {
5408                                                                         jQuery._evalUrl( node.src );
5409                                                                 }
5410                                                         } else {
5411                                                                 jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
5412                                                         }
5413                                                 }
5414                                         }
5415                                 }
5416                         }
5417                 }
5418
5419                 return this;
5420         }
5421 });
5422
5423 jQuery.each({
5424         appendTo: "append",
5425         prependTo: "prepend",
5426         insertBefore: "before",
5427         insertAfter: "after",
5428         replaceAll: "replaceWith"
5429 }, function( name, original ) {
5430         jQuery.fn[ name ] = function( selector ) {
5431                 var elems,
5432                         ret = [],
5433                         insert = jQuery( selector ),
5434                         last = insert.length - 1,
5435                         i = 0;
5436
5437                 for ( ; i <= last; i++ ) {
5438                         elems = i === last ? this : this.clone( true );
5439                         jQuery( insert[ i ] )[ original ]( elems );
5440
5441                         // Support: QtWebKit
5442                         // .get() because push.apply(_, arraylike) throws
5443                         push.apply( ret, elems.get() );
5444                 }
5445
5446                 return this.pushStack( ret );
5447         };
5448 });
5449
5450
5451 var iframe,
5452         elemdisplay = {};
5453
5454 /**
5455  * Retrieve the actual display of a element
5456  * @param {String} name nodeName of the element
5457  * @param {Object} doc Document object
5458  */
5459 // Called only from within defaultDisplay
5460 function actualDisplay( name, doc ) {
5461         var style,
5462                 elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
5463
5464                 // getDefaultComputedStyle might be reliably used only on attached element
5465                 display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
5466
5467                         // Use of this method is a temporary fix (more like optmization) until something better comes along,
5468                         // since it was removed from specification and supported only in FF
5469                         style.display : jQuery.css( elem[ 0 ], "display" );
5470
5471         // We don't have any data stored on the element,
5472         // so use "detach" method as fast way to get rid of the element
5473         elem.detach();
5474
5475         return display;
5476 }
5477
5478 /**
5479  * Try to determine the default display value of an element
5480  * @param {String} nodeName
5481  */
5482 function defaultDisplay( nodeName ) {
5483         var doc = document,
5484                 display = elemdisplay[ nodeName ];
5485
5486         if ( !display ) {
5487                 display = actualDisplay( nodeName, doc );
5488
5489                 // If the simple way fails, read from inside an iframe
5490                 if ( display === "none" || !display ) {
5491
5492                         // Use the already-created iframe if possible
5493                         iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
5494
5495                         // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
5496                         doc = iframe[ 0 ].contentDocument;
5497
5498                         // Support: IE
5499                         doc.write();
5500                         doc.close();
5501
5502                         display = actualDisplay( nodeName, doc );
5503                         iframe.detach();
5504                 }
5505
5506                 // Store the correct default display
5507                 elemdisplay[ nodeName ] = display;
5508         }
5509
5510         return display;
5511 }
5512 var rmargin = (/^margin/);
5513
5514 var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
5515
5516 var getStyles = function( elem ) {
5517                 return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
5518         };
5519
5520
5521
5522 function curCSS( elem, name, computed ) {
5523         var width, minWidth, maxWidth, ret,
5524                 style = elem.style;
5525
5526         computed = computed || getStyles( elem );
5527
5528         // Support: IE9
5529         // getPropertyValue is only needed for .css('filter') in IE9, see #12537
5530         if ( computed ) {
5531                 ret = computed.getPropertyValue( name ) || computed[ name ];
5532         }
5533
5534         if ( computed ) {
5535
5536                 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
5537                         ret = jQuery.style( elem, name );
5538                 }
5539
5540                 // Support: iOS < 6
5541                 // A tribute to the "awesome hack by Dean Edwards"
5542                 // iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
5543                 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
5544                 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
5545
5546                         // Remember the original values
5547                         width = style.width;
5548                         minWidth = style.minWidth;
5549                         maxWidth = style.maxWidth;
5550
5551                         // Put in the new values to get a computed value out
5552                         style.minWidth = style.maxWidth = style.width = ret;
5553                         ret = computed.width;
5554
5555                         // Revert the changed values
5556                         style.width = width;
5557                         style.minWidth = minWidth;
5558                         style.maxWidth = maxWidth;
5559                 }
5560         }
5561
5562         return ret !== undefined ?
5563                 // Support: IE
5564                 // IE returns zIndex value as an integer.
5565                 ret + "" :
5566                 ret;
5567 }
5568
5569
5570 function addGetHookIf( conditionFn, hookFn ) {
5571         // Define the hook, we'll check on the first run if it's really needed.
5572         return {
5573                 get: function() {
5574                         if ( conditionFn() ) {
5575                                 // Hook not needed (or it's not possible to use it due to missing dependency),
5576                                 // remove it.
5577                                 // Since there are no other hooks for marginRight, remove the whole object.
5578                                 delete this.get;
5579                                 return;
5580                         }
5581
5582                         // Hook needed; redefine it so that the support test is not executed again.
5583
5584                         return (this.get = hookFn).apply( this, arguments );
5585                 }
5586         };
5587 }
5588
5589
5590 (function() {
5591         var pixelPositionVal, boxSizingReliableVal,
5592                 docElem = document.documentElement,
5593                 container = document.createElement( "div" ),
5594                 div = document.createElement( "div" );
5595
5596         if ( !div.style ) {
5597                 return;
5598         }
5599
5600         div.style.backgroundClip = "content-box";
5601         div.cloneNode( true ).style.backgroundClip = "";
5602         support.clearCloneStyle = div.style.backgroundClip === "content-box";
5603
5604         container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
5605                 "position:absolute";
5606         container.appendChild( div );
5607
5608         // Executing both pixelPosition & boxSizingReliable tests require only one layout
5609         // so they're executed at the same time to save the second computation.
5610         function computePixelPositionAndBoxSizingReliable() {
5611                 div.style.cssText =
5612                         // Support: Firefox<29, Android 2.3
5613                         // Vendor-prefix box-sizing
5614                         "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
5615                         "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
5616                         "border:1px;padding:1px;width:4px;position:absolute";
5617                 div.innerHTML = "";
5618                 docElem.appendChild( container );
5619
5620                 var divStyle = window.getComputedStyle( div, null );
5621                 pixelPositionVal = divStyle.top !== "1%";
5622                 boxSizingReliableVal = divStyle.width === "4px";
5623
5624                 docElem.removeChild( container );
5625         }
5626
5627         // Support: node.js jsdom
5628         // Don't assume that getComputedStyle is a property of the global object
5629         if ( window.getComputedStyle ) {
5630                 jQuery.extend( support, {
5631                         pixelPosition: function() {
5632                                 // This test is executed only once but we still do memoizing
5633                                 // since we can use the boxSizingReliable pre-computing.
5634                                 // No need to check if the test was already performed, though.
5635                                 computePixelPositionAndBoxSizingReliable();
5636                                 return pixelPositionVal;
5637                         },
5638                         boxSizingReliable: function() {
5639                                 if ( boxSizingReliableVal == null ) {
5640                                         computePixelPositionAndBoxSizingReliable();
5641                                 }
5642                                 return boxSizingReliableVal;
5643                         },
5644                         reliableMarginRight: function() {
5645                                 // Support: Android 2.3
5646                                 // Check if div with explicit width and no margin-right incorrectly
5647                                 // gets computed margin-right based on width of container. (#3333)
5648                                 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
5649                                 // This support function is only executed once so no memoizing is needed.
5650                                 var ret,
5651                                         marginDiv = div.appendChild( document.createElement( "div" ) );
5652
5653                                 // Reset CSS: box-sizing; display; margin; border; padding
5654                                 marginDiv.style.cssText = div.style.cssText =
5655                                         // Support: Firefox<29, Android 2.3
5656                                         // Vendor-prefix box-sizing
5657                                         "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
5658                                         "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
5659                                 marginDiv.style.marginRight = marginDiv.style.width = "0";
5660                                 div.style.width = "1px";
5661                                 docElem.appendChild( container );
5662
5663                                 ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
5664
5665                                 docElem.removeChild( container );
5666
5667                                 return ret;
5668                         }
5669                 });
5670         }
5671 })();
5672
5673
5674 // A method for quickly swapping in/out CSS properties to get correct calculations.
5675 jQuery.swap = function( elem, options, callback, args ) {
5676         var ret, name,
5677                 old = {};
5678
5679         // Remember the old values, and insert the new ones
5680         for ( name in options ) {
5681                 old[ name ] = elem.style[ name ];
5682                 elem.style[ name ] = options[ name ];
5683         }
5684
5685         ret = callback.apply( elem, args || [] );
5686
5687         // Revert the old values
5688         for ( name in options ) {
5689                 elem.style[ name ] = old[ name ];
5690         }
5691
5692         return ret;
5693 };
5694
5695
5696 var
5697         // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
5698         // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
5699         rdisplayswap = /^(none|table(?!-c[ea]).+)/,
5700         rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
5701         rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
5702
5703         cssShow = { position: "absolute", visibility: "hidden", display: "block" },
5704         cssNormalTransform = {
5705                 letterSpacing: "0",
5706                 fontWeight: "400"
5707         },
5708
5709         cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
5710
5711 // return a css property mapped to a potentially vendor prefixed property
5712 function vendorPropName( style, name ) {
5713
5714         // shortcut for names that are not vendor prefixed
5715         if ( name in style ) {
5716                 return name;
5717         }
5718
5719         // check for vendor prefixed names
5720         var capName = name[0].toUpperCase() + name.slice(1),
5721                 origName = name,
5722                 i = cssPrefixes.length;
5723
5724         while ( i-- ) {
5725                 name = cssPrefixes[ i ] + capName;
5726                 if ( name in style ) {
5727                         return name;
5728                 }
5729         }
5730
5731         return origName;
5732 }
5733
5734 function setPositiveNumber( elem, value, subtract ) {
5735         var matches = rnumsplit.exec( value );
5736         return matches ?
5737                 // Guard against undefined "subtract", e.g., when used as in cssHooks
5738                 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
5739                 value;
5740 }
5741
5742 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
5743         var i = extra === ( isBorderBox ? "border" : "content" ) ?
5744                 // If we already have the right measurement, avoid augmentation
5745                 4 :
5746                 // Otherwise initialize for horizontal or vertical properties
5747                 name === "width" ? 1 : 0,
5748
5749                 val = 0;
5750
5751         for ( ; i < 4; i += 2 ) {
5752                 // both box models exclude margin, so add it if we want it
5753                 if ( extra === "margin" ) {
5754                         val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
5755                 }
5756
5757                 if ( isBorderBox ) {
5758                         // border-box includes padding, so remove it if we want content
5759                         if ( extra === "content" ) {
5760                                 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5761                         }
5762
5763                         // at this point, extra isn't border nor margin, so remove border
5764                         if ( extra !== "margin" ) {
5765                                 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5766                         }
5767                 } else {
5768                         // at this point, extra isn't content, so add padding
5769                         val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5770
5771                         // at this point, extra isn't content nor padding, so add border
5772                         if ( extra !== "padding" ) {
5773                                 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5774                         }
5775                 }
5776         }
5777
5778         return val;
5779 }
5780
5781 function getWidthOrHeight( elem, name, extra ) {
5782
5783         // Start with offset property, which is equivalent to the border-box value
5784         var valueIsBorderBox = true,
5785                 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
5786                 styles = getStyles( elem ),
5787                 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
5788
5789         // some non-html elements return undefined for offsetWidth, so check for null/undefined
5790         // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
5791         // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
5792         if ( val <= 0 || val == null ) {
5793                 // Fall back to computed then uncomputed css if necessary
5794                 val = curCSS( elem, name, styles );
5795                 if ( val < 0 || val == null ) {
5796                         val = elem.style[ name ];
5797                 }
5798
5799                 // Computed unit is not pixels. Stop here and return.
5800                 if ( rnumnonpx.test(val) ) {
5801                         return val;
5802                 }
5803
5804                 // we need the check for style in case a browser which returns unreliable values
5805                 // for getComputedStyle silently falls back to the reliable elem.style
5806                 valueIsBorderBox = isBorderBox &&
5807                         ( support.boxSizingReliable() || val === elem.style[ name ] );
5808
5809                 // Normalize "", auto, and prepare for extra
5810                 val = parseFloat( val ) || 0;
5811         }
5812
5813         // use the active box-sizing model to add/subtract irrelevant styles
5814         return ( val +
5815                 augmentWidthOrHeight(
5816                         elem,
5817                         name,
5818                         extra || ( isBorderBox ? "border" : "content" ),
5819                         valueIsBorderBox,
5820                         styles
5821                 )
5822         ) + "px";
5823 }
5824
5825 function showHide( elements, show ) {
5826         var display, elem, hidden,
5827                 values = [],
5828                 index = 0,
5829                 length = elements.length;
5830
5831         for ( ; index < length; index++ ) {
5832                 elem = elements[ index ];
5833                 if ( !elem.style ) {
5834                         continue;
5835                 }
5836
5837                 values[ index ] = data_priv.get( elem, "olddisplay" );
5838                 display = elem.style.display;
5839                 if ( show ) {
5840                         // Reset the inline display of this element to learn if it is
5841                         // being hidden by cascaded rules or not
5842                         if ( !values[ index ] && display === "none" ) {
5843                                 elem.style.display = "";
5844                         }
5845
5846                         // Set elements which have been overridden with display: none
5847                         // in a stylesheet to whatever the default browser style is
5848                         // for such an element
5849                         if ( elem.style.display === "" && isHidden( elem ) ) {
5850                                 values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
5851                         }
5852                 } else {
5853                         hidden = isHidden( elem );
5854
5855                         if ( display !== "none" || !hidden ) {
5856                                 data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
5857                         }
5858                 }
5859         }
5860
5861         // Set the display of most of the elements in a second loop
5862         // to avoid the constant reflow
5863         for ( index = 0; index < length; index++ ) {
5864                 elem = elements[ index ];
5865                 if ( !elem.style ) {
5866                         continue;
5867                 }
5868                 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
5869                         elem.style.display = show ? values[ index ] || "" : "none";
5870                 }
5871         }
5872
5873         return elements;
5874 }
5875
5876 jQuery.extend({
5877         // Add in style property hooks for overriding the default
5878         // behavior of getting and setting a style property
5879         cssHooks: {
5880                 opacity: {
5881                         get: function( elem, computed ) {
5882                                 if ( computed ) {
5883                                         // We should always get a number back from opacity
5884                                         var ret = curCSS( elem, "opacity" );
5885                                         return ret === "" ? "1" : ret;
5886                                 }
5887                         }
5888                 }
5889         },
5890
5891         // Don't automatically add "px" to these possibly-unitless properties
5892         cssNumber: {
5893                 "columnCount": true,
5894                 "fillOpacity": true,
5895                 "flexGrow": true,
5896                 "flexShrink": true,
5897                 "fontWeight": true,
5898                 "lineHeight": true,
5899                 "opacity": true,
5900                 "order": true,
5901                 "orphans": true,
5902                 "widows": true,
5903                 "zIndex": true,
5904                 "zoom": true
5905         },
5906
5907         // Add in properties whose names you wish to fix before
5908         // setting or getting the value
5909         cssProps: {
5910                 // normalize float css property
5911                 "float": "cssFloat"
5912         },
5913
5914         // Get and set the style property on a DOM Node
5915         style: function( elem, name, value, extra ) {
5916                 // Don't set styles on text and comment nodes
5917                 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
5918                         return;
5919                 }
5920
5921                 // Make sure that we're working with the right name
5922                 var ret, type, hooks,
5923                         origName = jQuery.camelCase( name ),
5924                         style = elem.style;
5925
5926                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
5927
5928                 // gets hook for the prefixed version
5929                 // followed by the unprefixed version
5930                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
5931
5932                 // Check if we're setting a value
5933                 if ( value !== undefined ) {
5934                         type = typeof value;
5935
5936                         // convert relative number strings (+= or -=) to relative numbers. #7345
5937                         if ( type === "string" && (ret = rrelNum.exec( value )) ) {
5938                                 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
5939                                 // Fixes bug #9237
5940                                 type = "number";
5941                         }
5942
5943                         // Make sure that null and NaN values aren't set. See: #7116
5944                         if ( value == null || value !== value ) {
5945                                 return;
5946                         }
5947
5948                         // If a number was passed in, add 'px' to the (except for certain CSS properties)
5949                         if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
5950                                 value += "px";
5951                         }
5952
5953                         // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
5954                         // but it would mean to define eight (for every problematic property) identical functions
5955                         if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
5956                                 style[ name ] = "inherit";
5957                         }
5958
5959                         // If a hook was provided, use that value, otherwise just set the specified value
5960                         if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
5961                                 style[ name ] = value;
5962                         }
5963
5964                 } else {
5965                         // If a hook was provided get the non-computed value from there
5966                         if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
5967                                 return ret;
5968                         }
5969
5970                         // Otherwise just get the value from the style object
5971                         return style[ name ];
5972                 }
5973         },
5974
5975         css: function( elem, name, extra, styles ) {
5976                 var val, num, hooks,
5977                         origName = jQuery.camelCase( name );
5978
5979                 // Make sure that we're working with the right name
5980                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
5981
5982                 // gets hook for the prefixed version
5983                 // followed by the unprefixed version
5984                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
5985
5986                 // If a hook was provided get the computed value from there
5987                 if ( hooks && "get" in hooks ) {
5988                         val = hooks.get( elem, true, extra );
5989                 }
5990
5991                 // Otherwise, if a way to get the computed value exists, use that
5992                 if ( val === undefined ) {
5993                         val = curCSS( elem, name, styles );
5994                 }
5995
5996                 //convert "normal" to computed value
5997                 if ( val === "normal" && name in cssNormalTransform ) {
5998                         val = cssNormalTransform[ name ];
5999                 }
6000
6001                 // Return, converting to number if forced or a qualifier was provided and val looks numeric
6002                 if ( extra === "" || extra ) {
6003                         num = parseFloat( val );
6004                         return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6005                 }
6006                 return val;
6007         }
6008 });
6009
6010 jQuery.each([ "height", "width" ], function( i, name ) {
6011         jQuery.cssHooks[ name ] = {
6012                 get: function( elem, computed, extra ) {
6013                         if ( computed ) {
6014                                 // certain elements can have dimension info if we invisibly show them
6015                                 // however, it must have a current display style that would benefit from this
6016                                 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
6017                                         jQuery.swap( elem, cssShow, function() {
6018                                                 return getWidthOrHeight( elem, name, extra );
6019                                         }) :
6020                                         getWidthOrHeight( elem, name, extra );
6021                         }
6022                 },
6023
6024                 set: function( elem, value, extra ) {
6025                         var styles = extra && getStyles( elem );
6026                         return setPositiveNumber( elem, value, extra ?
6027                                 augmentWidthOrHeight(
6028                                         elem,
6029                                         name,
6030                                         extra,
6031                                         jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6032                                         styles
6033                                 ) : 0
6034                         );
6035                 }
6036         };
6037 });
6038
6039 // Support: Android 2.3
6040 jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
6041         function( elem, computed ) {
6042                 if ( computed ) {
6043                         // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
6044                         // Work around by temporarily setting element display to inline-block
6045                         return jQuery.swap( elem, { "display": "inline-block" },
6046                                 curCSS, [ elem, "marginRight" ] );
6047                 }
6048         }
6049 );
6050
6051 // These hooks are used by animate to expand properties
6052 jQuery.each({
6053         margin: "",
6054         padding: "",
6055         border: "Width"
6056 }, function( prefix, suffix ) {
6057         jQuery.cssHooks[ prefix + suffix ] = {
6058                 expand: function( value ) {
6059                         var i = 0,
6060                                 expanded = {},
6061
6062                                 // assumes a single number if not a string
6063                                 parts = typeof value === "string" ? value.split(" ") : [ value ];
6064
6065                         for ( ; i < 4; i++ ) {
6066                                 expanded[ prefix + cssExpand[ i ] + suffix ] =
6067                                         parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6068                         }
6069
6070                         return expanded;
6071                 }
6072         };
6073
6074         if ( !rmargin.test( prefix ) ) {
6075                 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6076         }
6077 });
6078
6079 jQuery.fn.extend({
6080         css: function( name, value ) {
6081                 return access( this, function( elem, name, value ) {
6082                         var styles, len,
6083                                 map = {},
6084                                 i = 0;
6085
6086                         if ( jQuery.isArray( name ) ) {
6087                                 styles = getStyles( elem );
6088                                 len = name.length;
6089
6090                                 for ( ; i < len; i++ ) {
6091                                         map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6092                                 }
6093
6094                                 return map;
6095                         }
6096
6097                         return value !== undefined ?
6098                                 jQuery.style( elem, name, value ) :
6099                                 jQuery.css( elem, name );
6100                 }, name, value, arguments.length > 1 );
6101         },
6102         show: function() {
6103                 return showHide( this, true );
6104         },
6105         hide: function() {
6106                 return showHide( this );
6107         },
6108         toggle: function( state ) {
6109                 if ( typeof state === "boolean" ) {
6110                         return state ? this.show() : this.hide();
6111                 }
6112
6113                 return this.each(function() {
6114                         if ( isHidden( this ) ) {
6115                                 jQuery( this ).show();
6116                         } else {
6117                                 jQuery( this ).hide();
6118                         }
6119                 });
6120         }
6121 });
6122
6123
6124 function Tween( elem, options, prop, end, easing ) {
6125         return new Tween.prototype.init( elem, options, prop, end, easing );
6126 }
6127 jQuery.Tween = Tween;
6128
6129 Tween.prototype = {
6130         constructor: Tween,
6131         init: function( elem, options, prop, end, easing, unit ) {
6132                 this.elem = elem;
6133                 this.prop = prop;
6134                 this.easing = easing || "swing";
6135                 this.options = options;
6136                 this.start = this.now = this.cur();
6137                 this.end = end;
6138                 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
6139         },
6140         cur: function() {
6141                 var hooks = Tween.propHooks[ this.prop ];
6142
6143                 return hooks && hooks.get ?
6144                         hooks.get( this ) :
6145                         Tween.propHooks._default.get( this );
6146         },
6147         run: function( percent ) {
6148                 var eased,
6149                         hooks = Tween.propHooks[ this.prop ];
6150
6151                 if ( this.options.duration ) {
6152                         this.pos = eased = jQuery.easing[ this.easing ](
6153                                 percent, this.options.duration * percent, 0, 1, this.options.duration
6154                         );
6155                 } else {
6156                         this.pos = eased = percent;
6157                 }
6158                 this.now = ( this.end - this.start ) * eased + this.start;
6159
6160                 if ( this.options.step ) {
6161                         this.options.step.call( this.elem, this.now, this );
6162                 }
6163
6164                 if ( hooks && hooks.set ) {
6165                         hooks.set( this );
6166                 } else {
6167                         Tween.propHooks._default.set( this );
6168                 }
6169                 return this;
6170         }
6171 };
6172
6173 Tween.prototype.init.prototype = Tween.prototype;
6174
6175 Tween.propHooks = {
6176         _default: {
6177                 get: function( tween ) {
6178                         var result;
6179
6180                         if ( tween.elem[ tween.prop ] != null &&
6181                                 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
6182                                 return tween.elem[ tween.prop ];
6183                         }
6184
6185                         // passing an empty string as a 3rd parameter to .css will automatically
6186                         // attempt a parseFloat and fallback to a string if the parse fails
6187                         // so, simple values such as "10px" are parsed to Float.
6188                         // complex values such as "rotate(1rad)" are returned as is.
6189                         result = jQuery.css( tween.elem, tween.prop, "" );
6190                         // Empty strings, null, undefined and "auto" are converted to 0.
6191                         return !result || result === "auto" ? 0 : result;
6192                 },
6193                 set: function( tween ) {
6194                         // use step hook for back compat - use cssHook if its there - use .style if its
6195                         // available and use plain properties where available
6196                         if ( jQuery.fx.step[ tween.prop ] ) {
6197                                 jQuery.fx.step[ tween.prop ]( tween );
6198                         } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
6199                                 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
6200                         } else {
6201                                 tween.elem[ tween.prop ] = tween.now;
6202                         }
6203                 }
6204         }
6205 };
6206
6207 // Support: IE9
6208 // Panic based approach to setting things on disconnected nodes
6209
6210 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
6211         set: function( tween ) {
6212                 if ( tween.elem.nodeType && tween.elem.parentNode ) {
6213                         tween.elem[ tween.prop ] = tween.now;
6214                 }
6215         }
6216 };
6217
6218 jQuery.easing = {
6219         linear: function( p ) {
6220                 return p;
6221         },
6222         swing: function( p ) {
6223                 return 0.5 - Math.cos( p * Math.PI ) / 2;
6224         }
6225 };
6226
6227 jQuery.fx = Tween.prototype.init;
6228
6229 // Back Compat <1.8 extension point
6230 jQuery.fx.step = {};
6231
6232
6233
6234
6235 var
6236         fxNow, timerId,
6237         rfxtypes = /^(?:toggle|show|hide)$/,
6238         rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
6239         rrun = /queueHooks$/,
6240         animationPrefilters = [ defaultPrefilter ],
6241         tweeners = {
6242                 "*": [ function( prop, value ) {
6243                         var tween = this.createTween( prop, value ),
6244                                 target = tween.cur(),
6245                                 parts = rfxnum.exec( value ),
6246                                 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
6247
6248                                 // Starting value computation is required for potential unit mismatches
6249                                 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
6250                                         rfxnum.exec( jQuery.css( tween.elem, prop ) ),
6251                                 scale = 1,
6252                                 maxIterations = 20;
6253
6254                         if ( start && start[ 3 ] !== unit ) {
6255                                 // Trust units reported by jQuery.css
6256                                 unit = unit || start[ 3 ];
6257
6258                                 // Make sure we update the tween properties later on
6259                                 parts = parts || [];
6260
6261                                 // Iteratively approximate from a nonzero starting point
6262                                 start = +target || 1;
6263
6264                                 do {
6265                                         // If previous iteration zeroed out, double until we get *something*
6266                                         // Use a string for doubling factor so we don't accidentally see scale as unchanged below
6267                                         scale = scale || ".5";
6268
6269                                         // Adjust and apply
6270                                         start = start / scale;
6271                                         jQuery.style( tween.elem, prop, start + unit );
6272
6273                                 // Update scale, tolerating zero or NaN from tween.cur()
6274                                 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
6275                                 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
6276                         }
6277
6278                         // Update tween properties
6279                         if ( parts ) {
6280                                 start = tween.start = +start || +target || 0;
6281                                 tween.unit = unit;
6282                                 // If a +=/-= token was provided, we're doing a relative animation
6283                                 tween.end = parts[ 1 ] ?
6284                                         start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
6285                                         +parts[ 2 ];
6286                         }
6287
6288                         return tween;
6289                 } ]
6290         };
6291
6292 // Animations created synchronously will run synchronously
6293 function createFxNow() {
6294         setTimeout(function() {
6295                 fxNow = undefined;
6296         });
6297         return ( fxNow = jQuery.now() );
6298 }
6299
6300 // Generate parameters to create a standard animation
6301 function genFx( type, includeWidth ) {
6302         var which,
6303                 i = 0,
6304                 attrs = { height: type };
6305
6306         // if we include width, step value is 1 to do all cssExpand values,
6307         // if we don't include width, step value is 2 to skip over Left and Right
6308         includeWidth = includeWidth ? 1 : 0;
6309         for ( ; i < 4 ; i += 2 - includeWidth ) {
6310                 which = cssExpand[ i ];
6311                 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
6312         }
6313
6314         if ( includeWidth ) {
6315                 attrs.opacity = attrs.width = type;
6316         }
6317
6318         return attrs;
6319 }
6320
6321 function createTween( value, prop, animation ) {
6322         var tween,
6323                 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
6324                 index = 0,
6325                 length = collection.length;
6326         for ( ; index < length; index++ ) {
6327                 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
6328
6329                         // we're done with this property
6330                         return tween;
6331                 }
6332         }
6333 }
6334
6335 function defaultPrefilter( elem, props, opts ) {
6336         /* jshint validthis: true */
6337         var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
6338                 anim = this,
6339                 orig = {},
6340                 style = elem.style,
6341                 hidden = elem.nodeType && isHidden( elem ),
6342                 dataShow = data_priv.get( elem, "fxshow" );
6343
6344         // handle queue: false promises
6345         if ( !opts.queue ) {
6346                 hooks = jQuery._queueHooks( elem, "fx" );
6347                 if ( hooks.unqueued == null ) {
6348                         hooks.unqueued = 0;
6349                         oldfire = hooks.empty.fire;
6350                         hooks.empty.fire = function() {
6351                                 if ( !hooks.unqueued ) {
6352                                         oldfire();
6353                                 }
6354                         };
6355                 }
6356                 hooks.unqueued++;
6357
6358                 anim.always(function() {
6359                         // doing this makes sure that the complete handler will be called
6360                         // before this completes
6361                         anim.always(function() {
6362                                 hooks.unqueued--;
6363                                 if ( !jQuery.queue( elem, "fx" ).length ) {
6364                                         hooks.empty.fire();
6365                                 }
6366                         });
6367                 });
6368         }
6369
6370         // height/width overflow pass
6371         if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
6372                 // Make sure that nothing sneaks out
6373                 // Record all 3 overflow attributes because IE9-10 do not
6374                 // change the overflow attribute when overflowX and
6375                 // overflowY are set to the same value
6376                 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
6377
6378                 // Set display property to inline-block for height/width
6379                 // animations on inline elements that are having width/height animated
6380                 display = jQuery.css( elem, "display" );
6381
6382                 // Test default display if display is currently "none"
6383                 checkDisplay = display === "none" ?
6384                         data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
6385
6386                 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
6387                         style.display = "inline-block";
6388                 }
6389         }
6390
6391         if ( opts.overflow ) {
6392                 style.overflow = "hidden";
6393                 anim.always(function() {
6394                         style.overflow = opts.overflow[ 0 ];
6395                         style.overflowX = opts.overflow[ 1 ];
6396                         style.overflowY = opts.overflow[ 2 ];
6397                 });
6398         }
6399
6400         // show/hide pass
6401         for ( prop in props ) {
6402                 value = props[ prop ];
6403                 if ( rfxtypes.exec( value ) ) {
6404                         delete props[ prop ];
6405                         toggle = toggle || value === "toggle";
6406                         if ( value === ( hidden ? "hide" : "show" ) ) {
6407
6408                                 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
6409                                 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
6410                                         hidden = true;
6411                                 } else {
6412                                         continue;
6413                                 }
6414                         }
6415                         orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
6416
6417                 // Any non-fx value stops us from restoring the original display value
6418                 } else {
6419                         display = undefined;
6420                 }
6421         }
6422
6423         if ( !jQuery.isEmptyObject( orig ) ) {
6424                 if ( dataShow ) {
6425                         if ( "hidden" in dataShow ) {
6426                                 hidden = dataShow.hidden;
6427                         }
6428                 } else {
6429                         dataShow = data_priv.access( elem, "fxshow", {} );
6430                 }
6431
6432                 // store state if its toggle - enables .stop().toggle() to "reverse"
6433                 if ( toggle ) {
6434                         dataShow.hidden = !hidden;
6435                 }
6436                 if ( hidden ) {
6437                         jQuery( elem ).show();
6438                 } else {
6439                         anim.done(function() {
6440                                 jQuery( elem ).hide();
6441                         });
6442                 }
6443                 anim.done(function() {
6444                         var prop;
6445
6446                         data_priv.remove( elem, "fxshow" );
6447                         for ( prop in orig ) {
6448                                 jQuery.style( elem, prop, orig[ prop ] );
6449                         }
6450                 });
6451                 for ( prop in orig ) {
6452                         tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
6453
6454                         if ( !( prop in dataShow ) ) {
6455                                 dataShow[ prop ] = tween.start;
6456                                 if ( hidden ) {
6457                                         tween.end = tween.start;
6458                                         tween.start = prop === "width" || prop === "height" ? 1 : 0;
6459                                 }
6460                         }
6461                 }
6462
6463         // If this is a noop like .hide().hide(), restore an overwritten display value
6464         } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
6465                 style.display = display;
6466         }
6467 }
6468
6469 function propFilter( props, specialEasing ) {
6470         var index, name, easing, value, hooks;
6471
6472         // camelCase, specialEasing and expand cssHook pass
6473         for ( index in props ) {
6474                 name = jQuery.camelCase( index );
6475                 easing = specialEasing[ name ];
6476                 value = props[ index ];
6477                 if ( jQuery.isArray( value ) ) {
6478                         easing = value[ 1 ];
6479                         value = props[ index ] = value[ 0 ];
6480                 }
6481
6482                 if ( index !== name ) {
6483                         props[ name ] = value;
6484                         delete props[ index ];
6485                 }
6486
6487                 hooks = jQuery.cssHooks[ name ];
6488                 if ( hooks && "expand" in hooks ) {
6489                         value = hooks.expand( value );
6490                         delete props[ name ];
6491
6492                         // not quite $.extend, this wont overwrite keys already present.
6493                         // also - reusing 'index' from above because we have the correct "name"
6494                         for ( index in value ) {
6495                                 if ( !( index in props ) ) {
6496                                         props[ index ] = value[ index ];
6497                                         specialEasing[ index ] = easing;
6498                                 }
6499                         }
6500                 } else {
6501                         specialEasing[ name ] = easing;
6502                 }
6503         }
6504 }
6505
6506 function Animation( elem, properties, options ) {
6507         var result,
6508                 stopped,
6509                 index = 0,
6510                 length = animationPrefilters.length,
6511                 deferred = jQuery.Deferred().always( function() {
6512                         // don't match elem in the :animated selector
6513                         delete tick.elem;
6514                 }),
6515                 tick = function() {
6516                         if ( stopped ) {
6517                                 return false;
6518                         }
6519                         var currentTime = fxNow || createFxNow(),
6520                                 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
6521                                 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
6522                                 temp = remaining / animation.duration || 0,
6523                                 percent = 1 - temp,
6524                                 index = 0,
6525                                 length = animation.tweens.length;
6526
6527                         for ( ; index < length ; index++ ) {
6528                                 animation.tweens[ index ].run( percent );
6529                         }
6530
6531                         deferred.notifyWith( elem, [ animation, percent, remaining ]);
6532
6533                         if ( percent < 1 && length ) {
6534                                 return remaining;
6535                         } else {
6536                                 deferred.resolveWith( elem, [ animation ] );
6537                                 return false;
6538                         }
6539                 },
6540                 animation = deferred.promise({
6541                         elem: elem,
6542                         props: jQuery.extend( {}, properties ),
6543                         opts: jQuery.extend( true, { specialEasing: {} }, options ),
6544                         originalProperties: properties,
6545                         originalOptions: options,
6546                         startTime: fxNow || createFxNow(),
6547                         duration: options.duration,
6548                         tweens: [],
6549                         createTween: function( prop, end ) {
6550                                 var tween = jQuery.Tween( elem, animation.opts, prop, end,
6551                                                 animation.opts.specialEasing[ prop ] || animation.opts.easing );
6552                                 animation.tweens.push( tween );
6553                                 return tween;
6554                         },
6555                         stop: function( gotoEnd ) {
6556                                 var index = 0,
6557                                         // if we are going to the end, we want to run all the tweens
6558                                         // otherwise we skip this part
6559                                         length = gotoEnd ? animation.tweens.length : 0;
6560                                 if ( stopped ) {
6561                                         return this;
6562                                 }
6563                                 stopped = true;
6564                                 for ( ; index < length ; index++ ) {
6565                                         animation.tweens[ index ].run( 1 );
6566                                 }
6567
6568                                 // resolve when we played the last frame
6569                                 // otherwise, reject
6570                                 if ( gotoEnd ) {
6571                                         deferred.resolveWith( elem, [ animation, gotoEnd ] );
6572                                 } else {
6573                                         deferred.rejectWith( elem, [ animation, gotoEnd ] );
6574                                 }
6575                                 return this;
6576                         }
6577                 }),
6578                 props = animation.props;
6579
6580         propFilter( props, animation.opts.specialEasing );
6581
6582         for ( ; index < length ; index++ ) {
6583                 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
6584                 if ( result ) {
6585                         return result;
6586                 }
6587         }
6588
6589         jQuery.map( props, createTween, animation );
6590
6591         if ( jQuery.isFunction( animation.opts.start ) ) {
6592                 animation.opts.start.call( elem, animation );
6593         }
6594
6595         jQuery.fx.timer(
6596                 jQuery.extend( tick, {
6597                         elem: elem,
6598                         anim: animation,
6599                         queue: animation.opts.queue
6600                 })
6601         );
6602
6603         // attach callbacks from options
6604         return animation.progress( animation.opts.progress )
6605                 .done( animation.opts.done, animation.opts.complete )
6606                 .fail( animation.opts.fail )
6607                 .always( animation.opts.always );
6608 }
6609
6610 jQuery.Animation = jQuery.extend( Animation, {
6611
6612         tweener: function( props, callback ) {
6613                 if ( jQuery.isFunction( props ) ) {
6614                         callback = props;
6615                         props = [ "*" ];
6616                 } else {
6617                         props = props.split(" ");
6618                 }
6619
6620                 var prop,
6621                         index = 0,
6622                         length = props.length;
6623
6624                 for ( ; index < length ; index++ ) {
6625                         prop = props[ index ];
6626                         tweeners[ prop ] = tweeners[ prop ] || [];
6627                         tweeners[ prop ].unshift( callback );
6628                 }
6629         },
6630
6631         prefilter: function( callback, prepend ) {
6632                 if ( prepend ) {
6633                         animationPrefilters.unshift( callback );
6634                 } else {
6635                         animationPrefilters.push( callback );
6636                 }
6637         }
6638 });
6639
6640 jQuery.speed = function( speed, easing, fn ) {
6641         var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
6642                 complete: fn || !fn && easing ||
6643                         jQuery.isFunction( speed ) && speed,
6644                 duration: speed,
6645                 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
6646         };
6647
6648         opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
6649                 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
6650
6651         // normalize opt.queue - true/undefined/null -> "fx"
6652         if ( opt.queue == null || opt.queue === true ) {
6653                 opt.queue = "fx";
6654         }
6655
6656         // Queueing
6657         opt.old = opt.complete;
6658
6659         opt.complete = function() {
6660                 if ( jQuery.isFunction( opt.old ) ) {
6661                         opt.old.call( this );
6662                 }
6663
6664                 if ( opt.queue ) {
6665                         jQuery.dequeue( this, opt.queue );
6666                 }
6667         };
6668
6669         return opt;
6670 };
6671
6672 jQuery.fn.extend({
6673         fadeTo: function( speed, to, easing, callback ) {
6674
6675                 // show any hidden elements after setting opacity to 0
6676                 return this.filter( isHidden ).css( "opacity", 0 ).show()
6677
6678                         // animate to the value specified
6679                         .end().animate({ opacity: to }, speed, easing, callback );
6680         },
6681         animate: function( prop, speed, easing, callback ) {
6682                 var empty = jQuery.isEmptyObject( prop ),
6683                         optall = jQuery.speed( speed, easing, callback ),
6684                         doAnimation = function() {
6685                                 // Operate on a copy of prop so per-property easing won't be lost
6686                                 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
6687
6688                                 // Empty animations, or finishing resolves immediately
6689                                 if ( empty || data_priv.get( this, "finish" ) ) {
6690                                         anim.stop( true );
6691                                 }
6692                         };
6693                         doAnimation.finish = doAnimation;
6694
6695                 return empty || optall.queue === false ?
6696                         this.each( doAnimation ) :
6697                         this.queue( optall.queue, doAnimation );
6698         },
6699         stop: function( type, clearQueue, gotoEnd ) {
6700                 var stopQueue = function( hooks ) {
6701                         var stop = hooks.stop;
6702                         delete hooks.stop;
6703                         stop( gotoEnd );
6704                 };
6705
6706                 if ( typeof type !== "string" ) {
6707                         gotoEnd = clearQueue;
6708                         clearQueue = type;
6709                         type = undefined;
6710                 }
6711                 if ( clearQueue && type !== false ) {
6712                         this.queue( type || "fx", [] );
6713                 }
6714
6715                 return this.each(function() {
6716                         var dequeue = true,
6717                                 index = type != null && type + "queueHooks",
6718                                 timers = jQuery.timers,
6719                                 data = data_priv.get( this );
6720
6721                         if ( index ) {
6722                                 if ( data[ index ] && data[ index ].stop ) {
6723                                         stopQueue( data[ index ] );
6724                                 }
6725                         } else {
6726                                 for ( index in data ) {
6727                                         if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
6728                                                 stopQueue( data[ index ] );
6729                                         }
6730                                 }
6731                         }
6732
6733                         for ( index = timers.length; index--; ) {
6734                                 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
6735                                         timers[ index ].anim.stop( gotoEnd );
6736                                         dequeue = false;
6737                                         timers.splice( index, 1 );
6738                                 }
6739                         }
6740
6741                         // start the next in the queue if the last step wasn't forced
6742                         // timers currently will call their complete callbacks, which will dequeue
6743                         // but only if they were gotoEnd
6744                         if ( dequeue || !gotoEnd ) {
6745                                 jQuery.dequeue( this, type );
6746                         }
6747                 });
6748         },
6749         finish: function( type ) {
6750                 if ( type !== false ) {
6751                         type = type || "fx";
6752                 }
6753                 return this.each(function() {
6754                         var index,
6755                                 data = data_priv.get( this ),
6756                                 queue = data[ type + "queue" ],
6757                                 hooks = data[ type + "queueHooks" ],
6758                                 timers = jQuery.timers,
6759                                 length = queue ? queue.length : 0;
6760
6761                         // enable finishing flag on private data
6762                         data.finish = true;
6763
6764                         // empty the queue first
6765                         jQuery.queue( this, type, [] );
6766
6767                         if ( hooks && hooks.stop ) {
6768                                 hooks.stop.call( this, true );
6769                         }
6770
6771                         // look for any active animations, and finish them
6772                         for ( index = timers.length; index--; ) {
6773                                 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
6774                                         timers[ index ].anim.stop( true );
6775                                         timers.splice( index, 1 );
6776                                 }
6777                         }
6778
6779                         // look for any animations in the old queue and finish them
6780                         for ( index = 0; index < length; index++ ) {
6781                                 if ( queue[ index ] && queue[ index ].finish ) {
6782                                         queue[ index ].finish.call( this );
6783                                 }
6784                         }
6785
6786                         // turn off finishing flag
6787                         delete data.finish;
6788                 });
6789         }
6790 });
6791
6792 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
6793         var cssFn = jQuery.fn[ name ];
6794         jQuery.fn[ name ] = function( speed, easing, callback ) {
6795                 return speed == null || typeof speed === "boolean" ?
6796                         cssFn.apply( this, arguments ) :
6797                         this.animate( genFx( name, true ), speed, easing, callback );
6798         };
6799 });
6800
6801 // Generate shortcuts for custom animations
6802 jQuery.each({
6803         slideDown: genFx("show"),
6804         slideUp: genFx("hide"),
6805         slideToggle: genFx("toggle"),
6806         fadeIn: { opacity: "show" },
6807         fadeOut: { opacity: "hide" },
6808         fadeToggle: { opacity: "toggle" }
6809 }, function( name, props ) {
6810         jQuery.fn[ name ] = function( speed, easing, callback ) {
6811                 return this.animate( props, speed, easing, callback );
6812         };
6813 });
6814
6815 jQuery.timers = [];
6816 jQuery.fx.tick = function() {
6817         var timer,
6818                 i = 0,
6819                 timers = jQuery.timers;
6820
6821         fxNow = jQuery.now();
6822
6823         for ( ; i < timers.length; i++ ) {
6824                 timer = timers[ i ];
6825                 // Checks the timer has not already been removed
6826                 if ( !timer() && timers[ i ] === timer ) {
6827                         timers.splice( i--, 1 );
6828                 }
6829         }
6830
6831         if ( !timers.length ) {
6832                 jQuery.fx.stop();
6833         }
6834         fxNow = undefined;
6835 };
6836
6837 jQuery.fx.timer = function( timer ) {
6838         jQuery.timers.push( timer );
6839         if ( timer() ) {
6840                 jQuery.fx.start();
6841         } else {
6842                 jQuery.timers.pop();
6843         }
6844 };
6845
6846 jQuery.fx.interval = 13;
6847
6848 jQuery.fx.start = function() {
6849         if ( !timerId ) {
6850                 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
6851         }
6852 };
6853
6854 jQuery.fx.stop = function() {
6855         clearInterval( timerId );
6856         timerId = null;
6857 };
6858
6859 jQuery.fx.speeds = {
6860         slow: 600,
6861         fast: 200,
6862         // Default speed
6863         _default: 400
6864 };
6865
6866
6867 // Based off of the plugin by Clint Helfers, with permission.
6868 // http://blindsignals.com/index.php/2009/07/jquery-delay/
6869 jQuery.fn.delay = function( time, type ) {
6870         time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
6871         type = type || "fx";
6872
6873         return this.queue( type, function( next, hooks ) {
6874                 var timeout = setTimeout( next, time );
6875                 hooks.stop = function() {
6876                         clearTimeout( timeout );
6877                 };
6878         });
6879 };
6880
6881
6882 (function() {
6883         var input = document.createElement( "input" ),
6884                 select = document.createElement( "select" ),
6885                 opt = select.appendChild( document.createElement( "option" ) );
6886
6887         input.type = "checkbox";
6888
6889         // Support: iOS 5.1, Android 4.x, Android 2.3
6890         // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
6891         support.checkOn = input.value !== "";
6892
6893         // Must access the parent to make an option select properly
6894         // Support: IE9, IE10
6895         support.optSelected = opt.selected;
6896
6897         // Make sure that the options inside disabled selects aren't marked as disabled
6898         // (WebKit marks them as disabled)
6899         select.disabled = true;
6900         support.optDisabled = !opt.disabled;
6901
6902         // Check if an input maintains its value after becoming a radio
6903         // Support: IE9, IE10
6904         input = document.createElement( "input" );
6905         input.value = "t";
6906         input.type = "radio";
6907         support.radioValue = input.value === "t";
6908 })();
6909
6910
6911 var nodeHook, boolHook,
6912         attrHandle = jQuery.expr.attrHandle;
6913
6914 jQuery.fn.extend({
6915         attr: function( name, value ) {
6916                 return access( this, jQuery.attr, name, value, arguments.length > 1 );
6917         },
6918
6919         removeAttr: function( name ) {
6920                 return this.each(function() {
6921                         jQuery.removeAttr( this, name );
6922                 });
6923         }
6924 });
6925
6926 jQuery.extend({
6927         attr: function( elem, name, value ) {
6928                 var hooks, ret,
6929                         nType = elem.nodeType;
6930
6931                 // don't get/set attributes on text, comment and attribute nodes
6932                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
6933                         return;
6934                 }
6935
6936                 // Fallback to prop when attributes are not supported
6937                 if ( typeof elem.getAttribute === strundefined ) {
6938                         return jQuery.prop( elem, name, value );
6939                 }
6940
6941                 // All attributes are lowercase
6942                 // Grab necessary hook if one is defined
6943                 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
6944                         name = name.toLowerCase();
6945                         hooks = jQuery.attrHooks[ name ] ||
6946                                 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
6947                 }
6948
6949                 if ( value !== undefined ) {
6950
6951                         if ( value === null ) {
6952                                 jQuery.removeAttr( elem, name );
6953
6954                         } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
6955                                 return ret;
6956
6957                         } else {
6958                                 elem.setAttribute( name, value + "" );
6959                                 return value;
6960                         }
6961
6962                 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
6963                         return ret;
6964
6965                 } else {
6966                         ret = jQuery.find.attr( elem, name );
6967
6968                         // Non-existent attributes return null, we normalize to undefined
6969                         return ret == null ?
6970                                 undefined :
6971                                 ret;
6972                 }
6973         },
6974
6975         removeAttr: function( elem, value ) {
6976                 var name, propName,
6977                         i = 0,
6978                         attrNames = value && value.match( rnotwhite );
6979
6980                 if ( attrNames && elem.nodeType === 1 ) {
6981                         while ( (name = attrNames[i++]) ) {
6982                                 propName = jQuery.propFix[ name ] || name;
6983
6984                                 // Boolean attributes get special treatment (#10870)
6985                                 if ( jQuery.expr.match.bool.test( name ) ) {
6986                                         // Set corresponding property to false
6987                                         elem[ propName ] = false;
6988                                 }
6989
6990                                 elem.removeAttribute( name );
6991                         }
6992                 }
6993         },
6994
6995         attrHooks: {
6996                 type: {
6997                         set: function( elem, value ) {
6998                                 if ( !support.radioValue && value === "radio" &&
6999                                         jQuery.nodeName( elem, "input" ) ) {
7000                                         // Setting the type on a radio button after the value resets the value in IE6-9
7001                                         // Reset value to default in case type is set after value during creation
7002                                         var val = elem.value;
7003                                         elem.setAttribute( "type", value );
7004                                         if ( val ) {
7005                                                 elem.value = val;
7006                                         }
7007                                         return value;
7008                                 }
7009                         }
7010                 }
7011         }
7012 });
7013
7014 // Hooks for boolean attributes
7015 boolHook = {
7016         set: function( elem, value, name ) {
7017                 if ( value === false ) {
7018                         // Remove boolean attributes when set to false
7019                         jQuery.removeAttr( elem, name );
7020                 } else {
7021                         elem.setAttribute( name, name );
7022                 }
7023                 return name;
7024         }
7025 };
7026 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
7027         var getter = attrHandle[ name ] || jQuery.find.attr;
7028
7029         attrHandle[ name ] = function( elem, name, isXML ) {
7030                 var ret, handle;
7031                 if ( !isXML ) {
7032                         // Avoid an infinite loop by temporarily removing this function from the getter
7033                         handle = attrHandle[ name ];
7034                         attrHandle[ name ] = ret;
7035                         ret = getter( elem, name, isXML ) != null ?
7036                                 name.toLowerCase() :
7037                                 null;
7038                         attrHandle[ name ] = handle;
7039                 }
7040                 return ret;
7041         };
7042 });
7043
7044
7045
7046
7047 var rfocusable = /^(?:input|select|textarea|button)$/i;
7048
7049 jQuery.fn.extend({
7050         prop: function( name, value ) {
7051                 return access( this, jQuery.prop, name, value, arguments.length > 1 );
7052         },
7053
7054         removeProp: function( name ) {
7055                 return this.each(function() {
7056                         delete this[ jQuery.propFix[ name ] || name ];
7057                 });
7058         }
7059 });
7060
7061 jQuery.extend({
7062         propFix: {
7063                 "for": "htmlFor",
7064                 "class": "className"
7065         },
7066
7067         prop: function( elem, name, value ) {
7068                 var ret, hooks, notxml,
7069                         nType = elem.nodeType;
7070
7071                 // don't get/set properties on text, comment and attribute nodes
7072                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
7073                         return;
7074                 }
7075
7076                 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
7077
7078                 if ( notxml ) {
7079                         // Fix name and attach hooks
7080                         name = jQuery.propFix[ name ] || name;
7081                         hooks = jQuery.propHooks[ name ];
7082                 }
7083
7084                 if ( value !== undefined ) {
7085                         return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
7086                                 ret :
7087                                 ( elem[ name ] = value );
7088
7089                 } else {
7090                         return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
7091                                 ret :
7092                                 elem[ name ];
7093                 }
7094         },
7095
7096         propHooks: {
7097                 tabIndex: {
7098                         get: function( elem ) {
7099                                 return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
7100                                         elem.tabIndex :
7101                                         -1;
7102                         }
7103                 }
7104         }
7105 });
7106
7107 // Support: IE9+
7108 // Selectedness for an option in an optgroup can be inaccurate
7109 if ( !support.optSelected ) {
7110         jQuery.propHooks.selected = {
7111                 get: function( elem ) {
7112                         var parent = elem.parentNode;
7113                         if ( parent && parent.parentNode ) {
7114                                 parent.parentNode.selectedIndex;
7115                         }
7116                         return null;
7117                 }
7118         };
7119 }
7120
7121 jQuery.each([
7122         "tabIndex",
7123         "readOnly",
7124         "maxLength",
7125         "cellSpacing",
7126         "cellPadding",
7127         "rowSpan",
7128         "colSpan",
7129         "useMap",
7130         "frameBorder",
7131         "contentEditable"
7132 ], function() {
7133         jQuery.propFix[ this.toLowerCase() ] = this;
7134 });
7135
7136
7137
7138
7139 var rclass = /[\t\r\n\f]/g;
7140
7141 jQuery.fn.extend({
7142         addClass: function( value ) {
7143                 var classes, elem, cur, clazz, j, finalValue,
7144                         proceed = typeof value === "string" && value,
7145                         i = 0,
7146                         len = this.length;
7147
7148                 if ( jQuery.isFunction( value ) ) {
7149                         return this.each(function( j ) {
7150                                 jQuery( this ).addClass( value.call( this, j, this.className ) );
7151                         });
7152                 }
7153
7154                 if ( proceed ) {
7155                         // The disjunction here is for better compressibility (see removeClass)
7156                         classes = ( value || "" ).match( rnotwhite ) || [];
7157
7158                         for ( ; i < len; i++ ) {
7159                                 elem = this[ i ];
7160                                 cur = elem.nodeType === 1 && ( elem.className ?
7161                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
7162                                         " "
7163                                 );
7164
7165                                 if ( cur ) {
7166                                         j = 0;
7167                                         while ( (clazz = classes[j++]) ) {
7168                                                 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
7169                                                         cur += clazz + " ";
7170                                                 }
7171                                         }
7172
7173                                         // only assign if different to avoid unneeded rendering.
7174                                         finalValue = jQuery.trim( cur );
7175                                         if ( elem.className !== finalValue ) {
7176                                                 elem.className = finalValue;
7177                                         }
7178                                 }
7179                         }
7180                 }
7181
7182                 return this;
7183         },
7184
7185         removeClass: function( value ) {
7186                 var classes, elem, cur, clazz, j, finalValue,
7187                         proceed = arguments.length === 0 || typeof value === "string" && value,
7188                         i = 0,
7189                         len = this.length;
7190
7191                 if ( jQuery.isFunction( value ) ) {
7192                         return this.each(function( j ) {
7193                                 jQuery( this ).removeClass( value.call( this, j, this.className ) );
7194                         });
7195                 }
7196                 if ( proceed ) {
7197                         classes = ( value || "" ).match( rnotwhite ) || [];
7198
7199                         for ( ; i < len; i++ ) {
7200                                 elem = this[ i ];
7201                                 // This expression is here for better compressibility (see addClass)
7202                                 cur = elem.nodeType === 1 && ( elem.className ?
7203                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
7204                                         ""
7205                                 );
7206
7207                                 if ( cur ) {
7208                                         j = 0;
7209                                         while ( (clazz = classes[j++]) ) {
7210                                                 // Remove *all* instances
7211                                                 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
7212                                                         cur = cur.replace( " " + clazz + " ", " " );
7213                                                 }
7214                                         }
7215
7216                                         // only assign if different to avoid unneeded rendering.
7217                                         finalValue = value ? jQuery.trim( cur ) : "";
7218                                         if ( elem.className !== finalValue ) {
7219                                                 elem.className = finalValue;
7220                                         }
7221                                 }
7222                         }
7223                 }
7224
7225                 return this;
7226         },
7227
7228         toggleClass: function( value, stateVal ) {
7229                 var type = typeof value;
7230
7231                 if ( typeof stateVal === "boolean" && type === "string" ) {
7232                         return stateVal ? this.addClass( value ) : this.removeClass( value );
7233                 }
7234
7235                 if ( jQuery.isFunction( value ) ) {
7236                         return this.each(function( i ) {
7237                                 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
7238                         });
7239                 }
7240
7241                 return this.each(function() {
7242                         if ( type === "string" ) {
7243                                 // toggle individual class names
7244                                 var className,
7245                                         i = 0,
7246                                         self = jQuery( this ),
7247                                         classNames = value.match( rnotwhite ) || [];
7248
7249                                 while ( (className = classNames[ i++ ]) ) {
7250                                         // check each className given, space separated list
7251                                         if ( self.hasClass( className ) ) {
7252                                                 self.removeClass( className );
7253                                         } else {
7254                                                 self.addClass( className );
7255                                         }
7256                                 }
7257
7258                         // Toggle whole class name
7259                         } else if ( type === strundefined || type === "boolean" ) {
7260                                 if ( this.className ) {
7261                                         // store className if set
7262                                         data_priv.set( this, "__className__", this.className );
7263                                 }
7264
7265                                 // If the element has a class name or if we're passed "false",
7266                                 // then remove the whole classname (if there was one, the above saved it).
7267                                 // Otherwise bring back whatever was previously saved (if anything),
7268                                 // falling back to the empty string if nothing was stored.
7269                                 this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
7270                         }
7271                 });
7272         },
7273
7274         hasClass: function( selector ) {
7275                 var className = " " + selector + " ",
7276                         i = 0,
7277                         l = this.length;
7278                 for ( ; i < l; i++ ) {
7279                         if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
7280                                 return true;
7281                         }
7282                 }
7283
7284                 return false;
7285         }
7286 });
7287
7288
7289
7290
7291 var rreturn = /\r/g;
7292
7293 jQuery.fn.extend({
7294         val: function( value ) {
7295                 var hooks, ret, isFunction,
7296                         elem = this[0];
7297
7298                 if ( !arguments.length ) {
7299                         if ( elem ) {
7300                                 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
7301
7302                                 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
7303                                         return ret;
7304                                 }
7305
7306                                 ret = elem.value;
7307
7308                                 return typeof ret === "string" ?
7309                                         // handle most common string cases
7310                                         ret.replace(rreturn, "") :
7311                                         // handle cases where value is null/undef or number
7312                                         ret == null ? "" : ret;
7313                         }
7314
7315                         return;
7316                 }
7317
7318                 isFunction = jQuery.isFunction( value );
7319
7320                 return this.each(function( i ) {
7321                         var val;
7322
7323                         if ( this.nodeType !== 1 ) {
7324                                 return;
7325                         }
7326
7327                         if ( isFunction ) {
7328                                 val = value.call( this, i, jQuery( this ).val() );
7329                         } else {
7330                                 val = value;
7331                         }
7332
7333                         // Treat null/undefined as ""; convert numbers to string
7334                         if ( val == null ) {
7335                                 val = "";
7336
7337                         } else if ( typeof val === "number" ) {
7338                                 val += "";
7339
7340                         } else if ( jQuery.isArray( val ) ) {
7341                                 val = jQuery.map( val, function( value ) {
7342                                         return value == null ? "" : value + "";
7343                                 });
7344                         }
7345
7346                         hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
7347
7348                         // If set returns undefined, fall back to normal setting
7349                         if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
7350                                 this.value = val;
7351                         }
7352                 });
7353         }
7354 });
7355
7356 jQuery.extend({
7357         valHooks: {
7358                 option: {
7359                         get: function( elem ) {
7360                                 var val = jQuery.find.attr( elem, "value" );
7361                                 return val != null ?
7362                                         val :
7363                                         // Support: IE10-11+
7364                                         // option.text throws exceptions (#14686, #14858)
7365                                         jQuery.trim( jQuery.text( elem ) );
7366                         }
7367                 },
7368                 select: {
7369                         get: function( elem ) {
7370                                 var value, option,
7371                                         options = elem.options,
7372                                         index = elem.selectedIndex,
7373                                         one = elem.type === "select-one" || index < 0,
7374                                         values = one ? null : [],
7375                                         max = one ? index + 1 : options.length,
7376                                         i = index < 0 ?
7377                                                 max :
7378                                                 one ? index : 0;
7379
7380                                 // Loop through all the selected options
7381                                 for ( ; i < max; i++ ) {
7382                                         option = options[ i ];
7383
7384                                         // IE6-9 doesn't update selected after form reset (#2551)
7385                                         if ( ( option.selected || i === index ) &&
7386                                                         // Don't return options that are disabled or in a disabled optgroup
7387                                                         ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
7388                                                         ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
7389
7390                                                 // Get the specific value for the option
7391                                                 value = jQuery( option ).val();
7392
7393                                                 // We don't need an array for one selects
7394                                                 if ( one ) {
7395                                                         return value;
7396                                                 }
7397
7398                                                 // Multi-Selects return an array
7399                                                 values.push( value );
7400                                         }
7401                                 }
7402
7403                                 return values;
7404                         },
7405
7406                         set: function( elem, value ) {
7407                                 var optionSet, option,
7408                                         options = elem.options,
7409                                         values = jQuery.makeArray( value ),
7410                                         i = options.length;
7411
7412                                 while ( i-- ) {
7413                                         option = options[ i ];
7414                                         if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
7415                                                 optionSet = true;
7416                                         }
7417                                 }
7418
7419                                 // force browsers to behave consistently when non-matching value is set
7420                                 if ( !optionSet ) {
7421                                         elem.selectedIndex = -1;
7422                                 }
7423                                 return values;
7424                         }
7425                 }
7426         }
7427 });
7428
7429 // Radios and checkboxes getter/setter
7430 jQuery.each([ "radio", "checkbox" ], function() {
7431         jQuery.valHooks[ this ] = {
7432                 set: function( elem, value ) {
7433                         if ( jQuery.isArray( value ) ) {
7434                                 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
7435                         }
7436                 }
7437         };
7438         if ( !support.checkOn ) {
7439                 jQuery.valHooks[ this ].get = function( elem ) {
7440                         // Support: Webkit
7441                         // "" is returned instead of "on" if a value isn't specified
7442                         return elem.getAttribute("value") === null ? "on" : elem.value;
7443                 };
7444         }
7445 });
7446
7447
7448
7449
7450 // Return jQuery for attributes-only inclusion
7451
7452
7453 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7454         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7455         "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7456
7457         // Handle event binding
7458         jQuery.fn[ name ] = function( data, fn ) {
7459                 return arguments.length > 0 ?
7460                         this.on( name, null, data, fn ) :
7461                         this.trigger( name );
7462         };
7463 });
7464
7465 jQuery.fn.extend({
7466         hover: function( fnOver, fnOut ) {
7467                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7468         },
7469
7470         bind: function( types, data, fn ) {
7471                 return this.on( types, null, data, fn );
7472         },
7473         unbind: function( types, fn ) {
7474                 return this.off( types, null, fn );
7475         },
7476
7477         delegate: function( selector, types, data, fn ) {
7478                 return this.on( types, selector, data, fn );
7479         },
7480         undelegate: function( selector, types, fn ) {
7481                 // ( namespace ) or ( selector, types [, fn] )
7482                 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
7483         }
7484 });
7485
7486
7487 var nonce = jQuery.now();
7488
7489 var rquery = (/\?/);
7490
7491
7492
7493 // Support: Android 2.3
7494 // Workaround failure to string-cast null input
7495 jQuery.parseJSON = function( data ) {
7496         return JSON.parse( data + "" );
7497 };
7498
7499
7500 // Cross-browser xml parsing
7501 jQuery.parseXML = function( data ) {
7502         var xml, tmp;
7503         if ( !data || typeof data !== "string" ) {
7504                 return null;
7505         }
7506
7507         // Support: IE9
7508         try {
7509                 tmp = new DOMParser();
7510                 xml = tmp.parseFromString( data, "text/xml" );
7511         } catch ( e ) {
7512                 xml = undefined;
7513         }
7514
7515         if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
7516                 jQuery.error( "Invalid XML: " + data );
7517         }
7518         return xml;
7519 };
7520
7521
7522 var
7523         // Document location
7524         ajaxLocParts,
7525         ajaxLocation,
7526
7527         rhash = /#.*$/,
7528         rts = /([?&])_=[^&]*/,
7529         rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
7530         // #7653, #8125, #8152: local protocol detection
7531         rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7532         rnoContent = /^(?:GET|HEAD)$/,
7533         rprotocol = /^\/\//,
7534         rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
7535
7536         /* Prefilters
7537          * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7538          * 2) These are called:
7539          *    - BEFORE asking for a transport
7540          *    - AFTER param serialization (s.data is a string if s.processData is true)
7541          * 3) key is the dataType
7542          * 4) the catchall symbol "*" can be used
7543          * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7544          */
7545         prefilters = {},
7546
7547         /* Transports bindings
7548          * 1) key is the dataType
7549          * 2) the catchall symbol "*" can be used
7550          * 3) selection will start with transport dataType and THEN go to "*" if needed
7551          */
7552         transports = {},
7553
7554         // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7555         allTypes = "*/".concat("*");
7556
7557 // #8138, IE may throw an exception when accessing
7558 // a field from window.location if document.domain has been set
7559 try {
7560         ajaxLocation = location.href;
7561 } catch( e ) {
7562         // Use the href attribute of an A element
7563         // since IE will modify it given document.location
7564         ajaxLocation = document.createElement( "a" );
7565         ajaxLocation.href = "";
7566         ajaxLocation = ajaxLocation.href;
7567 }
7568
7569 // Segment location into parts
7570 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7571
7572 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7573 function addToPrefiltersOrTransports( structure ) {
7574
7575         // dataTypeExpression is optional and defaults to "*"
7576         return function( dataTypeExpression, func ) {
7577
7578                 if ( typeof dataTypeExpression !== "string" ) {
7579                         func = dataTypeExpression;
7580                         dataTypeExpression = "*";
7581                 }
7582
7583                 var dataType,
7584                         i = 0,
7585                         dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
7586
7587                 if ( jQuery.isFunction( func ) ) {
7588                         // For each dataType in the dataTypeExpression
7589                         while ( (dataType = dataTypes[i++]) ) {
7590                                 // Prepend if requested
7591                                 if ( dataType[0] === "+" ) {
7592                                         dataType = dataType.slice( 1 ) || "*";
7593                                         (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7594
7595                                 // Otherwise append
7596                                 } else {
7597                                         (structure[ dataType ] = structure[ dataType ] || []).push( func );
7598                                 }
7599                         }
7600                 }
7601         };
7602 }
7603
7604 // Base inspection function for prefilters and transports
7605 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7606
7607         var inspected = {},
7608                 seekingTransport = ( structure === transports );
7609
7610         function inspect( dataType ) {
7611                 var selected;
7612                 inspected[ dataType ] = true;
7613                 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7614                         var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7615                         if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7616                                 options.dataTypes.unshift( dataTypeOrTransport );
7617                                 inspect( dataTypeOrTransport );
7618                                 return false;
7619                         } else if ( seekingTransport ) {
7620                                 return !( selected = dataTypeOrTransport );
7621                         }
7622                 });
7623                 return selected;
7624         }
7625
7626         return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7627 }
7628
7629 // A special extend for ajax options
7630 // that takes "flat" options (not to be deep extended)
7631 // Fixes #9887
7632 function ajaxExtend( target, src ) {
7633         var key, deep,
7634                 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7635
7636         for ( key in src ) {
7637                 if ( src[ key ] !== undefined ) {
7638                         ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7639                 }
7640         }
7641         if ( deep ) {
7642                 jQuery.extend( true, target, deep );
7643         }
7644
7645         return target;
7646 }
7647
7648 /* Handles responses to an ajax request:
7649  * - finds the right dataType (mediates between content-type and expected dataType)
7650  * - returns the corresponding response
7651  */
7652 function ajaxHandleResponses( s, jqXHR, responses ) {
7653
7654         var ct, type, finalDataType, firstDataType,
7655                 contents = s.contents,
7656                 dataTypes = s.dataTypes;
7657
7658         // Remove auto dataType and get content-type in the process
7659         while ( dataTypes[ 0 ] === "*" ) {
7660                 dataTypes.shift();
7661                 if ( ct === undefined ) {
7662                         ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
7663                 }
7664         }
7665
7666         // Check if we're dealing with a known content-type
7667         if ( ct ) {
7668                 for ( type in contents ) {
7669                         if ( contents[ type ] && contents[ type ].test( ct ) ) {
7670                                 dataTypes.unshift( type );
7671                                 break;
7672                         }
7673                 }
7674         }
7675
7676         // Check to see if we have a response for the expected dataType
7677         if ( dataTypes[ 0 ] in responses ) {
7678                 finalDataType = dataTypes[ 0 ];
7679         } else {
7680                 // Try convertible dataTypes
7681                 for ( type in responses ) {
7682                         if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
7683                                 finalDataType = type;
7684                                 break;
7685                         }
7686                         if ( !firstDataType ) {
7687                                 firstDataType = type;
7688                         }
7689                 }
7690                 // Or just use first one
7691                 finalDataType = finalDataType || firstDataType;
7692         }
7693
7694         // If we found a dataType
7695         // We add the dataType to the list if needed
7696         // and return the corresponding response
7697         if ( finalDataType ) {
7698                 if ( finalDataType !== dataTypes[ 0 ] ) {
7699                         dataTypes.unshift( finalDataType );
7700                 }
7701                 return responses[ finalDataType ];
7702         }
7703 }
7704
7705 /* Chain conversions given the request and the original response
7706  * Also sets the responseXXX fields on the jqXHR instance
7707  */
7708 function ajaxConvert( s, response, jqXHR, isSuccess ) {
7709         var conv2, current, conv, tmp, prev,
7710                 converters = {},
7711                 // Work with a copy of dataTypes in case we need to modify it for conversion
7712                 dataTypes = s.dataTypes.slice();
7713
7714         // Create converters map with lowercased keys
7715         if ( dataTypes[ 1 ] ) {
7716                 for ( conv in s.converters ) {
7717                         converters[ conv.toLowerCase() ] = s.converters[ conv ];
7718                 }
7719         }
7720
7721         current = dataTypes.shift();
7722
7723         // Convert to each sequential dataType
7724         while ( current ) {
7725
7726                 if ( s.responseFields[ current ] ) {
7727                         jqXHR[ s.responseFields[ current ] ] = response;
7728                 }
7729
7730                 // Apply the dataFilter if provided
7731                 if ( !prev && isSuccess && s.dataFilter ) {
7732                         response = s.dataFilter( response, s.dataType );
7733                 }
7734
7735                 prev = current;
7736                 current = dataTypes.shift();
7737
7738                 if ( current ) {
7739
7740                 // There's only work to do if current dataType is non-auto
7741                         if ( current === "*" ) {
7742
7743                                 current = prev;
7744
7745                         // Convert response if prev dataType is non-auto and differs from current
7746                         } else if ( prev !== "*" && prev !== current ) {
7747
7748                                 // Seek a direct converter
7749                                 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
7750
7751                                 // If none found, seek a pair
7752                                 if ( !conv ) {
7753                                         for ( conv2 in converters ) {
7754
7755                                                 // If conv2 outputs current
7756                                                 tmp = conv2.split( " " );
7757                                                 if ( tmp[ 1 ] === current ) {
7758
7759                                                         // If prev can be converted to accepted input
7760                                                         conv = converters[ prev + " " + tmp[ 0 ] ] ||
7761                                                                 converters[ "* " + tmp[ 0 ] ];
7762                                                         if ( conv ) {
7763                                                                 // Condense equivalence converters
7764                                                                 if ( conv === true ) {
7765                                                                         conv = converters[ conv2 ];
7766
7767                                                                 // Otherwise, insert the intermediate dataType
7768                                                                 } else if ( converters[ conv2 ] !== true ) {
7769                                                                         current = tmp[ 0 ];
7770                                                                         dataTypes.unshift( tmp[ 1 ] );
7771                                                                 }
7772                                                                 break;
7773                                                         }
7774                                                 }
7775                                         }
7776                                 }
7777
7778                                 // Apply converter (if not an equivalence)
7779                                 if ( conv !== true ) {
7780
7781                                         // Unless errors are allowed to bubble, catch and return them
7782                                         if ( conv && s[ "throws" ] ) {
7783                                                 response = conv( response );
7784                                         } else {
7785                                                 try {
7786                                                         response = conv( response );
7787                                                 } catch ( e ) {
7788                                                         return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
7789                                                 }
7790                                         }
7791                                 }
7792                         }
7793                 }
7794         }
7795
7796         return { state: "success", data: response };
7797 }
7798
7799 jQuery.extend({
7800
7801         // Counter for holding the number of active queries
7802         active: 0,
7803
7804         // Last-Modified header cache for next request
7805         lastModified: {},
7806         etag: {},
7807
7808         ajaxSettings: {
7809                 url: ajaxLocation,
7810                 type: "GET",
7811                 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7812                 global: true,
7813                 processData: true,
7814                 async: true,
7815                 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7816                 /*
7817                 timeout: 0,
7818                 data: null,
7819                 dataType: null,
7820                 username: null,
7821                 password: null,
7822                 cache: null,
7823                 throws: false,
7824                 traditional: false,
7825                 headers: {},
7826                 */
7827
7828                 accepts: {
7829                         "*": allTypes,
7830                         text: "text/plain",
7831                         html: "text/html",
7832                         xml: "application/xml, text/xml",
7833                         json: "application/json, text/javascript"
7834                 },
7835
7836                 contents: {
7837                         xml: /xml/,
7838                         html: /html/,
7839                         json: /json/
7840                 },
7841
7842                 responseFields: {
7843                         xml: "responseXML",
7844                         text: "responseText",
7845                         json: "responseJSON"
7846                 },
7847
7848                 // Data converters
7849                 // Keys separate source (or catchall "*") and destination types with a single space
7850                 converters: {
7851
7852                         // Convert anything to text
7853                         "* text": String,
7854
7855                         // Text to html (true = no transformation)
7856                         "text html": true,
7857
7858                         // Evaluate text as a json expression
7859                         "text json": jQuery.parseJSON,
7860
7861                         // Parse text as xml
7862                         "text xml": jQuery.parseXML
7863                 },
7864
7865                 // For options that shouldn't be deep extended:
7866                 // you can add your own custom options here if
7867                 // and when you create one that shouldn't be
7868                 // deep extended (see ajaxExtend)
7869                 flatOptions: {
7870                         url: true,
7871                         context: true
7872                 }
7873         },
7874
7875         // Creates a full fledged settings object into target
7876         // with both ajaxSettings and settings fields.
7877         // If target is omitted, writes into ajaxSettings.
7878         ajaxSetup: function( target, settings ) {
7879                 return settings ?
7880
7881                         // Building a settings object
7882                         ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7883
7884                         // Extending ajaxSettings
7885                         ajaxExtend( jQuery.ajaxSettings, target );
7886         },
7887
7888         ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7889         ajaxTransport: addToPrefiltersOrTransports( transports ),
7890
7891         // Main method
7892         ajax: function( url, options ) {
7893
7894                 // If url is an object, simulate pre-1.5 signature
7895                 if ( typeof url === "object" ) {
7896                         options = url;
7897                         url = undefined;
7898                 }
7899
7900                 // Force options to be an object
7901                 options = options || {};
7902
7903                 var transport,
7904                         // URL without anti-cache param
7905                         cacheURL,
7906                         // Response headers
7907                         responseHeadersString,
7908                         responseHeaders,
7909                         // timeout handle
7910                         timeoutTimer,
7911                         // Cross-domain detection vars
7912                         parts,
7913                         // To know if global events are to be dispatched
7914                         fireGlobals,
7915                         // Loop variable
7916                         i,
7917                         // Create the final options object
7918                         s = jQuery.ajaxSetup( {}, options ),
7919                         // Callbacks context
7920                         callbackContext = s.context || s,
7921                         // Context for global events is callbackContext if it is a DOM node or jQuery collection
7922                         globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7923                                 jQuery( callbackContext ) :
7924                                 jQuery.event,
7925                         // Deferreds
7926                         deferred = jQuery.Deferred(),
7927                         completeDeferred = jQuery.Callbacks("once memory"),
7928                         // Status-dependent callbacks
7929                         statusCode = s.statusCode || {},
7930                         // Headers (they are sent all at once)
7931                         requestHeaders = {},
7932                         requestHeadersNames = {},
7933                         // The jqXHR state
7934                         state = 0,
7935                         // Default abort message
7936                         strAbort = "canceled",
7937                         // Fake xhr
7938                         jqXHR = {
7939                                 readyState: 0,
7940
7941                                 // Builds headers hashtable if needed
7942                                 getResponseHeader: function( key ) {
7943                                         var match;
7944                                         if ( state === 2 ) {
7945                                                 if ( !responseHeaders ) {
7946                                                         responseHeaders = {};
7947                                                         while ( (match = rheaders.exec( responseHeadersString )) ) {
7948                                                                 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7949                                                         }
7950                                                 }
7951                                                 match = responseHeaders[ key.toLowerCase() ];
7952                                         }
7953                                         return match == null ? null : match;
7954                                 },
7955
7956                                 // Raw string
7957                                 getAllResponseHeaders: function() {
7958                                         return state === 2 ? responseHeadersString : null;
7959                                 },
7960
7961                                 // Caches the header
7962                                 setRequestHeader: function( name, value ) {
7963                                         var lname = name.toLowerCase();
7964                                         if ( !state ) {
7965                                                 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7966                                                 requestHeaders[ name ] = value;
7967                                         }
7968                                         return this;
7969                                 },
7970
7971                                 // Overrides response content-type header
7972                                 overrideMimeType: function( type ) {
7973                                         if ( !state ) {
7974                                                 s.mimeType = type;
7975                                         }
7976                                         return this;
7977                                 },
7978
7979                                 // Status-dependent callbacks
7980                                 statusCode: function( map ) {
7981                                         var code;
7982                                         if ( map ) {
7983                                                 if ( state < 2 ) {
7984                                                         for ( code in map ) {
7985                                                                 // Lazy-add the new callback in a way that preserves old ones
7986                                                                 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7987                                                         }
7988                                                 } else {
7989                                                         // Execute the appropriate callbacks
7990                                                         jqXHR.always( map[ jqXHR.status ] );
7991                                                 }
7992                                         }
7993                                         return this;
7994                                 },
7995
7996                                 // Cancel the request
7997                                 abort: function( statusText ) {
7998                                         var finalText = statusText || strAbort;
7999                                         if ( transport ) {
8000                                                 transport.abort( finalText );
8001                                         }
8002                                         done( 0, finalText );
8003                                         return this;
8004                                 }
8005                         };
8006
8007                 // Attach deferreds
8008                 deferred.promise( jqXHR ).complete = completeDeferred.add;
8009                 jqXHR.success = jqXHR.done;
8010                 jqXHR.error = jqXHR.fail;
8011
8012                 // Remove hash character (#7531: and string promotion)
8013                 // Add protocol if not provided (prefilters might expect it)
8014                 // Handle falsy url in the settings object (#10093: consistency with old signature)
8015                 // We also use the url parameter if available
8016                 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
8017                         .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8018
8019                 // Alias method option to type as per ticket #12004
8020                 s.type = options.method || options.type || s.method || s.type;
8021
8022                 // Extract dataTypes list
8023                 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
8024
8025                 // A cross-domain request is in order when we have a protocol:host:port mismatch
8026                 if ( s.crossDomain == null ) {
8027                         parts = rurl.exec( s.url.toLowerCase() );
8028                         s.crossDomain = !!( parts &&
8029                                 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
8030                                         ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
8031                                                 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
8032                         );
8033                 }
8034
8035                 // Convert data if not already a string
8036                 if ( s.data && s.processData && typeof s.data !== "string" ) {
8037                         s.data = jQuery.param( s.data, s.traditional );
8038                 }
8039
8040                 // Apply prefilters
8041                 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8042
8043                 // If request was aborted inside a prefilter, stop there
8044                 if ( state === 2 ) {
8045                         return jqXHR;
8046                 }
8047
8048                 // We can fire global events as of now if asked to
8049                 fireGlobals = s.global;
8050
8051                 // Watch for a new set of requests
8052                 if ( fireGlobals && jQuery.active++ === 0 ) {
8053                         jQuery.event.trigger("ajaxStart");
8054                 }
8055
8056                 // Uppercase the type
8057                 s.type = s.type.toUpperCase();
8058
8059                 // Determine if request has content
8060                 s.hasContent = !rnoContent.test( s.type );
8061
8062                 // Save the URL in case we're toying with the If-Modified-Since
8063                 // and/or If-None-Match header later on
8064                 cacheURL = s.url;
8065
8066                 // More options handling for requests with no content
8067                 if ( !s.hasContent ) {
8068
8069                         // If data is available, append data to url
8070                         if ( s.data ) {
8071                                 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8072                                 // #9682: remove data so that it's not used in an eventual retry
8073                                 delete s.data;
8074                         }
8075
8076                         // Add anti-cache in url if needed
8077                         if ( s.cache === false ) {
8078                                 s.url = rts.test( cacheURL ) ?
8079
8080                                         // If there is already a '_' parameter, set its value
8081                                         cacheURL.replace( rts, "$1_=" + nonce++ ) :
8082
8083                                         // Otherwise add one to the end
8084                                         cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
8085                         }
8086                 }
8087
8088                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8089                 if ( s.ifModified ) {
8090                         if ( jQuery.lastModified[ cacheURL ] ) {
8091                                 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8092                         }
8093                         if ( jQuery.etag[ cacheURL ] ) {
8094                                 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8095                         }
8096                 }
8097
8098                 // Set the correct header, if data is being sent
8099                 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8100                         jqXHR.setRequestHeader( "Content-Type", s.contentType );
8101                 }
8102
8103                 // Set the Accepts header for the server, depending on the dataType
8104                 jqXHR.setRequestHeader(
8105                         "Accept",
8106                         s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8107                                 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8108                                 s.accepts[ "*" ]
8109                 );
8110
8111                 // Check for headers option
8112                 for ( i in s.headers ) {
8113                         jqXHR.setRequestHeader( i, s.headers[ i ] );
8114                 }
8115
8116                 // Allow custom headers/mimetypes and early abort
8117                 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8118                         // Abort if not done already and return
8119                         return jqXHR.abort();
8120                 }
8121
8122                 // aborting is no longer a cancellation
8123                 strAbort = "abort";
8124
8125                 // Install callbacks on deferreds
8126                 for ( i in { success: 1, error: 1, complete: 1 } ) {
8127                         jqXHR[ i ]( s[ i ] );
8128                 }
8129
8130                 // Get transport
8131                 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8132
8133                 // If no transport, we auto-abort
8134                 if ( !transport ) {
8135                         done( -1, "No Transport" );
8136                 } else {
8137                         jqXHR.readyState = 1;
8138
8139                         // Send global event
8140                         if ( fireGlobals ) {
8141                                 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8142                         }
8143                         // Timeout
8144                         if ( s.async && s.timeout > 0 ) {
8145                                 timeoutTimer = setTimeout(function() {
8146                                         jqXHR.abort("timeout");
8147                                 }, s.timeout );
8148                         }
8149
8150                         try {
8151                                 state = 1;
8152                                 transport.send( requestHeaders, done );
8153                         } catch ( e ) {
8154                                 // Propagate exception as error if not done
8155                                 if ( state < 2 ) {
8156                                         done( -1, e );
8157                                 // Simply rethrow otherwise
8158                                 } else {
8159                                         throw e;
8160                                 }
8161                         }
8162                 }
8163
8164                 // Callback for when everything is done
8165                 function done( status, nativeStatusText, responses, headers ) {
8166                         var isSuccess, success, error, response, modified,
8167                                 statusText = nativeStatusText;
8168
8169                         // Called once
8170                         if ( state === 2 ) {
8171                                 return;
8172                         }
8173
8174                         // State is "done" now
8175                         state = 2;
8176
8177                         // Clear timeout if it exists
8178                         if ( timeoutTimer ) {
8179                                 clearTimeout( timeoutTimer );
8180                         }
8181
8182                         // Dereference transport for early garbage collection
8183                         // (no matter how long the jqXHR object will be used)
8184                         transport = undefined;
8185
8186                         // Cache response headers
8187                         responseHeadersString = headers || "";
8188
8189                         // Set readyState
8190                         jqXHR.readyState = status > 0 ? 4 : 0;
8191
8192                         // Determine if successful
8193                         isSuccess = status >= 200 && status < 300 || status === 304;
8194
8195                         // Get response data
8196                         if ( responses ) {
8197                                 response = ajaxHandleResponses( s, jqXHR, responses );
8198                         }
8199
8200                         // Convert no matter what (that way responseXXX fields are always set)
8201                         response = ajaxConvert( s, response, jqXHR, isSuccess );
8202
8203                         // If successful, handle type chaining
8204                         if ( isSuccess ) {
8205
8206                                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8207                                 if ( s.ifModified ) {
8208                                         modified = jqXHR.getResponseHeader("Last-Modified");
8209                                         if ( modified ) {
8210                                                 jQuery.lastModified[ cacheURL ] = modified;
8211                                         }
8212                                         modified = jqXHR.getResponseHeader("etag");
8213                                         if ( modified ) {
8214                                                 jQuery.etag[ cacheURL ] = modified;
8215                                         }
8216                                 }
8217
8218                                 // if no content
8219                                 if ( status === 204 || s.type === "HEAD" ) {
8220                                         statusText = "nocontent";
8221
8222                                 // if not modified
8223                                 } else if ( status === 304 ) {
8224                                         statusText = "notmodified";
8225
8226                                 // If we have data, let's convert it
8227                                 } else {
8228                                         statusText = response.state;
8229                                         success = response.data;
8230                                         error = response.error;
8231                                         isSuccess = !error;
8232                                 }
8233                         } else {
8234                                 // We extract error from statusText
8235                                 // then normalize statusText and status for non-aborts
8236                                 error = statusText;
8237                                 if ( status || !statusText ) {
8238                                         statusText = "error";
8239                                         if ( status < 0 ) {
8240                                                 status = 0;
8241                                         }
8242                                 }
8243                         }
8244
8245                         // Set data for the fake xhr object
8246                         jqXHR.status = status;
8247                         jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8248
8249                         // Success/Error
8250                         if ( isSuccess ) {
8251                                 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8252                         } else {
8253                                 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8254                         }
8255
8256                         // Status-dependent callbacks
8257                         jqXHR.statusCode( statusCode );
8258                         statusCode = undefined;
8259
8260                         if ( fireGlobals ) {
8261                                 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8262                                         [ jqXHR, s, isSuccess ? success : error ] );
8263                         }
8264
8265                         // Complete
8266                         completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8267
8268                         if ( fireGlobals ) {
8269                                 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8270                                 // Handle the global AJAX counter
8271                                 if ( !( --jQuery.active ) ) {
8272                                         jQuery.event.trigger("ajaxStop");
8273                                 }
8274                         }
8275                 }
8276
8277                 return jqXHR;
8278         },
8279
8280         getJSON: function( url, data, callback ) {
8281                 return jQuery.get( url, data, callback, "json" );
8282         },
8283
8284         getScript: function( url, callback ) {
8285                 return jQuery.get( url, undefined, callback, "script" );
8286         }
8287 });
8288
8289 jQuery.each( [ "get", "post" ], function( i, method ) {
8290         jQuery[ method ] = function( url, data, callback, type ) {
8291                 // shift arguments if data argument was omitted
8292                 if ( jQuery.isFunction( data ) ) {
8293                         type = type || callback;
8294                         callback = data;
8295                         data = undefined;
8296                 }
8297
8298                 return jQuery.ajax({
8299                         url: url,
8300                         type: method,
8301                         dataType: type,
8302                         data: data,
8303                         success: callback
8304                 });
8305         };
8306 });
8307
8308 // Attach a bunch of functions for handling common AJAX events
8309 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
8310         jQuery.fn[ type ] = function( fn ) {
8311                 return this.on( type, fn );
8312         };
8313 });
8314
8315
8316 jQuery._evalUrl = function( url ) {
8317         return jQuery.ajax({
8318                 url: url,
8319                 type: "GET",
8320                 dataType: "script",
8321                 async: false,
8322                 global: false,
8323                 "throws": true
8324         });
8325 };
8326
8327
8328 jQuery.fn.extend({
8329         wrapAll: function( html ) {
8330                 var wrap;
8331
8332                 if ( jQuery.isFunction( html ) ) {
8333                         return this.each(function( i ) {
8334                                 jQuery( this ).wrapAll( html.call(this, i) );
8335                         });
8336                 }
8337
8338                 if ( this[ 0 ] ) {
8339
8340                         // The elements to wrap the target around
8341                         wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
8342
8343                         if ( this[ 0 ].parentNode ) {
8344                                 wrap.insertBefore( this[ 0 ] );
8345                         }
8346
8347                         wrap.map(function() {
8348                                 var elem = this;
8349
8350                                 while ( elem.firstElementChild ) {
8351                                         elem = elem.firstElementChild;
8352                                 }
8353
8354                                 return elem;
8355                         }).append( this );
8356                 }
8357
8358                 return this;
8359         },
8360
8361         wrapInner: function( html ) {
8362                 if ( jQuery.isFunction( html ) ) {
8363                         return this.each(function( i ) {
8364                                 jQuery( this ).wrapInner( html.call(this, i) );
8365                         });
8366                 }
8367
8368                 return this.each(function() {
8369                         var self = jQuery( this ),
8370                                 contents = self.contents();
8371
8372                         if ( contents.length ) {
8373                                 contents.wrapAll( html );
8374
8375                         } else {
8376                                 self.append( html );
8377                         }
8378                 });
8379         },
8380
8381         wrap: function( html ) {
8382                 var isFunction = jQuery.isFunction( html );
8383
8384                 return this.each(function( i ) {
8385                         jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
8386                 });
8387         },
8388
8389         unwrap: function() {
8390                 return this.parent().each(function() {
8391                         if ( !jQuery.nodeName( this, "body" ) ) {
8392                                 jQuery( this ).replaceWith( this.childNodes );
8393                         }
8394                 }).end();
8395         }
8396 });
8397
8398
8399 jQuery.expr.filters.hidden = function( elem ) {
8400         // Support: Opera <= 12.12
8401         // Opera reports offsetWidths and offsetHeights less than zero on some elements
8402         return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
8403 };
8404 jQuery.expr.filters.visible = function( elem ) {
8405         return !jQuery.expr.filters.hidden( elem );
8406 };
8407
8408
8409
8410
8411 var r20 = /%20/g,
8412         rbracket = /\[\]$/,
8413         rCRLF = /\r?\n/g,
8414         rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
8415         rsubmittable = /^(?:input|select|textarea|keygen)/i;
8416
8417 function buildParams( prefix, obj, traditional, add ) {
8418         var name;
8419
8420         if ( jQuery.isArray( obj ) ) {
8421                 // Serialize array item.
8422                 jQuery.each( obj, function( i, v ) {
8423                         if ( traditional || rbracket.test( prefix ) ) {
8424                                 // Treat each array item as a scalar.
8425                                 add( prefix, v );
8426
8427                         } else {
8428                                 // Item is non-scalar (array or object), encode its numeric index.
8429                                 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
8430                         }
8431                 });
8432
8433         } else if ( !traditional && jQuery.type( obj ) === "object" ) {
8434                 // Serialize object item.
8435                 for ( name in obj ) {
8436                         buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8437                 }
8438
8439         } else {
8440                 // Serialize scalar item.
8441                 add( prefix, obj );
8442         }
8443 }
8444
8445 // Serialize an array of form elements or a set of
8446 // key/values into a query string
8447 jQuery.param = function( a, traditional ) {
8448         var prefix,
8449                 s = [],
8450                 add = function( key, value ) {
8451                         // If value is a function, invoke it and return its value
8452                         value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
8453                         s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
8454                 };
8455
8456         // Set traditional to true for jQuery <= 1.3.2 behavior.
8457         if ( traditional === undefined ) {
8458                 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
8459         }
8460
8461         // If an array was passed in, assume that it is an array of form elements.
8462         if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8463                 // Serialize the form elements
8464                 jQuery.each( a, function() {
8465                         add( this.name, this.value );
8466                 });
8467
8468         } else {
8469                 // If traditional, encode the "old" way (the way 1.3.2 or older
8470                 // did it), otherwise encode params recursively.
8471                 for ( prefix in a ) {
8472                         buildParams( prefix, a[ prefix ], traditional, add );
8473                 }
8474         }
8475
8476         // Return the resulting serialization
8477         return s.join( "&" ).replace( r20, "+" );
8478 };
8479
8480 jQuery.fn.extend({
8481         serialize: function() {
8482                 return jQuery.param( this.serializeArray() );
8483         },
8484         serializeArray: function() {
8485                 return this.map(function() {
8486                         // Can add propHook for "elements" to filter or add form elements
8487                         var elements = jQuery.prop( this, "elements" );
8488                         return elements ? jQuery.makeArray( elements ) : this;
8489                 })
8490                 .filter(function() {
8491                         var type = this.type;
8492
8493                         // Use .is( ":disabled" ) so that fieldset[disabled] works
8494                         return this.name && !jQuery( this ).is( ":disabled" ) &&
8495                                 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
8496                                 ( this.checked || !rcheckableType.test( type ) );
8497                 })
8498                 .map(function( i, elem ) {
8499                         var val = jQuery( this ).val();
8500
8501                         return val == null ?
8502                                 null :
8503                                 jQuery.isArray( val ) ?
8504                                         jQuery.map( val, function( val ) {
8505                                                 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8506                                         }) :
8507                                         { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8508                 }).get();
8509         }
8510 });
8511
8512
8513 jQuery.ajaxSettings.xhr = function() {
8514         try {
8515                 return new XMLHttpRequest();
8516         } catch( e ) {}
8517 };
8518
8519 var xhrId = 0,
8520         xhrCallbacks = {},
8521         xhrSuccessStatus = {
8522                 // file protocol always yields status code 0, assume 200
8523                 0: 200,
8524                 // Support: IE9
8525                 // #1450: sometimes IE returns 1223 when it should be 204
8526                 1223: 204
8527         },
8528         xhrSupported = jQuery.ajaxSettings.xhr();
8529
8530 // Support: IE9
8531 // Open requests must be manually aborted on unload (#5280)
8532 if ( window.ActiveXObject ) {
8533         jQuery( window ).on( "unload", function() {
8534                 for ( var key in xhrCallbacks ) {
8535                         xhrCallbacks[ key ]();
8536                 }
8537         });
8538 }
8539
8540 support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8541 support.ajax = xhrSupported = !!xhrSupported;
8542
8543 jQuery.ajaxTransport(function( options ) {
8544         var callback;
8545
8546         // Cross domain only allowed if supported through XMLHttpRequest
8547         if ( support.cors || xhrSupported && !options.crossDomain ) {
8548                 return {
8549                         send: function( headers, complete ) {
8550                                 var i,
8551                                         xhr = options.xhr(),
8552                                         id = ++xhrId;
8553
8554                                 xhr.open( options.type, options.url, options.async, options.username, options.password );
8555
8556                                 // Apply custom fields if provided
8557                                 if ( options.xhrFields ) {
8558                                         for ( i in options.xhrFields ) {
8559                                                 xhr[ i ] = options.xhrFields[ i ];
8560                                         }
8561                                 }
8562
8563                                 // Override mime type if needed
8564                                 if ( options.mimeType && xhr.overrideMimeType ) {
8565                                         xhr.overrideMimeType( options.mimeType );
8566                                 }
8567
8568                                 // X-Requested-With header
8569                                 // For cross-domain requests, seeing as conditions for a preflight are
8570                                 // akin to a jigsaw puzzle, we simply never set it to be sure.
8571                                 // (it can always be set on a per-request basis or even using ajaxSetup)
8572                                 // For same-domain requests, won't change header if already provided.
8573                                 if ( !options.crossDomain && !headers["X-Requested-With"] ) {
8574                                         headers["X-Requested-With"] = "XMLHttpRequest";
8575                                 }
8576
8577                                 // Set headers
8578                                 for ( i in headers ) {
8579                                         xhr.setRequestHeader( i, headers[ i ] );
8580                                 }
8581
8582                                 // Callback
8583                                 callback = function( type ) {
8584                                         return function() {
8585                                                 if ( callback ) {
8586                                                         delete xhrCallbacks[ id ];
8587                                                         callback = xhr.onload = xhr.onerror = null;
8588
8589                                                         if ( type === "abort" ) {
8590                                                                 xhr.abort();
8591                                                         } else if ( type === "error" ) {
8592                                                                 complete(
8593                                                                         // file: protocol always yields status 0; see #8605, #14207
8594                                                                         xhr.status,
8595                                                                         xhr.statusText
8596                                                                 );
8597                                                         } else {
8598                                                                 complete(
8599                                                                         xhrSuccessStatus[ xhr.status ] || xhr.status,
8600                                                                         xhr.statusText,
8601                                                                         // Support: IE9
8602                                                                         // Accessing binary-data responseText throws an exception
8603                                                                         // (#11426)
8604                                                                         typeof xhr.responseText === "string" ? {
8605                                                                                 text: xhr.responseText
8606                                                                         } : undefined,
8607                                                                         xhr.getAllResponseHeaders()
8608                                                                 );
8609                                                         }
8610                                                 }
8611                                         };
8612                                 };
8613
8614                                 // Listen to events
8615                                 xhr.onload = callback();
8616                                 xhr.onerror = callback("error");
8617
8618                                 // Create the abort callback
8619                                 callback = xhrCallbacks[ id ] = callback("abort");
8620
8621                                 try {
8622                                         // Do send the request (this may raise an exception)
8623                                         xhr.send( options.hasContent && options.data || null );
8624                                 } catch ( e ) {
8625                                         // #14683: Only rethrow if this hasn't been notified as an error yet
8626                                         if ( callback ) {
8627                                                 throw e;
8628                                         }
8629                                 }
8630                         },
8631
8632                         abort: function() {
8633                                 if ( callback ) {
8634                                         callback();
8635                                 }
8636                         }
8637                 };
8638         }
8639 });
8640
8641
8642
8643
8644 // Install script dataType
8645 jQuery.ajaxSetup({
8646         accepts: {
8647                 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8648         },
8649         contents: {
8650                 script: /(?:java|ecma)script/
8651         },
8652         converters: {
8653                 "text script": function( text ) {
8654                         jQuery.globalEval( text );
8655                         return text;
8656                 }
8657         }
8658 });
8659
8660 // Handle cache's special case and crossDomain
8661 jQuery.ajaxPrefilter( "script", function( s ) {
8662         if ( s.cache === undefined ) {
8663                 s.cache = false;
8664         }
8665         if ( s.crossDomain ) {
8666                 s.type = "GET";
8667         }
8668 });
8669
8670 // Bind script tag hack transport
8671 jQuery.ajaxTransport( "script", function( s ) {
8672         // This transport only deals with cross domain requests
8673         if ( s.crossDomain ) {
8674                 var script, callback;
8675                 return {
8676                         send: function( _, complete ) {
8677                                 script = jQuery("<script>").prop({
8678                                         async: true,
8679                                         charset: s.scriptCharset,
8680                                         src: s.url
8681                                 }).on(
8682                                         "load error",
8683                                         callback = function( evt ) {
8684                                                 script.remove();
8685                                                 callback = null;
8686                                                 if ( evt ) {
8687                                                         complete( evt.type === "error" ? 404 : 200, evt.type );
8688                                                 }
8689                                         }
8690                                 );
8691                                 document.head.appendChild( script[ 0 ] );
8692                         },
8693                         abort: function() {
8694                                 if ( callback ) {
8695                                         callback();
8696                                 }
8697                         }
8698                 };
8699         }
8700 });
8701
8702
8703
8704
8705 var oldCallbacks = [],
8706         rjsonp = /(=)\?(?=&|$)|\?\?/;
8707
8708 // Default jsonp settings
8709 jQuery.ajaxSetup({
8710         jsonp: "callback",
8711         jsonpCallback: function() {
8712                 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
8713                 this[ callback ] = true;
8714                 return callback;
8715         }
8716 });
8717
8718 // Detect, normalize options and install callbacks for jsonp requests
8719 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8720
8721         var callbackName, overwritten, responseContainer,
8722                 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8723                         "url" :
8724                         typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8725                 );
8726
8727         // Handle iff the expected data type is "jsonp" or we have a parameter to set
8728         if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8729
8730                 // Get callback name, remembering preexisting value associated with it
8731                 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8732                         s.jsonpCallback() :
8733                         s.jsonpCallback;
8734
8735                 // Insert callback into url or form data
8736                 if ( jsonProp ) {
8737                         s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8738                 } else if ( s.jsonp !== false ) {
8739                         s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8740                 }
8741
8742                 // Use data converter to retrieve json after script execution
8743                 s.converters["script json"] = function() {
8744                         if ( !responseContainer ) {
8745                                 jQuery.error( callbackName + " was not called" );
8746                         }
8747                         return responseContainer[ 0 ];
8748                 };
8749
8750                 // force json dataType
8751                 s.dataTypes[ 0 ] = "json";
8752
8753                 // Install callback
8754                 overwritten = window[ callbackName ];
8755                 window[ callbackName ] = function() {
8756                         responseContainer = arguments;
8757                 };
8758
8759                 // Clean-up function (fires after converters)
8760                 jqXHR.always(function() {
8761                         // Restore preexisting value
8762                         window[ callbackName ] = overwritten;
8763
8764                         // Save back as free
8765                         if ( s[ callbackName ] ) {
8766                                 // make sure that re-using the options doesn't screw things around
8767                                 s.jsonpCallback = originalSettings.jsonpCallback;
8768
8769                                 // save the callback name for future use
8770                                 oldCallbacks.push( callbackName );
8771                         }
8772
8773                         // Call if it was a function and we have a response
8774                         if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8775                                 overwritten( responseContainer[ 0 ] );
8776                         }
8777
8778                         responseContainer = overwritten = undefined;
8779                 });
8780
8781                 // Delegate to script
8782                 return "script";
8783         }
8784 });
8785
8786
8787
8788
8789 // data: string of html
8790 // context (optional): If specified, the fragment will be created in this context, defaults to document
8791 // keepScripts (optional): If true, will include scripts passed in the html string
8792 jQuery.parseHTML = function( data, context, keepScripts ) {
8793         if ( !data || typeof data !== "string" ) {
8794                 return null;
8795         }
8796         if ( typeof context === "boolean" ) {
8797                 keepScripts = context;
8798                 context = false;
8799         }
8800         context = context || document;
8801
8802         var parsed = rsingleTag.exec( data ),
8803                 scripts = !keepScripts && [];
8804
8805         // Single tag
8806         if ( parsed ) {
8807                 return [ context.createElement( parsed[1] ) ];
8808         }
8809
8810         parsed = jQuery.buildFragment( [ data ], context, scripts );
8811
8812         if ( scripts && scripts.length ) {
8813                 jQuery( scripts ).remove();
8814         }
8815
8816         return jQuery.merge( [], parsed.childNodes );
8817 };
8818
8819
8820 // Keep a copy of the old load method
8821 var _load = jQuery.fn.load;
8822
8823 /**
8824  * Load a url into a page
8825  */
8826 jQuery.fn.load = function( url, params, callback ) {
8827         if ( typeof url !== "string" && _load ) {
8828                 return _load.apply( this, arguments );
8829         }
8830
8831         var selector, type, response,
8832                 self = this,
8833                 off = url.indexOf(" ");
8834
8835         if ( off >= 0 ) {
8836                 selector = jQuery.trim( url.slice( off ) );
8837                 url = url.slice( 0, off );
8838         }
8839
8840         // If it's a function
8841         if ( jQuery.isFunction( params ) ) {
8842
8843                 // We assume that it's the callback
8844                 callback = params;
8845                 params = undefined;
8846
8847         // Otherwise, build a param string
8848         } else if ( params && typeof params === "object" ) {
8849                 type = "POST";
8850         }
8851
8852         // If we have elements to modify, make the request
8853         if ( self.length > 0 ) {
8854                 jQuery.ajax({
8855                         url: url,
8856
8857                         // if "type" variable is undefined, then "GET" method will be used
8858                         type: type,
8859                         dataType: "html",
8860                         data: params
8861                 }).done(function( responseText ) {
8862
8863                         // Save response for use in complete callback
8864                         response = arguments;
8865
8866                         self.html( selector ?
8867
8868                                 // If a selector was specified, locate the right elements in a dummy div
8869                                 // Exclude scripts to avoid IE 'Permission Denied' errors
8870                                 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
8871
8872                                 // Otherwise use the full result
8873                                 responseText );
8874
8875                 }).complete( callback && function( jqXHR, status ) {
8876                         self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
8877                 });
8878         }
8879
8880         return this;
8881 };
8882
8883
8884
8885
8886 jQuery.expr.filters.animated = function( elem ) {
8887         return jQuery.grep(jQuery.timers, function( fn ) {
8888                 return elem === fn.elem;
8889         }).length;
8890 };
8891
8892
8893
8894
8895 var docElem = window.document.documentElement;
8896
8897 /**
8898  * Gets a window from an element
8899  */
8900 function getWindow( elem ) {
8901         return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
8902 }
8903
8904 jQuery.offset = {
8905         setOffset: function( elem, options, i ) {
8906                 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
8907                         position = jQuery.css( elem, "position" ),
8908                         curElem = jQuery( elem ),
8909                         props = {};
8910
8911                 // Set position first, in-case top/left are set even on static elem
8912                 if ( position === "static" ) {
8913                         elem.style.position = "relative";
8914                 }
8915
8916                 curOffset = curElem.offset();
8917                 curCSSTop = jQuery.css( elem, "top" );
8918                 curCSSLeft = jQuery.css( elem, "left" );
8919                 calculatePosition = ( position === "absolute" || position === "fixed" ) &&
8920                         ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
8921
8922                 // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
8923                 if ( calculatePosition ) {
8924                         curPosition = curElem.position();
8925                         curTop = curPosition.top;
8926                         curLeft = curPosition.left;
8927
8928                 } else {
8929                         curTop = parseFloat( curCSSTop ) || 0;
8930                         curLeft = parseFloat( curCSSLeft ) || 0;
8931                 }
8932
8933                 if ( jQuery.isFunction( options ) ) {
8934                         options = options.call( elem, i, curOffset );
8935                 }
8936
8937                 if ( options.top != null ) {
8938                         props.top = ( options.top - curOffset.top ) + curTop;
8939                 }
8940                 if ( options.left != null ) {
8941                         props.left = ( options.left - curOffset.left ) + curLeft;
8942                 }
8943
8944                 if ( "using" in options ) {
8945                         options.using.call( elem, props );
8946
8947                 } else {
8948                         curElem.css( props );
8949                 }
8950         }
8951 };
8952
8953 jQuery.fn.extend({
8954         offset: function( options ) {
8955                 if ( arguments.length ) {
8956                         return options === undefined ?
8957                                 this :
8958                                 this.each(function( i ) {
8959                                         jQuery.offset.setOffset( this, options, i );
8960                                 });
8961                 }
8962
8963                 var docElem, win,
8964                         elem = this[ 0 ],
8965                         box = { top: 0, left: 0 },
8966                         doc = elem && elem.ownerDocument;
8967
8968                 if ( !doc ) {
8969                         return;
8970                 }
8971
8972                 docElem = doc.documentElement;
8973
8974                 // Make sure it's not a disconnected DOM node
8975                 if ( !jQuery.contains( docElem, elem ) ) {
8976                         return box;
8977                 }
8978
8979                 // If we don't have gBCR, just use 0,0 rather than error
8980                 // BlackBerry 5, iOS 3 (original iPhone)
8981                 if ( typeof elem.getBoundingClientRect !== strundefined ) {
8982                         box = elem.getBoundingClientRect();
8983                 }
8984                 win = getWindow( doc );
8985                 return {
8986                         top: box.top + win.pageYOffset - docElem.clientTop,
8987                         left: box.left + win.pageXOffset - docElem.clientLeft
8988                 };
8989         },
8990
8991         position: function() {
8992                 if ( !this[ 0 ] ) {
8993                         return;
8994                 }
8995
8996                 var offsetParent, offset,
8997                         elem = this[ 0 ],
8998                         parentOffset = { top: 0, left: 0 };
8999
9000                 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
9001                 if ( jQuery.css( elem, "position" ) === "fixed" ) {
9002                         // We assume that getBoundingClientRect is available when computed position is fixed
9003                         offset = elem.getBoundingClientRect();
9004
9005                 } else {
9006                         // Get *real* offsetParent
9007                         offsetParent = this.offsetParent();
9008
9009                         // Get correct offsets
9010                         offset = this.offset();
9011                         if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9012                                 parentOffset = offsetParent.offset();
9013                         }
9014
9015                         // Add offsetParent borders
9016                         parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9017                         parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9018                 }
9019
9020                 // Subtract parent offsets and element margins
9021                 return {
9022                         top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9023                         left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
9024                 };
9025         },
9026
9027         offsetParent: function() {
9028                 return this.map(function() {
9029                         var offsetParent = this.offsetParent || docElem;
9030
9031                         while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
9032                                 offsetParent = offsetParent.offsetParent;
9033                         }
9034
9035                         return offsetParent || docElem;
9036                 });
9037         }
9038 });
9039
9040 // Create scrollLeft and scrollTop methods
9041 jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
9042         var top = "pageYOffset" === prop;
9043
9044         jQuery.fn[ method ] = function( val ) {
9045                 return access( this, function( elem, method, val ) {
9046                         var win = getWindow( elem );
9047
9048                         if ( val === undefined ) {
9049                                 return win ? win[ prop ] : elem[ method ];
9050                         }
9051
9052                         if ( win ) {
9053                                 win.scrollTo(
9054                                         !top ? val : window.pageXOffset,
9055                                         top ? val : window.pageYOffset
9056                                 );
9057
9058                         } else {
9059                                 elem[ method ] = val;
9060                         }
9061                 }, method, val, arguments.length, null );
9062         };
9063 });
9064
9065 // Add the top/left cssHooks using jQuery.fn.position
9066 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
9067 // getComputedStyle returns percent when specified for top/left/bottom/right
9068 // rather than make the css module depend on the offset module, we just check for it here
9069 jQuery.each( [ "top", "left" ], function( i, prop ) {
9070         jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
9071                 function( elem, computed ) {
9072                         if ( computed ) {
9073                                 computed = curCSS( elem, prop );
9074                                 // if curCSS returns percentage, fallback to offset
9075                                 return rnumnonpx.test( computed ) ?
9076                                         jQuery( elem ).position()[ prop ] + "px" :
9077                                         computed;
9078                         }
9079                 }
9080         );
9081 });
9082
9083
9084 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9085 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9086         jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9087                 // margin is only for outerHeight, outerWidth
9088                 jQuery.fn[ funcName ] = function( margin, value ) {
9089                         var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9090                                 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9091
9092                         return access( this, function( elem, type, value ) {
9093                                 var doc;
9094
9095                                 if ( jQuery.isWindow( elem ) ) {
9096                                         // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9097                                         // isn't a whole lot we can do. See pull request at this URL for discussion:
9098                                         // https://github.com/jquery/jquery/pull/764
9099                                         return elem.document.documentElement[ "client" + name ];
9100                                 }
9101
9102                                 // Get document width or height
9103                                 if ( elem.nodeType === 9 ) {
9104                                         doc = elem.documentElement;
9105
9106                                         // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
9107                                         // whichever is greatest
9108                                         return Math.max(
9109                                                 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9110                                                 elem.body[ "offset" + name ], doc[ "offset" + name ],
9111                                                 doc[ "client" + name ]
9112                                         );
9113                                 }
9114
9115                                 return value === undefined ?
9116                                         // Get width or height on the element, requesting but not forcing parseFloat
9117                                         jQuery.css( elem, type, extra ) :
9118
9119                                         // Set width or height on the element
9120                                         jQuery.style( elem, type, value, extra );
9121                         }, type, chainable ? margin : undefined, chainable, null );
9122                 };
9123         });
9124 });
9125
9126
9127 // The number of elements contained in the matched element set
9128 jQuery.fn.size = function() {
9129         return this.length;
9130 };
9131
9132 jQuery.fn.andSelf = jQuery.fn.addBack;
9133
9134
9135
9136
9137 // Register as a named AMD module, since jQuery can be concatenated with other
9138 // files that may use define, but not via a proper concatenation script that
9139 // understands anonymous AMD modules. A named AMD is safest and most robust
9140 // way to register. Lowercase jquery is used because AMD module names are
9141 // derived from file names, and jQuery is normally delivered in a lowercase
9142 // file name. Do this after creating the global so that if an AMD module wants
9143 // to call noConflict to hide this version of jQuery, it will work.
9144
9145 // Note that for maximum portability, libraries that are not jQuery should
9146 // declare themselves as anonymous modules, and avoid setting a global if an
9147 // AMD loader is present. jQuery is a special case. For more information, see
9148 // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
9149
9150 if ( typeof define === "function" && define.amd ) {
9151         define( "jquery", [], function() {
9152                 return jQuery;
9153         });
9154 }
9155
9156
9157
9158
9159 var
9160         // Map over jQuery in case of overwrite
9161         _jQuery = window.jQuery,
9162
9163         // Map over the $ in case of overwrite
9164         _$ = window.$;
9165
9166 jQuery.noConflict = function( deep ) {
9167         if ( window.$ === jQuery ) {
9168                 window.$ = _$;
9169         }
9170
9171         if ( deep && window.jQuery === jQuery ) {
9172                 window.jQuery = _jQuery;
9173         }
9174
9175         return jQuery;
9176 };
9177
9178 // Expose jQuery and $ identifiers, even in
9179 // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
9180 // and CommonJS for browser emulators (#13566)
9181 if ( typeof noGlobal === strundefined ) {
9182         window.jQuery = window.$ = jQuery;
9183 }
9184
9185
9186
9187
9188 return jQuery;
9189
9190 }));
9191
9192 /**
9193  * @license AngularJS v1.5.5
9194  * (c) 2010-2016 Google, Inc. http://angularjs.org
9195  * License: MIT
9196  */
9197 (function(window){
9198   var _jQuery = window.jQuery.noConflict(true);
9199
9200 /**
9201  * @description
9202  *
9203  * This object provides a utility for producing rich Error messages within
9204  * Angular. It can be called as follows:
9205  *
9206  * var exampleMinErr = minErr('example');
9207  * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
9208  *
9209  * The above creates an instance of minErr in the example namespace. The
9210  * resulting error will have a namespaced error code of example.one.  The
9211  * resulting error will replace {0} with the value of foo, and {1} with the
9212  * value of bar. The object is not restricted in the number of arguments it can
9213  * take.
9214  *
9215  * If fewer arguments are specified than necessary for interpolation, the extra
9216  * interpolation markers will be preserved in the final string.
9217  *
9218  * Since data will be parsed statically during a build step, some restrictions
9219  * are applied with respect to how minErr instances are created and called.
9220  * Instances should have names of the form namespaceMinErr for a minErr created
9221  * using minErr('namespace') . Error codes, namespaces and template strings
9222  * should all be static strings, not variables or general expressions.
9223  *
9224  * @param {string} module The namespace to use for the new minErr instance.
9225  * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
9226  *   error from returned function, for cases when a particular type of error is useful.
9227  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
9228  */
9229
9230 function minErr(module, ErrorConstructor) {
9231   ErrorConstructor = ErrorConstructor || Error;
9232   return function() {
9233     var SKIP_INDEXES = 2;
9234
9235     var templateArgs = arguments,
9236       code = templateArgs[0],
9237       message = '[' + (module ? module + ':' : '') + code + '] ',
9238       template = templateArgs[1],
9239       paramPrefix, i;
9240
9241     message += template.replace(/\{\d+\}/g, function(match) {
9242       var index = +match.slice(1, -1),
9243         shiftedIndex = index + SKIP_INDEXES;
9244
9245       if (shiftedIndex < templateArgs.length) {
9246         return toDebugString(templateArgs[shiftedIndex]);
9247       }
9248
9249       return match;
9250     });
9251
9252     message += '\nhttp://errors.angularjs.org/1.5.5/' +
9253       (module ? module + '/' : '') + code;
9254
9255     for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
9256       message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
9257         encodeURIComponent(toDebugString(templateArgs[i]));
9258     }
9259
9260     return new ErrorConstructor(message);
9261   };
9262 }
9263
9264 /* We need to tell jshint what variables are being exported */
9265 /* global angular: true,
9266   msie: true,
9267   jqLite: true,
9268   jQuery: true,
9269   slice: true,
9270   splice: true,
9271   push: true,
9272   toString: true,
9273   ngMinErr: true,
9274   angularModule: true,
9275   uid: true,
9276   REGEX_STRING_REGEXP: true,
9277   VALIDITY_STATE_PROPERTY: true,
9278
9279   lowercase: true,
9280   uppercase: true,
9281   manualLowercase: true,
9282   manualUppercase: true,
9283   nodeName_: true,
9284   isArrayLike: true,
9285   forEach: true,
9286   forEachSorted: true,
9287   reverseParams: true,
9288   nextUid: true,
9289   setHashKey: true,
9290   extend: true,
9291   toInt: true,
9292   inherit: true,
9293   merge: true,
9294   noop: true,
9295   identity: true,
9296   valueFn: true,
9297   isUndefined: true,
9298   isDefined: true,
9299   isObject: true,
9300   isBlankObject: true,
9301   isString: true,
9302   isNumber: true,
9303   isDate: true,
9304   isArray: true,
9305   isFunction: true,
9306   isRegExp: true,
9307   isWindow: true,
9308   isScope: true,
9309   isFile: true,
9310   isFormData: true,
9311   isBlob: true,
9312   isBoolean: true,
9313   isPromiseLike: true,
9314   trim: true,
9315   escapeForRegexp: true,
9316   isElement: true,
9317   makeMap: true,
9318   includes: true,
9319   arrayRemove: true,
9320   copy: true,
9321   shallowCopy: true,
9322   equals: true,
9323   csp: true,
9324   jq: true,
9325   concat: true,
9326   sliceArgs: true,
9327   bind: true,
9328   toJsonReplacer: true,
9329   toJson: true,
9330   fromJson: true,
9331   convertTimezoneToLocal: true,
9332   timezoneToOffset: true,
9333   startingTag: true,
9334   tryDecodeURIComponent: true,
9335   parseKeyValue: true,
9336   toKeyValue: true,
9337   encodeUriSegment: true,
9338   encodeUriQuery: true,
9339   angularInit: true,
9340   bootstrap: true,
9341   getTestability: true,
9342   snake_case: true,
9343   bindJQuery: true,
9344   assertArg: true,
9345   assertArgFn: true,
9346   assertNotHasOwnProperty: true,
9347   getter: true,
9348   getBlockNodes: true,
9349   hasOwnProperty: true,
9350   createMap: true,
9351
9352   NODE_TYPE_ELEMENT: true,
9353   NODE_TYPE_ATTRIBUTE: true,
9354   NODE_TYPE_TEXT: true,
9355   NODE_TYPE_COMMENT: true,
9356   NODE_TYPE_DOCUMENT: true,
9357   NODE_TYPE_DOCUMENT_FRAGMENT: true,
9358 */
9359
9360 ////////////////////////////////////
9361
9362 /**
9363  * @ngdoc module
9364  * @name ng
9365  * @module ng
9366  * @installation
9367  * @description
9368  *
9369  * # ng (core module)
9370  * The ng module is loaded by default when an AngularJS application is started. The module itself
9371  * contains the essential components for an AngularJS application to function. The table below
9372  * lists a high level breakdown of each of the services/factories, filters, directives and testing
9373  * components available within this core module.
9374  *
9375  * <div doc-module-components="ng"></div>
9376  */
9377
9378 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
9379
9380 // The name of a form control's ValidityState property.
9381 // This is used so that it's possible for internal tests to create mock ValidityStates.
9382 var VALIDITY_STATE_PROPERTY = 'validity';
9383
9384 var hasOwnProperty = Object.prototype.hasOwnProperty;
9385
9386 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
9387 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
9388
9389
9390 var manualLowercase = function(s) {
9391   /* jshint bitwise: false */
9392   return isString(s)
9393       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
9394       : s;
9395 };
9396 var manualUppercase = function(s) {
9397   /* jshint bitwise: false */
9398   return isString(s)
9399       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
9400       : s;
9401 };
9402
9403
9404 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
9405 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
9406 // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
9407 if ('i' !== 'I'.toLowerCase()) {
9408   lowercase = manualLowercase;
9409   uppercase = manualUppercase;
9410 }
9411
9412
9413 var
9414     msie,             // holds major version number for IE, or NaN if UA is not IE.
9415     jqLite,           // delay binding since jQuery could be loaded after us.
9416     jQuery,           // delay binding
9417     slice             = [].slice,
9418     splice            = [].splice,
9419     push              = [].push,
9420     toString          = Object.prototype.toString,
9421     getPrototypeOf    = Object.getPrototypeOf,
9422     ngMinErr          = minErr('ng'),
9423
9424     /** @name angular */
9425     angular           = window.angular || (window.angular = {}),
9426     angularModule,
9427     uid               = 0;
9428
9429 /**
9430  * documentMode is an IE-only property
9431  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
9432  */
9433 msie = window.document.documentMode;
9434
9435
9436 /**
9437  * @private
9438  * @param {*} obj
9439  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
9440  *                   String ...)
9441  */
9442 function isArrayLike(obj) {
9443
9444   // `null`, `undefined` and `window` are not array-like
9445   if (obj == null || isWindow(obj)) return false;
9446
9447   // arrays, strings and jQuery/jqLite objects are array like
9448   // * jqLite is either the jQuery or jqLite constructor function
9449   // * we have to check the existence of jqLite first as this method is called
9450   //   via the forEach method when constructing the jqLite object in the first place
9451   if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
9452
9453   // Support: iOS 8.2 (not reproducible in simulator)
9454   // "length" in obj used to prevent JIT error (gh-11508)
9455   var length = "length" in Object(obj) && obj.length;
9456
9457   // NodeList objects (with `item` method) and
9458   // other objects with suitable length characteristics are array-like
9459   return isNumber(length) &&
9460     (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
9461
9462 }
9463
9464 /**
9465  * @ngdoc function
9466  * @name angular.forEach
9467  * @module ng
9468  * @kind function
9469  *
9470  * @description
9471  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
9472  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
9473  * is the value of an object property or an array element, `key` is the object property key or
9474  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
9475  *
9476  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
9477  * using the `hasOwnProperty` method.
9478  *
9479  * Unlike ES262's
9480  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
9481  * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
9482  * return the value provided.
9483  *
9484    ```js
9485      var values = {name: 'misko', gender: 'male'};
9486      var log = [];
9487      angular.forEach(values, function(value, key) {
9488        this.push(key + ': ' + value);
9489      }, log);
9490      expect(log).toEqual(['name: misko', 'gender: male']);
9491    ```
9492  *
9493  * @param {Object|Array} obj Object to iterate over.
9494  * @param {Function} iterator Iterator function.
9495  * @param {Object=} context Object to become context (`this`) for the iterator function.
9496  * @returns {Object|Array} Reference to `obj`.
9497  */
9498
9499 function forEach(obj, iterator, context) {
9500   var key, length;
9501   if (obj) {
9502     if (isFunction(obj)) {
9503       for (key in obj) {
9504         // Need to check if hasOwnProperty exists,
9505         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
9506         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
9507           iterator.call(context, obj[key], key, obj);
9508         }
9509       }
9510     } else if (isArray(obj) || isArrayLike(obj)) {
9511       var isPrimitive = typeof obj !== 'object';
9512       for (key = 0, length = obj.length; key < length; key++) {
9513         if (isPrimitive || key in obj) {
9514           iterator.call(context, obj[key], key, obj);
9515         }
9516       }
9517     } else if (obj.forEach && obj.forEach !== forEach) {
9518         obj.forEach(iterator, context, obj);
9519     } else if (isBlankObject(obj)) {
9520       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
9521       for (key in obj) {
9522         iterator.call(context, obj[key], key, obj);
9523       }
9524     } else if (typeof obj.hasOwnProperty === 'function') {
9525       // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
9526       for (key in obj) {
9527         if (obj.hasOwnProperty(key)) {
9528           iterator.call(context, obj[key], key, obj);
9529         }
9530       }
9531     } else {
9532       // Slow path for objects which do not have a method `hasOwnProperty`
9533       for (key in obj) {
9534         if (hasOwnProperty.call(obj, key)) {
9535           iterator.call(context, obj[key], key, obj);
9536         }
9537       }
9538     }
9539   }
9540   return obj;
9541 }
9542
9543 function forEachSorted(obj, iterator, context) {
9544   var keys = Object.keys(obj).sort();
9545   for (var i = 0; i < keys.length; i++) {
9546     iterator.call(context, obj[keys[i]], keys[i]);
9547   }
9548   return keys;
9549 }
9550
9551
9552 /**
9553  * when using forEach the params are value, key, but it is often useful to have key, value.
9554  * @param {function(string, *)} iteratorFn
9555  * @returns {function(*, string)}
9556  */
9557 function reverseParams(iteratorFn) {
9558   return function(value, key) {iteratorFn(key, value);};
9559 }
9560
9561 /**
9562  * A consistent way of creating unique IDs in angular.
9563  *
9564  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
9565  * we hit number precision issues in JavaScript.
9566  *
9567  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
9568  *
9569  * @returns {number} an unique alpha-numeric string
9570  */
9571 function nextUid() {
9572   return ++uid;
9573 }
9574
9575
9576 /**
9577  * Set or clear the hashkey for an object.
9578  * @param obj object
9579  * @param h the hashkey (!truthy to delete the hashkey)
9580  */
9581 function setHashKey(obj, h) {
9582   if (h) {
9583     obj.$$hashKey = h;
9584   } else {
9585     delete obj.$$hashKey;
9586   }
9587 }
9588
9589
9590 function baseExtend(dst, objs, deep) {
9591   var h = dst.$$hashKey;
9592
9593   for (var i = 0, ii = objs.length; i < ii; ++i) {
9594     var obj = objs[i];
9595     if (!isObject(obj) && !isFunction(obj)) continue;
9596     var keys = Object.keys(obj);
9597     for (var j = 0, jj = keys.length; j < jj; j++) {
9598       var key = keys[j];
9599       var src = obj[key];
9600
9601       if (deep && isObject(src)) {
9602         if (isDate(src)) {
9603           dst[key] = new Date(src.valueOf());
9604         } else if (isRegExp(src)) {
9605           dst[key] = new RegExp(src);
9606         } else if (src.nodeName) {
9607           dst[key] = src.cloneNode(true);
9608         } else if (isElement(src)) {
9609           dst[key] = src.clone();
9610         } else {
9611           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
9612           baseExtend(dst[key], [src], true);
9613         }
9614       } else {
9615         dst[key] = src;
9616       }
9617     }
9618   }
9619
9620   setHashKey(dst, h);
9621   return dst;
9622 }
9623
9624 /**
9625  * @ngdoc function
9626  * @name angular.extend
9627  * @module ng
9628  * @kind function
9629  *
9630  * @description
9631  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9632  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9633  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
9634  *
9635  * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
9636  * {@link angular.merge} for this.
9637  *
9638  * @param {Object} dst Destination object.
9639  * @param {...Object} src Source object(s).
9640  * @returns {Object} Reference to `dst`.
9641  */
9642 function extend(dst) {
9643   return baseExtend(dst, slice.call(arguments, 1), false);
9644 }
9645
9646
9647 /**
9648 * @ngdoc function
9649 * @name angular.merge
9650 * @module ng
9651 * @kind function
9652 *
9653 * @description
9654 * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9655 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9656 * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
9657 *
9658 * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
9659 * objects, performing a deep copy.
9660 *
9661 * @param {Object} dst Destination object.
9662 * @param {...Object} src Source object(s).
9663 * @returns {Object} Reference to `dst`.
9664 */
9665 function merge(dst) {
9666   return baseExtend(dst, slice.call(arguments, 1), true);
9667 }
9668
9669
9670
9671 function toInt(str) {
9672   return parseInt(str, 10);
9673 }
9674
9675
9676 function inherit(parent, extra) {
9677   return extend(Object.create(parent), extra);
9678 }
9679
9680 /**
9681  * @ngdoc function
9682  * @name angular.noop
9683  * @module ng
9684  * @kind function
9685  *
9686  * @description
9687  * A function that performs no operations. This function can be useful when writing code in the
9688  * functional style.
9689    ```js
9690      function foo(callback) {
9691        var result = calculateResult();
9692        (callback || angular.noop)(result);
9693      }
9694    ```
9695  */
9696 function noop() {}
9697 noop.$inject = [];
9698
9699
9700 /**
9701  * @ngdoc function
9702  * @name angular.identity
9703  * @module ng
9704  * @kind function
9705  *
9706  * @description
9707  * A function that returns its first argument. This function is useful when writing code in the
9708  * functional style.
9709  *
9710    ```js
9711      function transformer(transformationFn, value) {
9712        return (transformationFn || angular.identity)(value);
9713      };
9714    ```
9715   * @param {*} value to be returned.
9716   * @returns {*} the value passed in.
9717  */
9718 function identity($) {return $;}
9719 identity.$inject = [];
9720
9721
9722 function valueFn(value) {return function valueRef() {return value;};}
9723
9724 function hasCustomToString(obj) {
9725   return isFunction(obj.toString) && obj.toString !== toString;
9726 }
9727
9728
9729 /**
9730  * @ngdoc function
9731  * @name angular.isUndefined
9732  * @module ng
9733  * @kind function
9734  *
9735  * @description
9736  * Determines if a reference is undefined.
9737  *
9738  * @param {*} value Reference to check.
9739  * @returns {boolean} True if `value` is undefined.
9740  */
9741 function isUndefined(value) {return typeof value === 'undefined';}
9742
9743
9744 /**
9745  * @ngdoc function
9746  * @name angular.isDefined
9747  * @module ng
9748  * @kind function
9749  *
9750  * @description
9751  * Determines if a reference is defined.
9752  *
9753  * @param {*} value Reference to check.
9754  * @returns {boolean} True if `value` is defined.
9755  */
9756 function isDefined(value) {return typeof value !== 'undefined';}
9757
9758
9759 /**
9760  * @ngdoc function
9761  * @name angular.isObject
9762  * @module ng
9763  * @kind function
9764  *
9765  * @description
9766  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
9767  * considered to be objects. Note that JavaScript arrays are objects.
9768  *
9769  * @param {*} value Reference to check.
9770  * @returns {boolean} True if `value` is an `Object` but not `null`.
9771  */
9772 function isObject(value) {
9773   // http://jsperf.com/isobject4
9774   return value !== null && typeof value === 'object';
9775 }
9776
9777
9778 /**
9779  * Determine if a value is an object with a null prototype
9780  *
9781  * @returns {boolean} True if `value` is an `Object` with a null prototype
9782  */
9783 function isBlankObject(value) {
9784   return value !== null && typeof value === 'object' && !getPrototypeOf(value);
9785 }
9786
9787
9788 /**
9789  * @ngdoc function
9790  * @name angular.isString
9791  * @module ng
9792  * @kind function
9793  *
9794  * @description
9795  * Determines if a reference is a `String`.
9796  *
9797  * @param {*} value Reference to check.
9798  * @returns {boolean} True if `value` is a `String`.
9799  */
9800 function isString(value) {return typeof value === 'string';}
9801
9802
9803 /**
9804  * @ngdoc function
9805  * @name angular.isNumber
9806  * @module ng
9807  * @kind function
9808  *
9809  * @description
9810  * Determines if a reference is a `Number`.
9811  *
9812  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
9813  *
9814  * If you wish to exclude these then you can use the native
9815  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
9816  * method.
9817  *
9818  * @param {*} value Reference to check.
9819  * @returns {boolean} True if `value` is a `Number`.
9820  */
9821 function isNumber(value) {return typeof value === 'number';}
9822
9823
9824 /**
9825  * @ngdoc function
9826  * @name angular.isDate
9827  * @module ng
9828  * @kind function
9829  *
9830  * @description
9831  * Determines if a value is a date.
9832  *
9833  * @param {*} value Reference to check.
9834  * @returns {boolean} True if `value` is a `Date`.
9835  */
9836 function isDate(value) {
9837   return toString.call(value) === '[object Date]';
9838 }
9839
9840
9841 /**
9842  * @ngdoc function
9843  * @name angular.isArray
9844  * @module ng
9845  * @kind function
9846  *
9847  * @description
9848  * Determines if a reference is an `Array`.
9849  *
9850  * @param {*} value Reference to check.
9851  * @returns {boolean} True if `value` is an `Array`.
9852  */
9853 var isArray = Array.isArray;
9854
9855 /**
9856  * @ngdoc function
9857  * @name angular.isFunction
9858  * @module ng
9859  * @kind function
9860  *
9861  * @description
9862  * Determines if a reference is a `Function`.
9863  *
9864  * @param {*} value Reference to check.
9865  * @returns {boolean} True if `value` is a `Function`.
9866  */
9867 function isFunction(value) {return typeof value === 'function';}
9868
9869
9870 /**
9871  * Determines if a value is a regular expression object.
9872  *
9873  * @private
9874  * @param {*} value Reference to check.
9875  * @returns {boolean} True if `value` is a `RegExp`.
9876  */
9877 function isRegExp(value) {
9878   return toString.call(value) === '[object RegExp]';
9879 }
9880
9881
9882 /**
9883  * Checks if `obj` is a window object.
9884  *
9885  * @private
9886  * @param {*} obj Object to check
9887  * @returns {boolean} True if `obj` is a window obj.
9888  */
9889 function isWindow(obj) {
9890   return obj && obj.window === obj;
9891 }
9892
9893
9894 function isScope(obj) {
9895   return obj && obj.$evalAsync && obj.$watch;
9896 }
9897
9898
9899 function isFile(obj) {
9900   return toString.call(obj) === '[object File]';
9901 }
9902
9903
9904 function isFormData(obj) {
9905   return toString.call(obj) === '[object FormData]';
9906 }
9907
9908
9909 function isBlob(obj) {
9910   return toString.call(obj) === '[object Blob]';
9911 }
9912
9913
9914 function isBoolean(value) {
9915   return typeof value === 'boolean';
9916 }
9917
9918
9919 function isPromiseLike(obj) {
9920   return obj && isFunction(obj.then);
9921 }
9922
9923
9924 var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
9925 function isTypedArray(value) {
9926   return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
9927 }
9928
9929 function isArrayBuffer(obj) {
9930   return toString.call(obj) === '[object ArrayBuffer]';
9931 }
9932
9933
9934 var trim = function(value) {
9935   return isString(value) ? value.trim() : value;
9936 };
9937
9938 // Copied from:
9939 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
9940 // Prereq: s is a string.
9941 var escapeForRegexp = function(s) {
9942   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
9943            replace(/\x08/g, '\\x08');
9944 };
9945
9946
9947 /**
9948  * @ngdoc function
9949  * @name angular.isElement
9950  * @module ng
9951  * @kind function
9952  *
9953  * @description
9954  * Determines if a reference is a DOM element (or wrapped jQuery element).
9955  *
9956  * @param {*} value Reference to check.
9957  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
9958  */
9959 function isElement(node) {
9960   return !!(node &&
9961     (node.nodeName  // we are a direct element
9962     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
9963 }
9964
9965 /**
9966  * @param str 'key1,key2,...'
9967  * @returns {object} in the form of {key1:true, key2:true, ...}
9968  */
9969 function makeMap(str) {
9970   var obj = {}, items = str.split(','), i;
9971   for (i = 0; i < items.length; i++) {
9972     obj[items[i]] = true;
9973   }
9974   return obj;
9975 }
9976
9977
9978 function nodeName_(element) {
9979   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
9980 }
9981
9982 function includes(array, obj) {
9983   return Array.prototype.indexOf.call(array, obj) != -1;
9984 }
9985
9986 function arrayRemove(array, value) {
9987   var index = array.indexOf(value);
9988   if (index >= 0) {
9989     array.splice(index, 1);
9990   }
9991   return index;
9992 }
9993
9994 /**
9995  * @ngdoc function
9996  * @name angular.copy
9997  * @module ng
9998  * @kind function
9999  *
10000  * @description
10001  * Creates a deep copy of `source`, which should be an object or an array.
10002  *
10003  * * If no destination is supplied, a copy of the object or array is created.
10004  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
10005  *   are deleted and then all elements/properties from the source are copied to it.
10006  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
10007  * * If `source` is identical to 'destination' an exception will be thrown.
10008  *
10009  * @param {*} source The source that will be used to make a copy.
10010  *                   Can be any type, including primitives, `null`, and `undefined`.
10011  * @param {(Object|Array)=} destination Destination into which the source is copied. If
10012  *     provided, must be of the same type as `source`.
10013  * @returns {*} The copy or updated `destination`, if `destination` was specified.
10014  *
10015  * @example
10016  <example module="copyExample">
10017  <file name="index.html">
10018  <div ng-controller="ExampleController">
10019  <form novalidate class="simple-form">
10020  Name: <input type="text" ng-model="user.name" /><br />
10021  E-mail: <input type="email" ng-model="user.email" /><br />
10022  Gender: <input type="radio" ng-model="user.gender" value="male" />male
10023  <input type="radio" ng-model="user.gender" value="female" />female<br />
10024  <button ng-click="reset()">RESET</button>
10025  <button ng-click="update(user)">SAVE</button>
10026  </form>
10027  <pre>form = {{user | json}}</pre>
10028  <pre>master = {{master | json}}</pre>
10029  </div>
10030
10031  <script>
10032   angular.module('copyExample', [])
10033     .controller('ExampleController', ['$scope', function($scope) {
10034       $scope.master= {};
10035
10036       $scope.update = function(user) {
10037         // Example with 1 argument
10038         $scope.master= angular.copy(user);
10039       };
10040
10041       $scope.reset = function() {
10042         // Example with 2 arguments
10043         angular.copy($scope.master, $scope.user);
10044       };
10045
10046       $scope.reset();
10047     }]);
10048  </script>
10049  </file>
10050  </example>
10051  */
10052 function copy(source, destination) {
10053   var stackSource = [];
10054   var stackDest = [];
10055
10056   if (destination) {
10057     if (isTypedArray(destination) || isArrayBuffer(destination)) {
10058       throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
10059     }
10060     if (source === destination) {
10061       throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
10062     }
10063
10064     // Empty the destination object
10065     if (isArray(destination)) {
10066       destination.length = 0;
10067     } else {
10068       forEach(destination, function(value, key) {
10069         if (key !== '$$hashKey') {
10070           delete destination[key];
10071         }
10072       });
10073     }
10074
10075     stackSource.push(source);
10076     stackDest.push(destination);
10077     return copyRecurse(source, destination);
10078   }
10079
10080   return copyElement(source);
10081
10082   function copyRecurse(source, destination) {
10083     var h = destination.$$hashKey;
10084     var key;
10085     if (isArray(source)) {
10086       for (var i = 0, ii = source.length; i < ii; i++) {
10087         destination.push(copyElement(source[i]));
10088       }
10089     } else if (isBlankObject(source)) {
10090       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
10091       for (key in source) {
10092         destination[key] = copyElement(source[key]);
10093       }
10094     } else if (source && typeof source.hasOwnProperty === 'function') {
10095       // Slow path, which must rely on hasOwnProperty
10096       for (key in source) {
10097         if (source.hasOwnProperty(key)) {
10098           destination[key] = copyElement(source[key]);
10099         }
10100       }
10101     } else {
10102       // Slowest path --- hasOwnProperty can't be called as a method
10103       for (key in source) {
10104         if (hasOwnProperty.call(source, key)) {
10105           destination[key] = copyElement(source[key]);
10106         }
10107       }
10108     }
10109     setHashKey(destination, h);
10110     return destination;
10111   }
10112
10113   function copyElement(source) {
10114     // Simple values
10115     if (!isObject(source)) {
10116       return source;
10117     }
10118
10119     // Already copied values
10120     var index = stackSource.indexOf(source);
10121     if (index !== -1) {
10122       return stackDest[index];
10123     }
10124
10125     if (isWindow(source) || isScope(source)) {
10126       throw ngMinErr('cpws',
10127         "Can't copy! Making copies of Window or Scope instances is not supported.");
10128     }
10129
10130     var needsRecurse = false;
10131     var destination = copyType(source);
10132
10133     if (destination === undefined) {
10134       destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
10135       needsRecurse = true;
10136     }
10137
10138     stackSource.push(source);
10139     stackDest.push(destination);
10140
10141     return needsRecurse
10142       ? copyRecurse(source, destination)
10143       : destination;
10144   }
10145
10146   function copyType(source) {
10147     switch (toString.call(source)) {
10148       case '[object Int8Array]':
10149       case '[object Int16Array]':
10150       case '[object Int32Array]':
10151       case '[object Float32Array]':
10152       case '[object Float64Array]':
10153       case '[object Uint8Array]':
10154       case '[object Uint8ClampedArray]':
10155       case '[object Uint16Array]':
10156       case '[object Uint32Array]':
10157         return new source.constructor(copyElement(source.buffer));
10158
10159       case '[object ArrayBuffer]':
10160         //Support: IE10
10161         if (!source.slice) {
10162           var copied = new ArrayBuffer(source.byteLength);
10163           new Uint8Array(copied).set(new Uint8Array(source));
10164           return copied;
10165         }
10166         return source.slice(0);
10167
10168       case '[object Boolean]':
10169       case '[object Number]':
10170       case '[object String]':
10171       case '[object Date]':
10172         return new source.constructor(source.valueOf());
10173
10174       case '[object RegExp]':
10175         var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10176         re.lastIndex = source.lastIndex;
10177         return re;
10178
10179       case '[object Blob]':
10180         return new source.constructor([source], {type: source.type});
10181     }
10182
10183     if (isFunction(source.cloneNode)) {
10184       return source.cloneNode(true);
10185     }
10186   }
10187 }
10188
10189 /**
10190  * Creates a shallow copy of an object, an array or a primitive.
10191  *
10192  * Assumes that there are no proto properties for objects.
10193  */
10194 function shallowCopy(src, dst) {
10195   if (isArray(src)) {
10196     dst = dst || [];
10197
10198     for (var i = 0, ii = src.length; i < ii; i++) {
10199       dst[i] = src[i];
10200     }
10201   } else if (isObject(src)) {
10202     dst = dst || {};
10203
10204     for (var key in src) {
10205       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
10206         dst[key] = src[key];
10207       }
10208     }
10209   }
10210
10211   return dst || src;
10212 }
10213
10214
10215 /**
10216  * @ngdoc function
10217  * @name angular.equals
10218  * @module ng
10219  * @kind function
10220  *
10221  * @description
10222  * Determines if two objects or two values are equivalent. Supports value types, regular
10223  * expressions, arrays and objects.
10224  *
10225  * Two objects or values are considered equivalent if at least one of the following is true:
10226  *
10227  * * Both objects or values pass `===` comparison.
10228  * * Both objects or values are of the same type and all of their properties are equal by
10229  *   comparing them with `angular.equals`.
10230  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
10231  * * Both values represent the same regular expression (In JavaScript,
10232  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
10233  *   representation matches).
10234  *
10235  * During a property comparison, properties of `function` type and properties with names
10236  * that begin with `$` are ignored.
10237  *
10238  * Scope and DOMWindow objects are being compared only by identify (`===`).
10239  *
10240  * @param {*} o1 Object or value to compare.
10241  * @param {*} o2 Object or value to compare.
10242  * @returns {boolean} True if arguments are equal.
10243  *
10244  * @example
10245    <example module="equalsExample" name="equalsExample">
10246      <file name="index.html">
10247       <div ng-controller="ExampleController">
10248         <form novalidate>
10249           <h3>User 1</h3>
10250           Name: <input type="text" ng-model="user1.name">
10251           Age: <input type="number" ng-model="user1.age">
10252
10253           <h3>User 2</h3>
10254           Name: <input type="text" ng-model="user2.name">
10255           Age: <input type="number" ng-model="user2.age">
10256
10257           <div>
10258             <br/>
10259             <input type="button" value="Compare" ng-click="compare()">
10260           </div>
10261           User 1: <pre>{{user1 | json}}</pre>
10262           User 2: <pre>{{user2 | json}}</pre>
10263           Equal: <pre>{{result}}</pre>
10264         </form>
10265       </div>
10266     </file>
10267     <file name="script.js">
10268         angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
10269           $scope.user1 = {};
10270           $scope.user2 = {};
10271           $scope.result;
10272           $scope.compare = function() {
10273             $scope.result = angular.equals($scope.user1, $scope.user2);
10274           };
10275         }]);
10276     </file>
10277   </example>
10278  */
10279 function equals(o1, o2) {
10280   if (o1 === o2) return true;
10281   if (o1 === null || o2 === null) return false;
10282   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
10283   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
10284   if (t1 == t2 && t1 == 'object') {
10285     if (isArray(o1)) {
10286       if (!isArray(o2)) return false;
10287       if ((length = o1.length) == o2.length) {
10288         for (key = 0; key < length; key++) {
10289           if (!equals(o1[key], o2[key])) return false;
10290         }
10291         return true;
10292       }
10293     } else if (isDate(o1)) {
10294       if (!isDate(o2)) return false;
10295       return equals(o1.getTime(), o2.getTime());
10296     } else if (isRegExp(o1)) {
10297       if (!isRegExp(o2)) return false;
10298       return o1.toString() == o2.toString();
10299     } else {
10300       if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
10301         isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
10302       keySet = createMap();
10303       for (key in o1) {
10304         if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10305         if (!equals(o1[key], o2[key])) return false;
10306         keySet[key] = true;
10307       }
10308       for (key in o2) {
10309         if (!(key in keySet) &&
10310             key.charAt(0) !== '$' &&
10311             isDefined(o2[key]) &&
10312             !isFunction(o2[key])) return false;
10313       }
10314       return true;
10315     }
10316   }
10317   return false;
10318 }
10319
10320 var csp = function() {
10321   if (!isDefined(csp.rules)) {
10322
10323
10324     var ngCspElement = (window.document.querySelector('[ng-csp]') ||
10325                     window.document.querySelector('[data-ng-csp]'));
10326
10327     if (ngCspElement) {
10328       var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
10329                     ngCspElement.getAttribute('data-ng-csp');
10330       csp.rules = {
10331         noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
10332         noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
10333       };
10334     } else {
10335       csp.rules = {
10336         noUnsafeEval: noUnsafeEval(),
10337         noInlineStyle: false
10338       };
10339     }
10340   }
10341
10342   return csp.rules;
10343
10344   function noUnsafeEval() {
10345     try {
10346       /* jshint -W031, -W054 */
10347       new Function('');
10348       /* jshint +W031, +W054 */
10349       return false;
10350     } catch (e) {
10351       return true;
10352     }
10353   }
10354 };
10355
10356 /**
10357  * @ngdoc directive
10358  * @module ng
10359  * @name ngJq
10360  *
10361  * @element ANY
10362  * @param {string=} ngJq the name of the library available under `window`
10363  * to be used for angular.element
10364  * @description
10365  * Use this directive to force the angular.element library.  This should be
10366  * used to force either jqLite by leaving ng-jq blank or setting the name of
10367  * the jquery variable under window (eg. jQuery).
10368  *
10369  * Since angular looks for this directive when it is loaded (doesn't wait for the
10370  * DOMContentLoaded event), it must be placed on an element that comes before the script
10371  * which loads angular. Also, only the first instance of `ng-jq` will be used and all
10372  * others ignored.
10373  *
10374  * @example
10375  * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
10376  ```html
10377  <!doctype html>
10378  <html ng-app ng-jq>
10379  ...
10380  ...
10381  </html>
10382  ```
10383  * @example
10384  * This example shows how to use a jQuery based library of a different name.
10385  * The library name must be available at the top most 'window'.
10386  ```html
10387  <!doctype html>
10388  <html ng-app ng-jq="jQueryLib">
10389  ...
10390  ...
10391  </html>
10392  ```
10393  */
10394 var jq = function() {
10395   if (isDefined(jq.name_)) return jq.name_;
10396   var el;
10397   var i, ii = ngAttrPrefixes.length, prefix, name;
10398   for (i = 0; i < ii; ++i) {
10399     prefix = ngAttrPrefixes[i];
10400     if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
10401       name = el.getAttribute(prefix + 'jq');
10402       break;
10403     }
10404   }
10405
10406   return (jq.name_ = name);
10407 };
10408
10409 function concat(array1, array2, index) {
10410   return array1.concat(slice.call(array2, index));
10411 }
10412
10413 function sliceArgs(args, startIndex) {
10414   return slice.call(args, startIndex || 0);
10415 }
10416
10417
10418 /* jshint -W101 */
10419 /**
10420  * @ngdoc function
10421  * @name angular.bind
10422  * @module ng
10423  * @kind function
10424  *
10425  * @description
10426  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
10427  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
10428  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
10429  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
10430  *
10431  * @param {Object} self Context which `fn` should be evaluated in.
10432  * @param {function()} fn Function to be bound.
10433  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
10434  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
10435  */
10436 /* jshint +W101 */
10437 function bind(self, fn) {
10438   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
10439   if (isFunction(fn) && !(fn instanceof RegExp)) {
10440     return curryArgs.length
10441       ? function() {
10442           return arguments.length
10443             ? fn.apply(self, concat(curryArgs, arguments, 0))
10444             : fn.apply(self, curryArgs);
10445         }
10446       : function() {
10447           return arguments.length
10448             ? fn.apply(self, arguments)
10449             : fn.call(self);
10450         };
10451   } else {
10452     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
10453     return fn;
10454   }
10455 }
10456
10457
10458 function toJsonReplacer(key, value) {
10459   var val = value;
10460
10461   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
10462     val = undefined;
10463   } else if (isWindow(value)) {
10464     val = '$WINDOW';
10465   } else if (value &&  window.document === value) {
10466     val = '$DOCUMENT';
10467   } else if (isScope(value)) {
10468     val = '$SCOPE';
10469   }
10470
10471   return val;
10472 }
10473
10474
10475 /**
10476  * @ngdoc function
10477  * @name angular.toJson
10478  * @module ng
10479  * @kind function
10480  *
10481  * @description
10482  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
10483  * stripped since angular uses this notation internally.
10484  *
10485  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
10486  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
10487  *    If set to an integer, the JSON output will contain that many spaces per indentation.
10488  * @returns {string|undefined} JSON-ified string representing `obj`.
10489  */
10490 function toJson(obj, pretty) {
10491   if (isUndefined(obj)) return undefined;
10492   if (!isNumber(pretty)) {
10493     pretty = pretty ? 2 : null;
10494   }
10495   return JSON.stringify(obj, toJsonReplacer, pretty);
10496 }
10497
10498
10499 /**
10500  * @ngdoc function
10501  * @name angular.fromJson
10502  * @module ng
10503  * @kind function
10504  *
10505  * @description
10506  * Deserializes a JSON string.
10507  *
10508  * @param {string} json JSON string to deserialize.
10509  * @returns {Object|Array|string|number} Deserialized JSON string.
10510  */
10511 function fromJson(json) {
10512   return isString(json)
10513       ? JSON.parse(json)
10514       : json;
10515 }
10516
10517
10518 var ALL_COLONS = /:/g;
10519 function timezoneToOffset(timezone, fallback) {
10520   // IE/Edge do not "understand" colon (`:`) in timezone
10521   timezone = timezone.replace(ALL_COLONS, '');
10522   var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
10523   return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
10524 }
10525
10526
10527 function addDateMinutes(date, minutes) {
10528   date = new Date(date.getTime());
10529   date.setMinutes(date.getMinutes() + minutes);
10530   return date;
10531 }
10532
10533
10534 function convertTimezoneToLocal(date, timezone, reverse) {
10535   reverse = reverse ? -1 : 1;
10536   var dateTimezoneOffset = date.getTimezoneOffset();
10537   var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
10538   return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
10539 }
10540
10541
10542 /**
10543  * @returns {string} Returns the string representation of the element.
10544  */
10545 function startingTag(element) {
10546   element = jqLite(element).clone();
10547   try {
10548     // turns out IE does not let you set .html() on elements which
10549     // are not allowed to have children. So we just ignore it.
10550     element.empty();
10551   } catch (e) {}
10552   var elemHtml = jqLite('<div>').append(element).html();
10553   try {
10554     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
10555         elemHtml.
10556           match(/^(<[^>]+>)/)[1].
10557           replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
10558   } catch (e) {
10559     return lowercase(elemHtml);
10560   }
10561
10562 }
10563
10564
10565 /////////////////////////////////////////////////
10566
10567 /**
10568  * Tries to decode the URI component without throwing an exception.
10569  *
10570  * @private
10571  * @param str value potential URI component to check.
10572  * @returns {boolean} True if `value` can be decoded
10573  * with the decodeURIComponent function.
10574  */
10575 function tryDecodeURIComponent(value) {
10576   try {
10577     return decodeURIComponent(value);
10578   } catch (e) {
10579     // Ignore any invalid uri component
10580   }
10581 }
10582
10583
10584 /**
10585  * Parses an escaped url query string into key-value pairs.
10586  * @returns {Object.<string,boolean|Array>}
10587  */
10588 function parseKeyValue(/**string*/keyValue) {
10589   var obj = {};
10590   forEach((keyValue || "").split('&'), function(keyValue) {
10591     var splitPoint, key, val;
10592     if (keyValue) {
10593       key = keyValue = keyValue.replace(/\+/g,'%20');
10594       splitPoint = keyValue.indexOf('=');
10595       if (splitPoint !== -1) {
10596         key = keyValue.substring(0, splitPoint);
10597         val = keyValue.substring(splitPoint + 1);
10598       }
10599       key = tryDecodeURIComponent(key);
10600       if (isDefined(key)) {
10601         val = isDefined(val) ? tryDecodeURIComponent(val) : true;
10602         if (!hasOwnProperty.call(obj, key)) {
10603           obj[key] = val;
10604         } else if (isArray(obj[key])) {
10605           obj[key].push(val);
10606         } else {
10607           obj[key] = [obj[key],val];
10608         }
10609       }
10610     }
10611   });
10612   return obj;
10613 }
10614
10615 function toKeyValue(obj) {
10616   var parts = [];
10617   forEach(obj, function(value, key) {
10618     if (isArray(value)) {
10619       forEach(value, function(arrayValue) {
10620         parts.push(encodeUriQuery(key, true) +
10621                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
10622       });
10623     } else {
10624     parts.push(encodeUriQuery(key, true) +
10625                (value === true ? '' : '=' + encodeUriQuery(value, true)));
10626     }
10627   });
10628   return parts.length ? parts.join('&') : '';
10629 }
10630
10631
10632 /**
10633  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
10634  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
10635  * segments:
10636  *    segment       = *pchar
10637  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10638  *    pct-encoded   = "%" HEXDIG HEXDIG
10639  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10640  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10641  *                     / "*" / "+" / "," / ";" / "="
10642  */
10643 function encodeUriSegment(val) {
10644   return encodeUriQuery(val, true).
10645              replace(/%26/gi, '&').
10646              replace(/%3D/gi, '=').
10647              replace(/%2B/gi, '+');
10648 }
10649
10650
10651 /**
10652  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
10653  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
10654  * encoded per http://tools.ietf.org/html/rfc3986:
10655  *    query       = *( pchar / "/" / "?" )
10656  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10657  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10658  *    pct-encoded   = "%" HEXDIG HEXDIG
10659  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10660  *                     / "*" / "+" / "," / ";" / "="
10661  */
10662 function encodeUriQuery(val, pctEncodeSpaces) {
10663   return encodeURIComponent(val).
10664              replace(/%40/gi, '@').
10665              replace(/%3A/gi, ':').
10666              replace(/%24/g, '$').
10667              replace(/%2C/gi, ',').
10668              replace(/%3B/gi, ';').
10669              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
10670 }
10671
10672 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
10673
10674 function getNgAttribute(element, ngAttr) {
10675   var attr, i, ii = ngAttrPrefixes.length;
10676   for (i = 0; i < ii; ++i) {
10677     attr = ngAttrPrefixes[i] + ngAttr;
10678     if (isString(attr = element.getAttribute(attr))) {
10679       return attr;
10680     }
10681   }
10682   return null;
10683 }
10684
10685 /**
10686  * @ngdoc directive
10687  * @name ngApp
10688  * @module ng
10689  *
10690  * @element ANY
10691  * @param {angular.Module} ngApp an optional application
10692  *   {@link angular.module module} name to load.
10693  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
10694  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
10695  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
10696  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
10697  *   tracking down the root of these bugs.
10698  *
10699  * @description
10700  *
10701  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
10702  * designates the **root element** of the application and is typically placed near the root element
10703  * of the page - e.g. on the `<body>` or `<html>` tags.
10704  *
10705  * There are a few things to keep in mind when using `ngApp`:
10706  * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
10707  *   found in the document will be used to define the root element to auto-bootstrap as an
10708  *   application. To run multiple applications in an HTML document you must manually bootstrap them using
10709  *   {@link angular.bootstrap} instead.
10710  * - AngularJS applications cannot be nested within each other.
10711  * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
10712  *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
10713  *   {@link ngRoute.ngView `ngView`}.
10714  *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
10715  *   causing animations to stop working and making the injector inaccessible from outside the app.
10716  *
10717  * You can specify an **AngularJS module** to be used as the root module for the application.  This
10718  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
10719  * should contain the application code needed or have dependencies on other modules that will
10720  * contain the code. See {@link angular.module} for more information.
10721  *
10722  * In the example below if the `ngApp` directive were not placed on the `html` element then the
10723  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
10724  * would not be resolved to `3`.
10725  *
10726  * `ngApp` is the easiest, and most common way to bootstrap an application.
10727  *
10728  <example module="ngAppDemo">
10729    <file name="index.html">
10730    <div ng-controller="ngAppDemoController">
10731      I can add: {{a}} + {{b}} =  {{ a+b }}
10732    </div>
10733    </file>
10734    <file name="script.js">
10735    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
10736      $scope.a = 1;
10737      $scope.b = 2;
10738    });
10739    </file>
10740  </example>
10741  *
10742  * Using `ngStrictDi`, you would see something like this:
10743  *
10744  <example ng-app-included="true">
10745    <file name="index.html">
10746    <div ng-app="ngAppStrictDemo" ng-strict-di>
10747        <div ng-controller="GoodController1">
10748            I can add: {{a}} + {{b}} =  {{ a+b }}
10749
10750            <p>This renders because the controller does not fail to
10751               instantiate, by using explicit annotation style (see
10752               script.js for details)
10753            </p>
10754        </div>
10755
10756        <div ng-controller="GoodController2">
10757            Name: <input ng-model="name"><br />
10758            Hello, {{name}}!
10759
10760            <p>This renders because the controller does not fail to
10761               instantiate, by using explicit annotation style
10762               (see script.js for details)
10763            </p>
10764        </div>
10765
10766        <div ng-controller="BadController">
10767            I can add: {{a}} + {{b}} =  {{ a+b }}
10768
10769            <p>The controller could not be instantiated, due to relying
10770               on automatic function annotations (which are disabled in
10771               strict mode). As such, the content of this section is not
10772               interpolated, and there should be an error in your web console.
10773            </p>
10774        </div>
10775    </div>
10776    </file>
10777    <file name="script.js">
10778    angular.module('ngAppStrictDemo', [])
10779      // BadController will fail to instantiate, due to relying on automatic function annotation,
10780      // rather than an explicit annotation
10781      .controller('BadController', function($scope) {
10782        $scope.a = 1;
10783        $scope.b = 2;
10784      })
10785      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
10786      // due to using explicit annotations using the array style and $inject property, respectively.
10787      .controller('GoodController1', ['$scope', function($scope) {
10788        $scope.a = 1;
10789        $scope.b = 2;
10790      }])
10791      .controller('GoodController2', GoodController2);
10792      function GoodController2($scope) {
10793        $scope.name = "World";
10794      }
10795      GoodController2.$inject = ['$scope'];
10796    </file>
10797    <file name="style.css">
10798    div[ng-controller] {
10799        margin-bottom: 1em;
10800        -webkit-border-radius: 4px;
10801        border-radius: 4px;
10802        border: 1px solid;
10803        padding: .5em;
10804    }
10805    div[ng-controller^=Good] {
10806        border-color: #d6e9c6;
10807        background-color: #dff0d8;
10808        color: #3c763d;
10809    }
10810    div[ng-controller^=Bad] {
10811        border-color: #ebccd1;
10812        background-color: #f2dede;
10813        color: #a94442;
10814        margin-bottom: 0;
10815    }
10816    </file>
10817  </example>
10818  */
10819 function angularInit(element, bootstrap) {
10820   var appElement,
10821       module,
10822       config = {};
10823
10824   // The element `element` has priority over any other element
10825   forEach(ngAttrPrefixes, function(prefix) {
10826     var name = prefix + 'app';
10827
10828     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
10829       appElement = element;
10830       module = element.getAttribute(name);
10831     }
10832   });
10833   forEach(ngAttrPrefixes, function(prefix) {
10834     var name = prefix + 'app';
10835     var candidate;
10836
10837     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
10838       appElement = candidate;
10839       module = candidate.getAttribute(name);
10840     }
10841   });
10842   if (appElement) {
10843     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
10844     bootstrap(appElement, module ? [module] : [], config);
10845   }
10846 }
10847
10848 /**
10849  * @ngdoc function
10850  * @name angular.bootstrap
10851  * @module ng
10852  * @description
10853  * Use this function to manually start up angular application.
10854  *
10855  * For more information, see the {@link guide/bootstrap Bootstrap guide}.
10856  *
10857  * Angular will detect if it has been loaded into the browser more than once and only allow the
10858  * first loaded script to be bootstrapped and will report a warning to the browser console for
10859  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
10860  * multiple instances of Angular try to work on the DOM.
10861  *
10862  * <div class="alert alert-warning">
10863  * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
10864  * They must use {@link ng.directive:ngApp ngApp}.
10865  * </div>
10866  *
10867  * <div class="alert alert-warning">
10868  * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
10869  * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
10870  * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
10871  * causing animations to stop working and making the injector inaccessible from outside the app.
10872  * </div>
10873  *
10874  * ```html
10875  * <!doctype html>
10876  * <html>
10877  * <body>
10878  * <div ng-controller="WelcomeController">
10879  *   {{greeting}}
10880  * </div>
10881  *
10882  * <script src="angular.js"></script>
10883  * <script>
10884  *   var app = angular.module('demo', [])
10885  *   .controller('WelcomeController', function($scope) {
10886  *       $scope.greeting = 'Welcome!';
10887  *   });
10888  *   angular.bootstrap(document, ['demo']);
10889  * </script>
10890  * </body>
10891  * </html>
10892  * ```
10893  *
10894  * @param {DOMElement} element DOM element which is the root of angular application.
10895  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
10896  *     Each item in the array should be the name of a predefined module or a (DI annotated)
10897  *     function that will be invoked by the injector as a `config` block.
10898  *     See: {@link angular.module modules}
10899  * @param {Object=} config an object for defining configuration options for the application. The
10900  *     following keys are supported:
10901  *
10902  * * `strictDi` - disable automatic function annotation for the application. This is meant to
10903  *   assist in finding bugs which break minified code. Defaults to `false`.
10904  *
10905  * @returns {auto.$injector} Returns the newly created injector for this app.
10906  */
10907 function bootstrap(element, modules, config) {
10908   if (!isObject(config)) config = {};
10909   var defaultConfig = {
10910     strictDi: false
10911   };
10912   config = extend(defaultConfig, config);
10913   var doBootstrap = function() {
10914     element = jqLite(element);
10915
10916     if (element.injector()) {
10917       var tag = (element[0] === window.document) ? 'document' : startingTag(element);
10918       //Encode angle brackets to prevent input from being sanitized to empty string #8683
10919       throw ngMinErr(
10920           'btstrpd',
10921           "App already bootstrapped with this element '{0}'",
10922           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
10923     }
10924
10925     modules = modules || [];
10926     modules.unshift(['$provide', function($provide) {
10927       $provide.value('$rootElement', element);
10928     }]);
10929
10930     if (config.debugInfoEnabled) {
10931       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
10932       modules.push(['$compileProvider', function($compileProvider) {
10933         $compileProvider.debugInfoEnabled(true);
10934       }]);
10935     }
10936
10937     modules.unshift('ng');
10938     var injector = createInjector(modules, config.strictDi);
10939     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
10940        function bootstrapApply(scope, element, compile, injector) {
10941         scope.$apply(function() {
10942           element.data('$injector', injector);
10943           compile(element)(scope);
10944         });
10945       }]
10946     );
10947     return injector;
10948   };
10949
10950   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
10951   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
10952
10953   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
10954     config.debugInfoEnabled = true;
10955     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
10956   }
10957
10958   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
10959     return doBootstrap();
10960   }
10961
10962   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
10963   angular.resumeBootstrap = function(extraModules) {
10964     forEach(extraModules, function(module) {
10965       modules.push(module);
10966     });
10967     return doBootstrap();
10968   };
10969
10970   if (isFunction(angular.resumeDeferredBootstrap)) {
10971     angular.resumeDeferredBootstrap();
10972   }
10973 }
10974
10975 /**
10976  * @ngdoc function
10977  * @name angular.reloadWithDebugInfo
10978  * @module ng
10979  * @description
10980  * Use this function to reload the current application with debug information turned on.
10981  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
10982  *
10983  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
10984  */
10985 function reloadWithDebugInfo() {
10986   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
10987   window.location.reload();
10988 }
10989
10990 /**
10991  * @name angular.getTestability
10992  * @module ng
10993  * @description
10994  * Get the testability service for the instance of Angular on the given
10995  * element.
10996  * @param {DOMElement} element DOM element which is the root of angular application.
10997  */
10998 function getTestability(rootElement) {
10999   var injector = angular.element(rootElement).injector();
11000   if (!injector) {
11001     throw ngMinErr('test',
11002       'no injector found for element argument to getTestability');
11003   }
11004   return injector.get('$$testability');
11005 }
11006
11007 var SNAKE_CASE_REGEXP = /[A-Z]/g;
11008 function snake_case(name, separator) {
11009   separator = separator || '_';
11010   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
11011     return (pos ? separator : '') + letter.toLowerCase();
11012   });
11013 }
11014
11015 var bindJQueryFired = false;
11016 function bindJQuery() {
11017   var originalCleanData;
11018
11019   if (bindJQueryFired) {
11020     return;
11021   }
11022
11023   // bind to jQuery if present;
11024   var jqName = jq();
11025   jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
11026            !jqName             ? undefined     :   // use jqLite
11027                                  window[jqName];   // use jQuery specified by `ngJq`
11028
11029   // Use jQuery if it exists with proper functionality, otherwise default to us.
11030   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
11031   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
11032   // versions. It will not work for sure with jQuery <1.7, though.
11033   if (jQuery && jQuery.fn.on) {
11034     jqLite = jQuery;
11035     extend(jQuery.fn, {
11036       scope: JQLitePrototype.scope,
11037       isolateScope: JQLitePrototype.isolateScope,
11038       controller: JQLitePrototype.controller,
11039       injector: JQLitePrototype.injector,
11040       inheritedData: JQLitePrototype.inheritedData
11041     });
11042
11043     // All nodes removed from the DOM via various jQuery APIs like .remove()
11044     // are passed through jQuery.cleanData. Monkey-patch this method to fire
11045     // the $destroy event on all removed nodes.
11046     originalCleanData = jQuery.cleanData;
11047     jQuery.cleanData = function(elems) {
11048       var events;
11049       for (var i = 0, elem; (elem = elems[i]) != null; i++) {
11050         events = jQuery._data(elem, "events");
11051         if (events && events.$destroy) {
11052           jQuery(elem).triggerHandler('$destroy');
11053         }
11054       }
11055       originalCleanData(elems);
11056     };
11057   } else {
11058     jqLite = JQLite;
11059   }
11060
11061   angular.element = jqLite;
11062
11063   // Prevent double-proxying.
11064   bindJQueryFired = true;
11065 }
11066
11067 /**
11068  * throw error if the argument is falsy.
11069  */
11070 function assertArg(arg, name, reason) {
11071   if (!arg) {
11072     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
11073   }
11074   return arg;
11075 }
11076
11077 function assertArgFn(arg, name, acceptArrayAnnotation) {
11078   if (acceptArrayAnnotation && isArray(arg)) {
11079       arg = arg[arg.length - 1];
11080   }
11081
11082   assertArg(isFunction(arg), name, 'not a function, got ' +
11083       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
11084   return arg;
11085 }
11086
11087 /**
11088  * throw error if the name given is hasOwnProperty
11089  * @param  {String} name    the name to test
11090  * @param  {String} context the context in which the name is used, such as module or directive
11091  */
11092 function assertNotHasOwnProperty(name, context) {
11093   if (name === 'hasOwnProperty') {
11094     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
11095   }
11096 }
11097
11098 /**
11099  * Return the value accessible from the object by path. Any undefined traversals are ignored
11100  * @param {Object} obj starting object
11101  * @param {String} path path to traverse
11102  * @param {boolean} [bindFnToScope=true]
11103  * @returns {Object} value as accessible by path
11104  */
11105 //TODO(misko): this function needs to be removed
11106 function getter(obj, path, bindFnToScope) {
11107   if (!path) return obj;
11108   var keys = path.split('.');
11109   var key;
11110   var lastInstance = obj;
11111   var len = keys.length;
11112
11113   for (var i = 0; i < len; i++) {
11114     key = keys[i];
11115     if (obj) {
11116       obj = (lastInstance = obj)[key];
11117     }
11118   }
11119   if (!bindFnToScope && isFunction(obj)) {
11120     return bind(lastInstance, obj);
11121   }
11122   return obj;
11123 }
11124
11125 /**
11126  * Return the DOM siblings between the first and last node in the given array.
11127  * @param {Array} array like object
11128  * @returns {Array} the inputted object or a jqLite collection containing the nodes
11129  */
11130 function getBlockNodes(nodes) {
11131   // TODO(perf): update `nodes` instead of creating a new object?
11132   var node = nodes[0];
11133   var endNode = nodes[nodes.length - 1];
11134   var blockNodes;
11135
11136   for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
11137     if (blockNodes || nodes[i] !== node) {
11138       if (!blockNodes) {
11139         blockNodes = jqLite(slice.call(nodes, 0, i));
11140       }
11141       blockNodes.push(node);
11142     }
11143   }
11144
11145   return blockNodes || nodes;
11146 }
11147
11148
11149 /**
11150  * Creates a new object without a prototype. This object is useful for lookup without having to
11151  * guard against prototypically inherited properties via hasOwnProperty.
11152  *
11153  * Related micro-benchmarks:
11154  * - http://jsperf.com/object-create2
11155  * - http://jsperf.com/proto-map-lookup/2
11156  * - http://jsperf.com/for-in-vs-object-keys2
11157  *
11158  * @returns {Object}
11159  */
11160 function createMap() {
11161   return Object.create(null);
11162 }
11163
11164 var NODE_TYPE_ELEMENT = 1;
11165 var NODE_TYPE_ATTRIBUTE = 2;
11166 var NODE_TYPE_TEXT = 3;
11167 var NODE_TYPE_COMMENT = 8;
11168 var NODE_TYPE_DOCUMENT = 9;
11169 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
11170
11171 /**
11172  * @ngdoc type
11173  * @name angular.Module
11174  * @module ng
11175  * @description
11176  *
11177  * Interface for configuring angular {@link angular.module modules}.
11178  */
11179
11180 function setupModuleLoader(window) {
11181
11182   var $injectorMinErr = minErr('$injector');
11183   var ngMinErr = minErr('ng');
11184
11185   function ensure(obj, name, factory) {
11186     return obj[name] || (obj[name] = factory());
11187   }
11188
11189   var angular = ensure(window, 'angular', Object);
11190
11191   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
11192   angular.$$minErr = angular.$$minErr || minErr;
11193
11194   return ensure(angular, 'module', function() {
11195     /** @type {Object.<string, angular.Module>} */
11196     var modules = {};
11197
11198     /**
11199      * @ngdoc function
11200      * @name angular.module
11201      * @module ng
11202      * @description
11203      *
11204      * The `angular.module` is a global place for creating, registering and retrieving Angular
11205      * modules.
11206      * All modules (angular core or 3rd party) that should be available to an application must be
11207      * registered using this mechanism.
11208      *
11209      * Passing one argument retrieves an existing {@link angular.Module},
11210      * whereas passing more than one argument creates a new {@link angular.Module}
11211      *
11212      *
11213      * # Module
11214      *
11215      * A module is a collection of services, directives, controllers, filters, and configuration information.
11216      * `angular.module` is used to configure the {@link auto.$injector $injector}.
11217      *
11218      * ```js
11219      * // Create a new module
11220      * var myModule = angular.module('myModule', []);
11221      *
11222      * // register a new service
11223      * myModule.value('appName', 'MyCoolApp');
11224      *
11225      * // configure existing services inside initialization blocks.
11226      * myModule.config(['$locationProvider', function($locationProvider) {
11227      *   // Configure existing providers
11228      *   $locationProvider.hashPrefix('!');
11229      * }]);
11230      * ```
11231      *
11232      * Then you can create an injector and load your modules like this:
11233      *
11234      * ```js
11235      * var injector = angular.injector(['ng', 'myModule'])
11236      * ```
11237      *
11238      * However it's more likely that you'll just use
11239      * {@link ng.directive:ngApp ngApp} or
11240      * {@link angular.bootstrap} to simplify this process for you.
11241      *
11242      * @param {!string} name The name of the module to create or retrieve.
11243      * @param {!Array.<string>=} requires If specified then new module is being created. If
11244      *        unspecified then the module is being retrieved for further configuration.
11245      * @param {Function=} configFn Optional configuration function for the module. Same as
11246      *        {@link angular.Module#config Module#config()}.
11247      * @returns {angular.Module} new module with the {@link angular.Module} api.
11248      */
11249     return function module(name, requires, configFn) {
11250       var assertNotHasOwnProperty = function(name, context) {
11251         if (name === 'hasOwnProperty') {
11252           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
11253         }
11254       };
11255
11256       assertNotHasOwnProperty(name, 'module');
11257       if (requires && modules.hasOwnProperty(name)) {
11258         modules[name] = null;
11259       }
11260       return ensure(modules, name, function() {
11261         if (!requires) {
11262           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
11263              "the module name or forgot to load it. If registering a module ensure that you " +
11264              "specify the dependencies as the second argument.", name);
11265         }
11266
11267         /** @type {!Array.<Array.<*>>} */
11268         var invokeQueue = [];
11269
11270         /** @type {!Array.<Function>} */
11271         var configBlocks = [];
11272
11273         /** @type {!Array.<Function>} */
11274         var runBlocks = [];
11275
11276         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
11277
11278         /** @type {angular.Module} */
11279         var moduleInstance = {
11280           // Private state
11281           _invokeQueue: invokeQueue,
11282           _configBlocks: configBlocks,
11283           _runBlocks: runBlocks,
11284
11285           /**
11286            * @ngdoc property
11287            * @name angular.Module#requires
11288            * @module ng
11289            *
11290            * @description
11291            * Holds the list of modules which the injector will load before the current module is
11292            * loaded.
11293            */
11294           requires: requires,
11295
11296           /**
11297            * @ngdoc property
11298            * @name angular.Module#name
11299            * @module ng
11300            *
11301            * @description
11302            * Name of the module.
11303            */
11304           name: name,
11305
11306
11307           /**
11308            * @ngdoc method
11309            * @name angular.Module#provider
11310            * @module ng
11311            * @param {string} name service name
11312            * @param {Function} providerType Construction function for creating new instance of the
11313            *                                service.
11314            * @description
11315            * See {@link auto.$provide#provider $provide.provider()}.
11316            */
11317           provider: invokeLaterAndSetModuleName('$provide', 'provider'),
11318
11319           /**
11320            * @ngdoc method
11321            * @name angular.Module#factory
11322            * @module ng
11323            * @param {string} name service name
11324            * @param {Function} providerFunction Function for creating new instance of the service.
11325            * @description
11326            * See {@link auto.$provide#factory $provide.factory()}.
11327            */
11328           factory: invokeLaterAndSetModuleName('$provide', 'factory'),
11329
11330           /**
11331            * @ngdoc method
11332            * @name angular.Module#service
11333            * @module ng
11334            * @param {string} name service name
11335            * @param {Function} constructor A constructor function that will be instantiated.
11336            * @description
11337            * See {@link auto.$provide#service $provide.service()}.
11338            */
11339           service: invokeLaterAndSetModuleName('$provide', 'service'),
11340
11341           /**
11342            * @ngdoc method
11343            * @name angular.Module#value
11344            * @module ng
11345            * @param {string} name service name
11346            * @param {*} object Service instance object.
11347            * @description
11348            * See {@link auto.$provide#value $provide.value()}.
11349            */
11350           value: invokeLater('$provide', 'value'),
11351
11352           /**
11353            * @ngdoc method
11354            * @name angular.Module#constant
11355            * @module ng
11356            * @param {string} name constant name
11357            * @param {*} object Constant value.
11358            * @description
11359            * Because the constants are fixed, they get applied before other provide methods.
11360            * See {@link auto.$provide#constant $provide.constant()}.
11361            */
11362           constant: invokeLater('$provide', 'constant', 'unshift'),
11363
11364            /**
11365            * @ngdoc method
11366            * @name angular.Module#decorator
11367            * @module ng
11368            * @param {string} name The name of the service to decorate.
11369            * @param {Function} decorFn This function will be invoked when the service needs to be
11370            *                           instantiated and should return the decorated service instance.
11371            * @description
11372            * See {@link auto.$provide#decorator $provide.decorator()}.
11373            */
11374           decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
11375
11376           /**
11377            * @ngdoc method
11378            * @name angular.Module#animation
11379            * @module ng
11380            * @param {string} name animation name
11381            * @param {Function} animationFactory Factory function for creating new instance of an
11382            *                                    animation.
11383            * @description
11384            *
11385            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
11386            *
11387            *
11388            * Defines an animation hook that can be later used with
11389            * {@link $animate $animate} service and directives that use this service.
11390            *
11391            * ```js
11392            * module.animation('.animation-name', function($inject1, $inject2) {
11393            *   return {
11394            *     eventName : function(element, done) {
11395            *       //code to run the animation
11396            *       //once complete, then run done()
11397            *       return function cancellationFunction(element) {
11398            *         //code to cancel the animation
11399            *       }
11400            *     }
11401            *   }
11402            * })
11403            * ```
11404            *
11405            * See {@link ng.$animateProvider#register $animateProvider.register()} and
11406            * {@link ngAnimate ngAnimate module} for more information.
11407            */
11408           animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
11409
11410           /**
11411            * @ngdoc method
11412            * @name angular.Module#filter
11413            * @module ng
11414            * @param {string} name Filter name - this must be a valid angular expression identifier
11415            * @param {Function} filterFactory Factory function for creating new instance of filter.
11416            * @description
11417            * See {@link ng.$filterProvider#register $filterProvider.register()}.
11418            *
11419            * <div class="alert alert-warning">
11420            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
11421            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
11422            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
11423            * (`myapp_subsection_filterx`).
11424            * </div>
11425            */
11426           filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
11427
11428           /**
11429            * @ngdoc method
11430            * @name angular.Module#controller
11431            * @module ng
11432            * @param {string|Object} name Controller name, or an object map of controllers where the
11433            *    keys are the names and the values are the constructors.
11434            * @param {Function} constructor Controller constructor function.
11435            * @description
11436            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
11437            */
11438           controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
11439
11440           /**
11441            * @ngdoc method
11442            * @name angular.Module#directive
11443            * @module ng
11444            * @param {string|Object} name Directive name, or an object map of directives where the
11445            *    keys are the names and the values are the factories.
11446            * @param {Function} directiveFactory Factory function for creating new instance of
11447            * directives.
11448            * @description
11449            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
11450            */
11451           directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
11452
11453           /**
11454            * @ngdoc method
11455            * @name angular.Module#component
11456            * @module ng
11457            * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
11458            * @param {Object} options Component definition object (a simplified
11459            *    {@link ng.$compile#directive-definition-object directive definition object})
11460            *
11461            * @description
11462            * See {@link ng.$compileProvider#component $compileProvider.component()}.
11463            */
11464           component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
11465
11466           /**
11467            * @ngdoc method
11468            * @name angular.Module#config
11469            * @module ng
11470            * @param {Function} configFn Execute this function on module load. Useful for service
11471            *    configuration.
11472            * @description
11473            * Use this method to register work which needs to be performed on module loading.
11474            * For more about how to configure services, see
11475            * {@link providers#provider-recipe Provider Recipe}.
11476            */
11477           config: config,
11478
11479           /**
11480            * @ngdoc method
11481            * @name angular.Module#run
11482            * @module ng
11483            * @param {Function} initializationFn Execute this function after injector creation.
11484            *    Useful for application initialization.
11485            * @description
11486            * Use this method to register work which should be performed when the injector is done
11487            * loading all modules.
11488            */
11489           run: function(block) {
11490             runBlocks.push(block);
11491             return this;
11492           }
11493         };
11494
11495         if (configFn) {
11496           config(configFn);
11497         }
11498
11499         return moduleInstance;
11500
11501         /**
11502          * @param {string} provider
11503          * @param {string} method
11504          * @param {String=} insertMethod
11505          * @returns {angular.Module}
11506          */
11507         function invokeLater(provider, method, insertMethod, queue) {
11508           if (!queue) queue = invokeQueue;
11509           return function() {
11510             queue[insertMethod || 'push']([provider, method, arguments]);
11511             return moduleInstance;
11512           };
11513         }
11514
11515         /**
11516          * @param {string} provider
11517          * @param {string} method
11518          * @returns {angular.Module}
11519          */
11520         function invokeLaterAndSetModuleName(provider, method) {
11521           return function(recipeName, factoryFunction) {
11522             if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
11523             invokeQueue.push([provider, method, arguments]);
11524             return moduleInstance;
11525           };
11526         }
11527       });
11528     };
11529   });
11530
11531 }
11532
11533 /* global: toDebugString: true */
11534
11535 function serializeObject(obj) {
11536   var seen = [];
11537
11538   return JSON.stringify(obj, function(key, val) {
11539     val = toJsonReplacer(key, val);
11540     if (isObject(val)) {
11541
11542       if (seen.indexOf(val) >= 0) return '...';
11543
11544       seen.push(val);
11545     }
11546     return val;
11547   });
11548 }
11549
11550 function toDebugString(obj) {
11551   if (typeof obj === 'function') {
11552     return obj.toString().replace(/ \{[\s\S]*$/, '');
11553   } else if (isUndefined(obj)) {
11554     return 'undefined';
11555   } else if (typeof obj !== 'string') {
11556     return serializeObject(obj);
11557   }
11558   return obj;
11559 }
11560
11561 /* global angularModule: true,
11562   version: true,
11563
11564   $CompileProvider,
11565
11566   htmlAnchorDirective,
11567   inputDirective,
11568   inputDirective,
11569   formDirective,
11570   scriptDirective,
11571   selectDirective,
11572   styleDirective,
11573   optionDirective,
11574   ngBindDirective,
11575   ngBindHtmlDirective,
11576   ngBindTemplateDirective,
11577   ngClassDirective,
11578   ngClassEvenDirective,
11579   ngClassOddDirective,
11580   ngCloakDirective,
11581   ngControllerDirective,
11582   ngFormDirective,
11583   ngHideDirective,
11584   ngIfDirective,
11585   ngIncludeDirective,
11586   ngIncludeFillContentDirective,
11587   ngInitDirective,
11588   ngNonBindableDirective,
11589   ngPluralizeDirective,
11590   ngRepeatDirective,
11591   ngShowDirective,
11592   ngStyleDirective,
11593   ngSwitchDirective,
11594   ngSwitchWhenDirective,
11595   ngSwitchDefaultDirective,
11596   ngOptionsDirective,
11597   ngTranscludeDirective,
11598   ngModelDirective,
11599   ngListDirective,
11600   ngChangeDirective,
11601   patternDirective,
11602   patternDirective,
11603   requiredDirective,
11604   requiredDirective,
11605   minlengthDirective,
11606   minlengthDirective,
11607   maxlengthDirective,
11608   maxlengthDirective,
11609   ngValueDirective,
11610   ngModelOptionsDirective,
11611   ngAttributeAliasDirectives,
11612   ngEventDirectives,
11613
11614   $AnchorScrollProvider,
11615   $AnimateProvider,
11616   $CoreAnimateCssProvider,
11617   $$CoreAnimateJsProvider,
11618   $$CoreAnimateQueueProvider,
11619   $$AnimateRunnerFactoryProvider,
11620   $$AnimateAsyncRunFactoryProvider,
11621   $BrowserProvider,
11622   $CacheFactoryProvider,
11623   $ControllerProvider,
11624   $DateProvider,
11625   $DocumentProvider,
11626   $ExceptionHandlerProvider,
11627   $FilterProvider,
11628   $$ForceReflowProvider,
11629   $InterpolateProvider,
11630   $IntervalProvider,
11631   $$HashMapProvider,
11632   $HttpProvider,
11633   $HttpParamSerializerProvider,
11634   $HttpParamSerializerJQLikeProvider,
11635   $HttpBackendProvider,
11636   $xhrFactoryProvider,
11637   $LocationProvider,
11638   $LogProvider,
11639   $ParseProvider,
11640   $RootScopeProvider,
11641   $QProvider,
11642   $$QProvider,
11643   $$SanitizeUriProvider,
11644   $SceProvider,
11645   $SceDelegateProvider,
11646   $SnifferProvider,
11647   $TemplateCacheProvider,
11648   $TemplateRequestProvider,
11649   $$TestabilityProvider,
11650   $TimeoutProvider,
11651   $$RAFProvider,
11652   $WindowProvider,
11653   $$jqLiteProvider,
11654   $$CookieReaderProvider
11655 */
11656
11657
11658 /**
11659  * @ngdoc object
11660  * @name angular.version
11661  * @module ng
11662  * @description
11663  * An object that contains information about the current AngularJS version.
11664  *
11665  * This object has the following properties:
11666  *
11667  * - `full` â€“ `{string}` â€“ Full version string, such as "0.9.18".
11668  * - `major` â€“ `{number}` â€“ Major version number, such as "0".
11669  * - `minor` â€“ `{number}` â€“ Minor version number, such as "9".
11670  * - `dot` â€“ `{number}` â€“ Dot version number, such as "18".
11671  * - `codeName` â€“ `{string}` â€“ Code name of the release, such as "jiggling-armfat".
11672  */
11673 var version = {
11674   full: '1.5.5',    // all of these placeholder strings will be replaced by grunt's
11675   major: 1,    // package task
11676   minor: 5,
11677   dot: 5,
11678   codeName: 'material-conspiration'
11679 };
11680
11681
11682 function publishExternalAPI(angular) {
11683   extend(angular, {
11684     'bootstrap': bootstrap,
11685     'copy': copy,
11686     'extend': extend,
11687     'merge': merge,
11688     'equals': equals,
11689     'element': jqLite,
11690     'forEach': forEach,
11691     'injector': createInjector,
11692     'noop': noop,
11693     'bind': bind,
11694     'toJson': toJson,
11695     'fromJson': fromJson,
11696     'identity': identity,
11697     'isUndefined': isUndefined,
11698     'isDefined': isDefined,
11699     'isString': isString,
11700     'isFunction': isFunction,
11701     'isObject': isObject,
11702     'isNumber': isNumber,
11703     'isElement': isElement,
11704     'isArray': isArray,
11705     'version': version,
11706     'isDate': isDate,
11707     'lowercase': lowercase,
11708     'uppercase': uppercase,
11709     'callbacks': {counter: 0},
11710     'getTestability': getTestability,
11711     '$$minErr': minErr,
11712     '$$csp': csp,
11713     'reloadWithDebugInfo': reloadWithDebugInfo
11714   });
11715
11716   angularModule = setupModuleLoader(window);
11717
11718   angularModule('ng', ['ngLocale'], ['$provide',
11719     function ngModule($provide) {
11720       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
11721       $provide.provider({
11722         $$sanitizeUri: $$SanitizeUriProvider
11723       });
11724       $provide.provider('$compile', $CompileProvider).
11725         directive({
11726             a: htmlAnchorDirective,
11727             input: inputDirective,
11728             textarea: inputDirective,
11729             form: formDirective,
11730             script: scriptDirective,
11731             select: selectDirective,
11732             style: styleDirective,
11733             option: optionDirective,
11734             ngBind: ngBindDirective,
11735             ngBindHtml: ngBindHtmlDirective,
11736             ngBindTemplate: ngBindTemplateDirective,
11737             ngClass: ngClassDirective,
11738             ngClassEven: ngClassEvenDirective,
11739             ngClassOdd: ngClassOddDirective,
11740             ngCloak: ngCloakDirective,
11741             ngController: ngControllerDirective,
11742             ngForm: ngFormDirective,
11743             ngHide: ngHideDirective,
11744             ngIf: ngIfDirective,
11745             ngInclude: ngIncludeDirective,
11746             ngInit: ngInitDirective,
11747             ngNonBindable: ngNonBindableDirective,
11748             ngPluralize: ngPluralizeDirective,
11749             ngRepeat: ngRepeatDirective,
11750             ngShow: ngShowDirective,
11751             ngStyle: ngStyleDirective,
11752             ngSwitch: ngSwitchDirective,
11753             ngSwitchWhen: ngSwitchWhenDirective,
11754             ngSwitchDefault: ngSwitchDefaultDirective,
11755             ngOptions: ngOptionsDirective,
11756             ngTransclude: ngTranscludeDirective,
11757             ngModel: ngModelDirective,
11758             ngList: ngListDirective,
11759             ngChange: ngChangeDirective,
11760             pattern: patternDirective,
11761             ngPattern: patternDirective,
11762             required: requiredDirective,
11763             ngRequired: requiredDirective,
11764             minlength: minlengthDirective,
11765             ngMinlength: minlengthDirective,
11766             maxlength: maxlengthDirective,
11767             ngMaxlength: maxlengthDirective,
11768             ngValue: ngValueDirective,
11769             ngModelOptions: ngModelOptionsDirective
11770         }).
11771         directive({
11772           ngInclude: ngIncludeFillContentDirective
11773         }).
11774         directive(ngAttributeAliasDirectives).
11775         directive(ngEventDirectives);
11776       $provide.provider({
11777         $anchorScroll: $AnchorScrollProvider,
11778         $animate: $AnimateProvider,
11779         $animateCss: $CoreAnimateCssProvider,
11780         $$animateJs: $$CoreAnimateJsProvider,
11781         $$animateQueue: $$CoreAnimateQueueProvider,
11782         $$AnimateRunner: $$AnimateRunnerFactoryProvider,
11783         $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
11784         $browser: $BrowserProvider,
11785         $cacheFactory: $CacheFactoryProvider,
11786         $controller: $ControllerProvider,
11787         $document: $DocumentProvider,
11788         $exceptionHandler: $ExceptionHandlerProvider,
11789         $filter: $FilterProvider,
11790         $$forceReflow: $$ForceReflowProvider,
11791         $interpolate: $InterpolateProvider,
11792         $interval: $IntervalProvider,
11793         $http: $HttpProvider,
11794         $httpParamSerializer: $HttpParamSerializerProvider,
11795         $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
11796         $httpBackend: $HttpBackendProvider,
11797         $xhrFactory: $xhrFactoryProvider,
11798         $location: $LocationProvider,
11799         $log: $LogProvider,
11800         $parse: $ParseProvider,
11801         $rootScope: $RootScopeProvider,
11802         $q: $QProvider,
11803         $$q: $$QProvider,
11804         $sce: $SceProvider,
11805         $sceDelegate: $SceDelegateProvider,
11806         $sniffer: $SnifferProvider,
11807         $templateCache: $TemplateCacheProvider,
11808         $templateRequest: $TemplateRequestProvider,
11809         $$testability: $$TestabilityProvider,
11810         $timeout: $TimeoutProvider,
11811         $window: $WindowProvider,
11812         $$rAF: $$RAFProvider,
11813         $$jqLite: $$jqLiteProvider,
11814         $$HashMap: $$HashMapProvider,
11815         $$cookieReader: $$CookieReaderProvider
11816       });
11817     }
11818   ]);
11819 }
11820
11821 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11822  *     Any commits to this file should be reviewed with security in mind.  *
11823  *   Changes to this file can potentially create security vulnerabilities. *
11824  *          An approval from 2 Core members with history of modifying      *
11825  *                         this file is required.                          *
11826  *                                                                         *
11827  *  Does the change somehow allow for arbitrary javascript to be executed? *
11828  *    Or allows for someone to change the prototype of built-in objects?   *
11829  *     Or gives undesired access to variables likes document or window?    *
11830  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11831
11832 /* global JQLitePrototype: true,
11833   addEventListenerFn: true,
11834   removeEventListenerFn: true,
11835   BOOLEAN_ATTR: true,
11836   ALIASED_ATTR: true,
11837 */
11838
11839 //////////////////////////////////
11840 //JQLite
11841 //////////////////////////////////
11842
11843 /**
11844  * @ngdoc function
11845  * @name angular.element
11846  * @module ng
11847  * @kind function
11848  *
11849  * @description
11850  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
11851  *
11852  * If jQuery is available, `angular.element` is an alias for the
11853  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
11854  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
11855  *
11856  * jqLite is a tiny, API-compatible subset of jQuery that allows
11857  * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
11858  * commonly needed functionality with the goal of having a very small footprint.
11859  *
11860  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
11861  * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
11862  * specific version of jQuery if multiple versions exist on the page.
11863  *
11864  * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
11865  * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
11866  *
11867  * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
11868  * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
11869  * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
11870  *
11871  * ## Angular's jqLite
11872  * jqLite provides only the following jQuery methods:
11873  *
11874  * - [`addClass()`](http://api.jquery.com/addClass/)
11875  * - [`after()`](http://api.jquery.com/after/)
11876  * - [`append()`](http://api.jquery.com/append/)
11877  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
11878  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
11879  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
11880  * - [`clone()`](http://api.jquery.com/clone/)
11881  * - [`contents()`](http://api.jquery.com/contents/)
11882  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
11883  *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
11884  * - [`data()`](http://api.jquery.com/data/)
11885  * - [`detach()`](http://api.jquery.com/detach/)
11886  * - [`empty()`](http://api.jquery.com/empty/)
11887  * - [`eq()`](http://api.jquery.com/eq/)
11888  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
11889  * - [`hasClass()`](http://api.jquery.com/hasClass/)
11890  * - [`html()`](http://api.jquery.com/html/)
11891  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
11892  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
11893  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
11894  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
11895  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
11896  * - [`prepend()`](http://api.jquery.com/prepend/)
11897  * - [`prop()`](http://api.jquery.com/prop/)
11898  * - [`ready()`](http://api.jquery.com/ready/)
11899  * - [`remove()`](http://api.jquery.com/remove/)
11900  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
11901  * - [`removeClass()`](http://api.jquery.com/removeClass/)
11902  * - [`removeData()`](http://api.jquery.com/removeData/)
11903  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
11904  * - [`text()`](http://api.jquery.com/text/)
11905  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
11906  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
11907  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
11908  * - [`val()`](http://api.jquery.com/val/)
11909  * - [`wrap()`](http://api.jquery.com/wrap/)
11910  *
11911  * ## jQuery/jqLite Extras
11912  * Angular also provides the following additional methods and events to both jQuery and jqLite:
11913  *
11914  * ### Events
11915  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
11916  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
11917  *    element before it is removed.
11918  *
11919  * ### Methods
11920  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
11921  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
11922  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
11923  *   `'ngModel'`).
11924  * - `injector()` - retrieves the injector of the current element or its parent.
11925  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
11926  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
11927  *   be enabled.
11928  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
11929  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
11930  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
11931  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
11932  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
11933  *   parent element is reached.
11934  *
11935  * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
11936  * https://github.com/angular/angular.js/issues/14251 for more information.
11937  *
11938  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
11939  * @returns {Object} jQuery object.
11940  */
11941
11942 JQLite.expando = 'ng339';
11943
11944 var jqCache = JQLite.cache = {},
11945     jqId = 1,
11946     addEventListenerFn = function(element, type, fn) {
11947       element.addEventListener(type, fn, false);
11948     },
11949     removeEventListenerFn = function(element, type, fn) {
11950       element.removeEventListener(type, fn, false);
11951     };
11952
11953 /*
11954  * !!! This is an undocumented "private" function !!!
11955  */
11956 JQLite._data = function(node) {
11957   //jQuery always returns an object on cache miss
11958   return this.cache[node[this.expando]] || {};
11959 };
11960
11961 function jqNextId() { return ++jqId; }
11962
11963
11964 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
11965 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
11966 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
11967 var jqLiteMinErr = minErr('jqLite');
11968
11969 /**
11970  * Converts snake_case to camelCase.
11971  * Also there is special case for Moz prefix starting with upper case letter.
11972  * @param name Name to normalize
11973  */
11974 function camelCase(name) {
11975   return name.
11976     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
11977       return offset ? letter.toUpperCase() : letter;
11978     }).
11979     replace(MOZ_HACK_REGEXP, 'Moz$1');
11980 }
11981
11982 var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
11983 var HTML_REGEXP = /<|&#?\w+;/;
11984 var TAG_NAME_REGEXP = /<([\w:-]+)/;
11985 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
11986
11987 var wrapMap = {
11988   'option': [1, '<select multiple="multiple">', '</select>'],
11989
11990   'thead': [1, '<table>', '</table>'],
11991   'col': [2, '<table><colgroup>', '</colgroup></table>'],
11992   'tr': [2, '<table><tbody>', '</tbody></table>'],
11993   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
11994   '_default': [0, "", ""]
11995 };
11996
11997 wrapMap.optgroup = wrapMap.option;
11998 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
11999 wrapMap.th = wrapMap.td;
12000
12001
12002 function jqLiteIsTextNode(html) {
12003   return !HTML_REGEXP.test(html);
12004 }
12005
12006 function jqLiteAcceptsData(node) {
12007   // The window object can accept data but has no nodeType
12008   // Otherwise we are only interested in elements (1) and documents (9)
12009   var nodeType = node.nodeType;
12010   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
12011 }
12012
12013 function jqLiteHasData(node) {
12014   for (var key in jqCache[node.ng339]) {
12015     return true;
12016   }
12017   return false;
12018 }
12019
12020 function jqLiteCleanData(nodes) {
12021   for (var i = 0, ii = nodes.length; i < ii; i++) {
12022     jqLiteRemoveData(nodes[i]);
12023   }
12024 }
12025
12026 function jqLiteBuildFragment(html, context) {
12027   var tmp, tag, wrap,
12028       fragment = context.createDocumentFragment(),
12029       nodes = [], i;
12030
12031   if (jqLiteIsTextNode(html)) {
12032     // Convert non-html into a text node
12033     nodes.push(context.createTextNode(html));
12034   } else {
12035     // Convert html into DOM nodes
12036     tmp = tmp || fragment.appendChild(context.createElement("div"));
12037     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
12038     wrap = wrapMap[tag] || wrapMap._default;
12039     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
12040
12041     // Descend through wrappers to the right content
12042     i = wrap[0];
12043     while (i--) {
12044       tmp = tmp.lastChild;
12045     }
12046
12047     nodes = concat(nodes, tmp.childNodes);
12048
12049     tmp = fragment.firstChild;
12050     tmp.textContent = "";
12051   }
12052
12053   // Remove wrapper from fragment
12054   fragment.textContent = "";
12055   fragment.innerHTML = ""; // Clear inner HTML
12056   forEach(nodes, function(node) {
12057     fragment.appendChild(node);
12058   });
12059
12060   return fragment;
12061 }
12062
12063 function jqLiteParseHTML(html, context) {
12064   context = context || window.document;
12065   var parsed;
12066
12067   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
12068     return [context.createElement(parsed[1])];
12069   }
12070
12071   if ((parsed = jqLiteBuildFragment(html, context))) {
12072     return parsed.childNodes;
12073   }
12074
12075   return [];
12076 }
12077
12078 function jqLiteWrapNode(node, wrapper) {
12079   var parent = node.parentNode;
12080
12081   if (parent) {
12082     parent.replaceChild(wrapper, node);
12083   }
12084
12085   wrapper.appendChild(node);
12086 }
12087
12088
12089 // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
12090 var jqLiteContains = window.Node.prototype.contains || function(arg) {
12091   // jshint bitwise: false
12092   return !!(this.compareDocumentPosition(arg) & 16);
12093   // jshint bitwise: true
12094 };
12095
12096 /////////////////////////////////////////////
12097 function JQLite(element) {
12098   if (element instanceof JQLite) {
12099     return element;
12100   }
12101
12102   var argIsString;
12103
12104   if (isString(element)) {
12105     element = trim(element);
12106     argIsString = true;
12107   }
12108   if (!(this instanceof JQLite)) {
12109     if (argIsString && element.charAt(0) != '<') {
12110       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
12111     }
12112     return new JQLite(element);
12113   }
12114
12115   if (argIsString) {
12116     jqLiteAddNodes(this, jqLiteParseHTML(element));
12117   } else {
12118     jqLiteAddNodes(this, element);
12119   }
12120 }
12121
12122 function jqLiteClone(element) {
12123   return element.cloneNode(true);
12124 }
12125
12126 function jqLiteDealoc(element, onlyDescendants) {
12127   if (!onlyDescendants) jqLiteRemoveData(element);
12128
12129   if (element.querySelectorAll) {
12130     var descendants = element.querySelectorAll('*');
12131     for (var i = 0, l = descendants.length; i < l; i++) {
12132       jqLiteRemoveData(descendants[i]);
12133     }
12134   }
12135 }
12136
12137 function jqLiteOff(element, type, fn, unsupported) {
12138   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
12139
12140   var expandoStore = jqLiteExpandoStore(element);
12141   var events = expandoStore && expandoStore.events;
12142   var handle = expandoStore && expandoStore.handle;
12143
12144   if (!handle) return; //no listeners registered
12145
12146   if (!type) {
12147     for (type in events) {
12148       if (type !== '$destroy') {
12149         removeEventListenerFn(element, type, handle);
12150       }
12151       delete events[type];
12152     }
12153   } else {
12154
12155     var removeHandler = function(type) {
12156       var listenerFns = events[type];
12157       if (isDefined(fn)) {
12158         arrayRemove(listenerFns || [], fn);
12159       }
12160       if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
12161         removeEventListenerFn(element, type, handle);
12162         delete events[type];
12163       }
12164     };
12165
12166     forEach(type.split(' '), function(type) {
12167       removeHandler(type);
12168       if (MOUSE_EVENT_MAP[type]) {
12169         removeHandler(MOUSE_EVENT_MAP[type]);
12170       }
12171     });
12172   }
12173 }
12174
12175 function jqLiteRemoveData(element, name) {
12176   var expandoId = element.ng339;
12177   var expandoStore = expandoId && jqCache[expandoId];
12178
12179   if (expandoStore) {
12180     if (name) {
12181       delete expandoStore.data[name];
12182       return;
12183     }
12184
12185     if (expandoStore.handle) {
12186       if (expandoStore.events.$destroy) {
12187         expandoStore.handle({}, '$destroy');
12188       }
12189       jqLiteOff(element);
12190     }
12191     delete jqCache[expandoId];
12192     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
12193   }
12194 }
12195
12196
12197 function jqLiteExpandoStore(element, createIfNecessary) {
12198   var expandoId = element.ng339,
12199       expandoStore = expandoId && jqCache[expandoId];
12200
12201   if (createIfNecessary && !expandoStore) {
12202     element.ng339 = expandoId = jqNextId();
12203     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
12204   }
12205
12206   return expandoStore;
12207 }
12208
12209
12210 function jqLiteData(element, key, value) {
12211   if (jqLiteAcceptsData(element)) {
12212
12213     var isSimpleSetter = isDefined(value);
12214     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
12215     var massGetter = !key;
12216     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
12217     var data = expandoStore && expandoStore.data;
12218
12219     if (isSimpleSetter) { // data('key', value)
12220       data[key] = value;
12221     } else {
12222       if (massGetter) {  // data()
12223         return data;
12224       } else {
12225         if (isSimpleGetter) { // data('key')
12226           // don't force creation of expandoStore if it doesn't exist yet
12227           return data && data[key];
12228         } else { // mass-setter: data({key1: val1, key2: val2})
12229           extend(data, key);
12230         }
12231       }
12232     }
12233   }
12234 }
12235
12236 function jqLiteHasClass(element, selector) {
12237   if (!element.getAttribute) return false;
12238   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
12239       indexOf(" " + selector + " ") > -1);
12240 }
12241
12242 function jqLiteRemoveClass(element, cssClasses) {
12243   if (cssClasses && element.setAttribute) {
12244     forEach(cssClasses.split(' '), function(cssClass) {
12245       element.setAttribute('class', trim(
12246           (" " + (element.getAttribute('class') || '') + " ")
12247           .replace(/[\n\t]/g, " ")
12248           .replace(" " + trim(cssClass) + " ", " "))
12249       );
12250     });
12251   }
12252 }
12253
12254 function jqLiteAddClass(element, cssClasses) {
12255   if (cssClasses && element.setAttribute) {
12256     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
12257                             .replace(/[\n\t]/g, " ");
12258
12259     forEach(cssClasses.split(' '), function(cssClass) {
12260       cssClass = trim(cssClass);
12261       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
12262         existingClasses += cssClass + ' ';
12263       }
12264     });
12265
12266     element.setAttribute('class', trim(existingClasses));
12267   }
12268 }
12269
12270
12271 function jqLiteAddNodes(root, elements) {
12272   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
12273
12274   if (elements) {
12275
12276     // if a Node (the most common case)
12277     if (elements.nodeType) {
12278       root[root.length++] = elements;
12279     } else {
12280       var length = elements.length;
12281
12282       // if an Array or NodeList and not a Window
12283       if (typeof length === 'number' && elements.window !== elements) {
12284         if (length) {
12285           for (var i = 0; i < length; i++) {
12286             root[root.length++] = elements[i];
12287           }
12288         }
12289       } else {
12290         root[root.length++] = elements;
12291       }
12292     }
12293   }
12294 }
12295
12296
12297 function jqLiteController(element, name) {
12298   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
12299 }
12300
12301 function jqLiteInheritedData(element, name, value) {
12302   // if element is the document object work with the html element instead
12303   // this makes $(document).scope() possible
12304   if (element.nodeType == NODE_TYPE_DOCUMENT) {
12305     element = element.documentElement;
12306   }
12307   var names = isArray(name) ? name : [name];
12308
12309   while (element) {
12310     for (var i = 0, ii = names.length; i < ii; i++) {
12311       if (isDefined(value = jqLite.data(element, names[i]))) return value;
12312     }
12313
12314     // If dealing with a document fragment node with a host element, and no parent, use the host
12315     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
12316     // to lookup parent controllers.
12317     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
12318   }
12319 }
12320
12321 function jqLiteEmpty(element) {
12322   jqLiteDealoc(element, true);
12323   while (element.firstChild) {
12324     element.removeChild(element.firstChild);
12325   }
12326 }
12327
12328 function jqLiteRemove(element, keepData) {
12329   if (!keepData) jqLiteDealoc(element);
12330   var parent = element.parentNode;
12331   if (parent) parent.removeChild(element);
12332 }
12333
12334
12335 function jqLiteDocumentLoaded(action, win) {
12336   win = win || window;
12337   if (win.document.readyState === 'complete') {
12338     // Force the action to be run async for consistent behavior
12339     // from the action's point of view
12340     // i.e. it will definitely not be in a $apply
12341     win.setTimeout(action);
12342   } else {
12343     // No need to unbind this handler as load is only ever called once
12344     jqLite(win).on('load', action);
12345   }
12346 }
12347
12348 //////////////////////////////////////////
12349 // Functions which are declared directly.
12350 //////////////////////////////////////////
12351 var JQLitePrototype = JQLite.prototype = {
12352   ready: function(fn) {
12353     var fired = false;
12354
12355     function trigger() {
12356       if (fired) return;
12357       fired = true;
12358       fn();
12359     }
12360
12361     // check if document is already loaded
12362     if (window.document.readyState === 'complete') {
12363       window.setTimeout(trigger);
12364     } else {
12365       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
12366       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
12367       // jshint -W064
12368       JQLite(window).on('load', trigger); // fallback to window.onload for others
12369       // jshint +W064
12370     }
12371   },
12372   toString: function() {
12373     var value = [];
12374     forEach(this, function(e) { value.push('' + e);});
12375     return '[' + value.join(', ') + ']';
12376   },
12377
12378   eq: function(index) {
12379       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
12380   },
12381
12382   length: 0,
12383   push: push,
12384   sort: [].sort,
12385   splice: [].splice
12386 };
12387
12388 //////////////////////////////////////////
12389 // Functions iterating getter/setters.
12390 // these functions return self on setter and
12391 // value on get.
12392 //////////////////////////////////////////
12393 var BOOLEAN_ATTR = {};
12394 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
12395   BOOLEAN_ATTR[lowercase(value)] = value;
12396 });
12397 var BOOLEAN_ELEMENTS = {};
12398 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
12399   BOOLEAN_ELEMENTS[value] = true;
12400 });
12401 var ALIASED_ATTR = {
12402   'ngMinlength': 'minlength',
12403   'ngMaxlength': 'maxlength',
12404   'ngMin': 'min',
12405   'ngMax': 'max',
12406   'ngPattern': 'pattern'
12407 };
12408
12409 function getBooleanAttrName(element, name) {
12410   // check dom last since we will most likely fail on name
12411   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
12412
12413   // booleanAttr is here twice to minimize DOM access
12414   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
12415 }
12416
12417 function getAliasedAttrName(name) {
12418   return ALIASED_ATTR[name];
12419 }
12420
12421 forEach({
12422   data: jqLiteData,
12423   removeData: jqLiteRemoveData,
12424   hasData: jqLiteHasData,
12425   cleanData: jqLiteCleanData
12426 }, function(fn, name) {
12427   JQLite[name] = fn;
12428 });
12429
12430 forEach({
12431   data: jqLiteData,
12432   inheritedData: jqLiteInheritedData,
12433
12434   scope: function(element) {
12435     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12436     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12437   },
12438
12439   isolateScope: function(element) {
12440     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12441     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
12442   },
12443
12444   controller: jqLiteController,
12445
12446   injector: function(element) {
12447     return jqLiteInheritedData(element, '$injector');
12448   },
12449
12450   removeAttr: function(element, name) {
12451     element.removeAttribute(name);
12452   },
12453
12454   hasClass: jqLiteHasClass,
12455
12456   css: function(element, name, value) {
12457     name = camelCase(name);
12458
12459     if (isDefined(value)) {
12460       element.style[name] = value;
12461     } else {
12462       return element.style[name];
12463     }
12464   },
12465
12466   attr: function(element, name, value) {
12467     var nodeType = element.nodeType;
12468     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
12469       return;
12470     }
12471     var lowercasedName = lowercase(name);
12472     if (BOOLEAN_ATTR[lowercasedName]) {
12473       if (isDefined(value)) {
12474         if (!!value) {
12475           element[name] = true;
12476           element.setAttribute(name, lowercasedName);
12477         } else {
12478           element[name] = false;
12479           element.removeAttribute(lowercasedName);
12480         }
12481       } else {
12482         return (element[name] ||
12483                  (element.attributes.getNamedItem(name) || noop).specified)
12484                ? lowercasedName
12485                : undefined;
12486       }
12487     } else if (isDefined(value)) {
12488       element.setAttribute(name, value);
12489     } else if (element.getAttribute) {
12490       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
12491       // some elements (e.g. Document) don't have get attribute, so return undefined
12492       var ret = element.getAttribute(name, 2);
12493       // normalize non-existing attributes to undefined (as jQuery)
12494       return ret === null ? undefined : ret;
12495     }
12496   },
12497
12498   prop: function(element, name, value) {
12499     if (isDefined(value)) {
12500       element[name] = value;
12501     } else {
12502       return element[name];
12503     }
12504   },
12505
12506   text: (function() {
12507     getText.$dv = '';
12508     return getText;
12509
12510     function getText(element, value) {
12511       if (isUndefined(value)) {
12512         var nodeType = element.nodeType;
12513         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
12514       }
12515       element.textContent = value;
12516     }
12517   })(),
12518
12519   val: function(element, value) {
12520     if (isUndefined(value)) {
12521       if (element.multiple && nodeName_(element) === 'select') {
12522         var result = [];
12523         forEach(element.options, function(option) {
12524           if (option.selected) {
12525             result.push(option.value || option.text);
12526           }
12527         });
12528         return result.length === 0 ? null : result;
12529       }
12530       return element.value;
12531     }
12532     element.value = value;
12533   },
12534
12535   html: function(element, value) {
12536     if (isUndefined(value)) {
12537       return element.innerHTML;
12538     }
12539     jqLiteDealoc(element, true);
12540     element.innerHTML = value;
12541   },
12542
12543   empty: jqLiteEmpty
12544 }, function(fn, name) {
12545   /**
12546    * Properties: writes return selection, reads return first value
12547    */
12548   JQLite.prototype[name] = function(arg1, arg2) {
12549     var i, key;
12550     var nodeCount = this.length;
12551
12552     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
12553     // in a way that survives minification.
12554     // jqLiteEmpty takes no arguments but is a setter.
12555     if (fn !== jqLiteEmpty &&
12556         (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
12557       if (isObject(arg1)) {
12558
12559         // we are a write, but the object properties are the key/values
12560         for (i = 0; i < nodeCount; i++) {
12561           if (fn === jqLiteData) {
12562             // data() takes the whole object in jQuery
12563             fn(this[i], arg1);
12564           } else {
12565             for (key in arg1) {
12566               fn(this[i], key, arg1[key]);
12567             }
12568           }
12569         }
12570         // return self for chaining
12571         return this;
12572       } else {
12573         // we are a read, so read the first child.
12574         // TODO: do we still need this?
12575         var value = fn.$dv;
12576         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
12577         var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
12578         for (var j = 0; j < jj; j++) {
12579           var nodeValue = fn(this[j], arg1, arg2);
12580           value = value ? value + nodeValue : nodeValue;
12581         }
12582         return value;
12583       }
12584     } else {
12585       // we are a write, so apply to all children
12586       for (i = 0; i < nodeCount; i++) {
12587         fn(this[i], arg1, arg2);
12588       }
12589       // return self for chaining
12590       return this;
12591     }
12592   };
12593 });
12594
12595 function createEventHandler(element, events) {
12596   var eventHandler = function(event, type) {
12597     // jQuery specific api
12598     event.isDefaultPrevented = function() {
12599       return event.defaultPrevented;
12600     };
12601
12602     var eventFns = events[type || event.type];
12603     var eventFnsLength = eventFns ? eventFns.length : 0;
12604
12605     if (!eventFnsLength) return;
12606
12607     if (isUndefined(event.immediatePropagationStopped)) {
12608       var originalStopImmediatePropagation = event.stopImmediatePropagation;
12609       event.stopImmediatePropagation = function() {
12610         event.immediatePropagationStopped = true;
12611
12612         if (event.stopPropagation) {
12613           event.stopPropagation();
12614         }
12615
12616         if (originalStopImmediatePropagation) {
12617           originalStopImmediatePropagation.call(event);
12618         }
12619       };
12620     }
12621
12622     event.isImmediatePropagationStopped = function() {
12623       return event.immediatePropagationStopped === true;
12624     };
12625
12626     // Some events have special handlers that wrap the real handler
12627     var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
12628
12629     // Copy event handlers in case event handlers array is modified during execution.
12630     if ((eventFnsLength > 1)) {
12631       eventFns = shallowCopy(eventFns);
12632     }
12633
12634     for (var i = 0; i < eventFnsLength; i++) {
12635       if (!event.isImmediatePropagationStopped()) {
12636         handlerWrapper(element, event, eventFns[i]);
12637       }
12638     }
12639   };
12640
12641   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
12642   //       events on `element`
12643   eventHandler.elem = element;
12644   return eventHandler;
12645 }
12646
12647 function defaultHandlerWrapper(element, event, handler) {
12648   handler.call(element, event);
12649 }
12650
12651 function specialMouseHandlerWrapper(target, event, handler) {
12652   // Refer to jQuery's implementation of mouseenter & mouseleave
12653   // Read about mouseenter and mouseleave:
12654   // http://www.quirksmode.org/js/events_mouse.html#link8
12655   var related = event.relatedTarget;
12656   // For mousenter/leave call the handler if related is outside the target.
12657   // NB: No relatedTarget if the mouse left/entered the browser window
12658   if (!related || (related !== target && !jqLiteContains.call(target, related))) {
12659     handler.call(target, event);
12660   }
12661 }
12662
12663 //////////////////////////////////////////
12664 // Functions iterating traversal.
12665 // These functions chain results into a single
12666 // selector.
12667 //////////////////////////////////////////
12668 forEach({
12669   removeData: jqLiteRemoveData,
12670
12671   on: function jqLiteOn(element, type, fn, unsupported) {
12672     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
12673
12674     // Do not add event handlers to non-elements because they will not be cleaned up.
12675     if (!jqLiteAcceptsData(element)) {
12676       return;
12677     }
12678
12679     var expandoStore = jqLiteExpandoStore(element, true);
12680     var events = expandoStore.events;
12681     var handle = expandoStore.handle;
12682
12683     if (!handle) {
12684       handle = expandoStore.handle = createEventHandler(element, events);
12685     }
12686
12687     // http://jsperf.com/string-indexof-vs-split
12688     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
12689     var i = types.length;
12690
12691     var addHandler = function(type, specialHandlerWrapper, noEventListener) {
12692       var eventFns = events[type];
12693
12694       if (!eventFns) {
12695         eventFns = events[type] = [];
12696         eventFns.specialHandlerWrapper = specialHandlerWrapper;
12697         if (type !== '$destroy' && !noEventListener) {
12698           addEventListenerFn(element, type, handle);
12699         }
12700       }
12701
12702       eventFns.push(fn);
12703     };
12704
12705     while (i--) {
12706       type = types[i];
12707       if (MOUSE_EVENT_MAP[type]) {
12708         addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
12709         addHandler(type, undefined, true);
12710       } else {
12711         addHandler(type);
12712       }
12713     }
12714   },
12715
12716   off: jqLiteOff,
12717
12718   one: function(element, type, fn) {
12719     element = jqLite(element);
12720
12721     //add the listener twice so that when it is called
12722     //you can remove the original function and still be
12723     //able to call element.off(ev, fn) normally
12724     element.on(type, function onFn() {
12725       element.off(type, fn);
12726       element.off(type, onFn);
12727     });
12728     element.on(type, fn);
12729   },
12730
12731   replaceWith: function(element, replaceNode) {
12732     var index, parent = element.parentNode;
12733     jqLiteDealoc(element);
12734     forEach(new JQLite(replaceNode), function(node) {
12735       if (index) {
12736         parent.insertBefore(node, index.nextSibling);
12737       } else {
12738         parent.replaceChild(node, element);
12739       }
12740       index = node;
12741     });
12742   },
12743
12744   children: function(element) {
12745     var children = [];
12746     forEach(element.childNodes, function(element) {
12747       if (element.nodeType === NODE_TYPE_ELEMENT) {
12748         children.push(element);
12749       }
12750     });
12751     return children;
12752   },
12753
12754   contents: function(element) {
12755     return element.contentDocument || element.childNodes || [];
12756   },
12757
12758   append: function(element, node) {
12759     var nodeType = element.nodeType;
12760     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
12761
12762     node = new JQLite(node);
12763
12764     for (var i = 0, ii = node.length; i < ii; i++) {
12765       var child = node[i];
12766       element.appendChild(child);
12767     }
12768   },
12769
12770   prepend: function(element, node) {
12771     if (element.nodeType === NODE_TYPE_ELEMENT) {
12772       var index = element.firstChild;
12773       forEach(new JQLite(node), function(child) {
12774         element.insertBefore(child, index);
12775       });
12776     }
12777   },
12778
12779   wrap: function(element, wrapNode) {
12780     jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
12781   },
12782
12783   remove: jqLiteRemove,
12784
12785   detach: function(element) {
12786     jqLiteRemove(element, true);
12787   },
12788
12789   after: function(element, newElement) {
12790     var index = element, parent = element.parentNode;
12791     newElement = new JQLite(newElement);
12792
12793     for (var i = 0, ii = newElement.length; i < ii; i++) {
12794       var node = newElement[i];
12795       parent.insertBefore(node, index.nextSibling);
12796       index = node;
12797     }
12798   },
12799
12800   addClass: jqLiteAddClass,
12801   removeClass: jqLiteRemoveClass,
12802
12803   toggleClass: function(element, selector, condition) {
12804     if (selector) {
12805       forEach(selector.split(' '), function(className) {
12806         var classCondition = condition;
12807         if (isUndefined(classCondition)) {
12808           classCondition = !jqLiteHasClass(element, className);
12809         }
12810         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
12811       });
12812     }
12813   },
12814
12815   parent: function(element) {
12816     var parent = element.parentNode;
12817     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
12818   },
12819
12820   next: function(element) {
12821     return element.nextElementSibling;
12822   },
12823
12824   find: function(element, selector) {
12825     if (element.getElementsByTagName) {
12826       return element.getElementsByTagName(selector);
12827     } else {
12828       return [];
12829     }
12830   },
12831
12832   clone: jqLiteClone,
12833
12834   triggerHandler: function(element, event, extraParameters) {
12835
12836     var dummyEvent, eventFnsCopy, handlerArgs;
12837     var eventName = event.type || event;
12838     var expandoStore = jqLiteExpandoStore(element);
12839     var events = expandoStore && expandoStore.events;
12840     var eventFns = events && events[eventName];
12841
12842     if (eventFns) {
12843       // Create a dummy event to pass to the handlers
12844       dummyEvent = {
12845         preventDefault: function() { this.defaultPrevented = true; },
12846         isDefaultPrevented: function() { return this.defaultPrevented === true; },
12847         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
12848         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
12849         stopPropagation: noop,
12850         type: eventName,
12851         target: element
12852       };
12853
12854       // If a custom event was provided then extend our dummy event with it
12855       if (event.type) {
12856         dummyEvent = extend(dummyEvent, event);
12857       }
12858
12859       // Copy event handlers in case event handlers array is modified during execution.
12860       eventFnsCopy = shallowCopy(eventFns);
12861       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
12862
12863       forEach(eventFnsCopy, function(fn) {
12864         if (!dummyEvent.isImmediatePropagationStopped()) {
12865           fn.apply(element, handlerArgs);
12866         }
12867       });
12868     }
12869   }
12870 }, function(fn, name) {
12871   /**
12872    * chaining functions
12873    */
12874   JQLite.prototype[name] = function(arg1, arg2, arg3) {
12875     var value;
12876
12877     for (var i = 0, ii = this.length; i < ii; i++) {
12878       if (isUndefined(value)) {
12879         value = fn(this[i], arg1, arg2, arg3);
12880         if (isDefined(value)) {
12881           // any function which returns a value needs to be wrapped
12882           value = jqLite(value);
12883         }
12884       } else {
12885         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
12886       }
12887     }
12888     return isDefined(value) ? value : this;
12889   };
12890
12891   // bind legacy bind/unbind to on/off
12892   JQLite.prototype.bind = JQLite.prototype.on;
12893   JQLite.prototype.unbind = JQLite.prototype.off;
12894 });
12895
12896
12897 // Provider for private $$jqLite service
12898 function $$jqLiteProvider() {
12899   this.$get = function $$jqLite() {
12900     return extend(JQLite, {
12901       hasClass: function(node, classes) {
12902         if (node.attr) node = node[0];
12903         return jqLiteHasClass(node, classes);
12904       },
12905       addClass: function(node, classes) {
12906         if (node.attr) node = node[0];
12907         return jqLiteAddClass(node, classes);
12908       },
12909       removeClass: function(node, classes) {
12910         if (node.attr) node = node[0];
12911         return jqLiteRemoveClass(node, classes);
12912       }
12913     });
12914   };
12915 }
12916
12917 /**
12918  * Computes a hash of an 'obj'.
12919  * Hash of a:
12920  *  string is string
12921  *  number is number as string
12922  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
12923  *         that is also assigned to the $$hashKey property of the object.
12924  *
12925  * @param obj
12926  * @returns {string} hash string such that the same input will have the same hash string.
12927  *         The resulting string key is in 'type:hashKey' format.
12928  */
12929 function hashKey(obj, nextUidFn) {
12930   var key = obj && obj.$$hashKey;
12931
12932   if (key) {
12933     if (typeof key === 'function') {
12934       key = obj.$$hashKey();
12935     }
12936     return key;
12937   }
12938
12939   var objType = typeof obj;
12940   if (objType == 'function' || (objType == 'object' && obj !== null)) {
12941     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
12942   } else {
12943     key = objType + ':' + obj;
12944   }
12945
12946   return key;
12947 }
12948
12949 /**
12950  * HashMap which can use objects as keys
12951  */
12952 function HashMap(array, isolatedUid) {
12953   if (isolatedUid) {
12954     var uid = 0;
12955     this.nextUid = function() {
12956       return ++uid;
12957     };
12958   }
12959   forEach(array, this.put, this);
12960 }
12961 HashMap.prototype = {
12962   /**
12963    * Store key value pair
12964    * @param key key to store can be any type
12965    * @param value value to store can be any type
12966    */
12967   put: function(key, value) {
12968     this[hashKey(key, this.nextUid)] = value;
12969   },
12970
12971   /**
12972    * @param key
12973    * @returns {Object} the value for the key
12974    */
12975   get: function(key) {
12976     return this[hashKey(key, this.nextUid)];
12977   },
12978
12979   /**
12980    * Remove the key/value pair
12981    * @param key
12982    */
12983   remove: function(key) {
12984     var value = this[key = hashKey(key, this.nextUid)];
12985     delete this[key];
12986     return value;
12987   }
12988 };
12989
12990 var $$HashMapProvider = [function() {
12991   this.$get = [function() {
12992     return HashMap;
12993   }];
12994 }];
12995
12996 /**
12997  * @ngdoc function
12998  * @module ng
12999  * @name angular.injector
13000  * @kind function
13001  *
13002  * @description
13003  * Creates an injector object that can be used for retrieving services as well as for
13004  * dependency injection (see {@link guide/di dependency injection}).
13005  *
13006  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
13007  *     {@link angular.module}. The `ng` module must be explicitly added.
13008  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
13009  *     disallows argument name annotation inference.
13010  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
13011  *
13012  * @example
13013  * Typical usage
13014  * ```js
13015  *   // create an injector
13016  *   var $injector = angular.injector(['ng']);
13017  *
13018  *   // use the injector to kick off your application
13019  *   // use the type inference to auto inject arguments, or use implicit injection
13020  *   $injector.invoke(function($rootScope, $compile, $document) {
13021  *     $compile($document)($rootScope);
13022  *     $rootScope.$digest();
13023  *   });
13024  * ```
13025  *
13026  * Sometimes you want to get access to the injector of a currently running Angular app
13027  * from outside Angular. Perhaps, you want to inject and compile some markup after the
13028  * application has been bootstrapped. You can do this using the extra `injector()` added
13029  * to JQuery/jqLite elements. See {@link angular.element}.
13030  *
13031  * *This is fairly rare but could be the case if a third party library is injecting the
13032  * markup.*
13033  *
13034  * In the following example a new block of HTML containing a `ng-controller`
13035  * directive is added to the end of the document body by JQuery. We then compile and link
13036  * it into the current AngularJS scope.
13037  *
13038  * ```js
13039  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
13040  * $(document.body).append($div);
13041  *
13042  * angular.element(document).injector().invoke(function($compile) {
13043  *   var scope = angular.element($div).scope();
13044  *   $compile($div)(scope);
13045  * });
13046  * ```
13047  */
13048
13049
13050 /**
13051  * @ngdoc module
13052  * @name auto
13053  * @installation
13054  * @description
13055  *
13056  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
13057  */
13058
13059 var ARROW_ARG = /^([^\(]+?)=>/;
13060 var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
13061 var FN_ARG_SPLIT = /,/;
13062 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
13063 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
13064 var $injectorMinErr = minErr('$injector');
13065
13066 function extractArgs(fn) {
13067   var fnText = Function.prototype.toString.call(fn).replace(STRIP_COMMENTS, ''),
13068       args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
13069   return args;
13070 }
13071
13072 function anonFn(fn) {
13073   // For anonymous functions, showing at the very least the function signature can help in
13074   // debugging.
13075   var args = extractArgs(fn);
13076   if (args) {
13077     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
13078   }
13079   return 'fn';
13080 }
13081
13082 function annotate(fn, strictDi, name) {
13083   var $inject,
13084       argDecl,
13085       last;
13086
13087   if (typeof fn === 'function') {
13088     if (!($inject = fn.$inject)) {
13089       $inject = [];
13090       if (fn.length) {
13091         if (strictDi) {
13092           if (!isString(name) || !name) {
13093             name = fn.name || anonFn(fn);
13094           }
13095           throw $injectorMinErr('strictdi',
13096             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
13097         }
13098         argDecl = extractArgs(fn);
13099         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
13100           arg.replace(FN_ARG, function(all, underscore, name) {
13101             $inject.push(name);
13102           });
13103         });
13104       }
13105       fn.$inject = $inject;
13106     }
13107   } else if (isArray(fn)) {
13108     last = fn.length - 1;
13109     assertArgFn(fn[last], 'fn');
13110     $inject = fn.slice(0, last);
13111   } else {
13112     assertArgFn(fn, 'fn', true);
13113   }
13114   return $inject;
13115 }
13116
13117 ///////////////////////////////////////
13118
13119 /**
13120  * @ngdoc service
13121  * @name $injector
13122  *
13123  * @description
13124  *
13125  * `$injector` is used to retrieve object instances as defined by
13126  * {@link auto.$provide provider}, instantiate types, invoke methods,
13127  * and load modules.
13128  *
13129  * The following always holds true:
13130  *
13131  * ```js
13132  *   var $injector = angular.injector();
13133  *   expect($injector.get('$injector')).toBe($injector);
13134  *   expect($injector.invoke(function($injector) {
13135  *     return $injector;
13136  *   })).toBe($injector);
13137  * ```
13138  *
13139  * # Injection Function Annotation
13140  *
13141  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
13142  * following are all valid ways of annotating function with injection arguments and are equivalent.
13143  *
13144  * ```js
13145  *   // inferred (only works if code not minified/obfuscated)
13146  *   $injector.invoke(function(serviceA){});
13147  *
13148  *   // annotated
13149  *   function explicit(serviceA) {};
13150  *   explicit.$inject = ['serviceA'];
13151  *   $injector.invoke(explicit);
13152  *
13153  *   // inline
13154  *   $injector.invoke(['serviceA', function(serviceA){}]);
13155  * ```
13156  *
13157  * ## Inference
13158  *
13159  * In JavaScript calling `toString()` on a function returns the function definition. The definition
13160  * can then be parsed and the function arguments can be extracted. This method of discovering
13161  * annotations is disallowed when the injector is in strict mode.
13162  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
13163  * argument names.
13164  *
13165  * ## `$inject` Annotation
13166  * By adding an `$inject` property onto a function the injection parameters can be specified.
13167  *
13168  * ## Inline
13169  * As an array of injection names, where the last item in the array is the function to call.
13170  */
13171
13172 /**
13173  * @ngdoc method
13174  * @name $injector#get
13175  *
13176  * @description
13177  * Return an instance of the service.
13178  *
13179  * @param {string} name The name of the instance to retrieve.
13180  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
13181  * @return {*} The instance.
13182  */
13183
13184 /**
13185  * @ngdoc method
13186  * @name $injector#invoke
13187  *
13188  * @description
13189  * Invoke the method and supply the method arguments from the `$injector`.
13190  *
13191  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
13192  *   injected according to the {@link guide/di $inject Annotation} rules.
13193  * @param {Object=} self The `this` for the invoked method.
13194  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13195  *                         object first, before the `$injector` is consulted.
13196  * @returns {*} the value returned by the invoked `fn` function.
13197  */
13198
13199 /**
13200  * @ngdoc method
13201  * @name $injector#has
13202  *
13203  * @description
13204  * Allows the user to query if the particular service exists.
13205  *
13206  * @param {string} name Name of the service to query.
13207  * @returns {boolean} `true` if injector has given service.
13208  */
13209
13210 /**
13211  * @ngdoc method
13212  * @name $injector#instantiate
13213  * @description
13214  * Create a new instance of JS type. The method takes a constructor function, invokes the new
13215  * operator, and supplies all of the arguments to the constructor function as specified by the
13216  * constructor annotation.
13217  *
13218  * @param {Function} Type Annotated constructor function.
13219  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13220  * object first, before the `$injector` is consulted.
13221  * @returns {Object} new instance of `Type`.
13222  */
13223
13224 /**
13225  * @ngdoc method
13226  * @name $injector#annotate
13227  *
13228  * @description
13229  * Returns an array of service names which the function is requesting for injection. This API is
13230  * used by the injector to determine which services need to be injected into the function when the
13231  * function is invoked. There are three ways in which the function can be annotated with the needed
13232  * dependencies.
13233  *
13234  * # Argument names
13235  *
13236  * The simplest form is to extract the dependencies from the arguments of the function. This is done
13237  * by converting the function into a string using `toString()` method and extracting the argument
13238  * names.
13239  * ```js
13240  *   // Given
13241  *   function MyController($scope, $route) {
13242  *     // ...
13243  *   }
13244  *
13245  *   // Then
13246  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13247  * ```
13248  *
13249  * You can disallow this method by using strict injection mode.
13250  *
13251  * This method does not work with code minification / obfuscation. For this reason the following
13252  * annotation strategies are supported.
13253  *
13254  * # The `$inject` property
13255  *
13256  * If a function has an `$inject` property and its value is an array of strings, then the strings
13257  * represent names of services to be injected into the function.
13258  * ```js
13259  *   // Given
13260  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
13261  *     // ...
13262  *   }
13263  *   // Define function dependencies
13264  *   MyController['$inject'] = ['$scope', '$route'];
13265  *
13266  *   // Then
13267  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13268  * ```
13269  *
13270  * # The array notation
13271  *
13272  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
13273  * is very inconvenient. In these situations using the array notation to specify the dependencies in
13274  * a way that survives minification is a better choice:
13275  *
13276  * ```js
13277  *   // We wish to write this (not minification / obfuscation safe)
13278  *   injector.invoke(function($compile, $rootScope) {
13279  *     // ...
13280  *   });
13281  *
13282  *   // We are forced to write break inlining
13283  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
13284  *     // ...
13285  *   };
13286  *   tmpFn.$inject = ['$compile', '$rootScope'];
13287  *   injector.invoke(tmpFn);
13288  *
13289  *   // To better support inline function the inline annotation is supported
13290  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
13291  *     // ...
13292  *   }]);
13293  *
13294  *   // Therefore
13295  *   expect(injector.annotate(
13296  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
13297  *    ).toEqual(['$compile', '$rootScope']);
13298  * ```
13299  *
13300  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
13301  * be retrieved as described above.
13302  *
13303  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
13304  *
13305  * @returns {Array.<string>} The names of the services which the function requires.
13306  */
13307
13308
13309
13310
13311 /**
13312  * @ngdoc service
13313  * @name $provide
13314  *
13315  * @description
13316  *
13317  * The {@link auto.$provide $provide} service has a number of methods for registering components
13318  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
13319  * {@link angular.Module}.
13320  *
13321  * An Angular **service** is a singleton object created by a **service factory**.  These **service
13322  * factories** are functions which, in turn, are created by a **service provider**.
13323  * The **service providers** are constructor functions. When instantiated they must contain a
13324  * property called `$get`, which holds the **service factory** function.
13325  *
13326  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
13327  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
13328  * function to get the instance of the **service**.
13329  *
13330  * Often services have no configuration options and there is no need to add methods to the service
13331  * provider.  The provider will be no more than a constructor function with a `$get` property. For
13332  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
13333  * services without specifying a provider.
13334  *
13335  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
13336  *     {@link auto.$injector $injector}
13337  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
13338  *     providers and services.
13339  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
13340  *     services, not providers.
13341  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
13342  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
13343  *     given factory function.
13344  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
13345  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
13346  *      a new object using the given constructor function.
13347  *
13348  * See the individual methods for more information and examples.
13349  */
13350
13351 /**
13352  * @ngdoc method
13353  * @name $provide#provider
13354  * @description
13355  *
13356  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
13357  * are constructor functions, whose instances are responsible for "providing" a factory for a
13358  * service.
13359  *
13360  * Service provider names start with the name of the service they provide followed by `Provider`.
13361  * For example, the {@link ng.$log $log} service has a provider called
13362  * {@link ng.$logProvider $logProvider}.
13363  *
13364  * Service provider objects can have additional methods which allow configuration of the provider
13365  * and its service. Importantly, you can configure what kind of service is created by the `$get`
13366  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
13367  * method {@link ng.$logProvider#debugEnabled debugEnabled}
13368  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
13369  * console or not.
13370  *
13371  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
13372                         'Provider'` key.
13373  * @param {(Object|function())} provider If the provider is:
13374  *
13375  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
13376  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
13377  *   - `Constructor`: a new instance of the provider will be created using
13378  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
13379  *
13380  * @returns {Object} registered provider instance
13381
13382  * @example
13383  *
13384  * The following example shows how to create a simple event tracking service and register it using
13385  * {@link auto.$provide#provider $provide.provider()}.
13386  *
13387  * ```js
13388  *  // Define the eventTracker provider
13389  *  function EventTrackerProvider() {
13390  *    var trackingUrl = '/track';
13391  *
13392  *    // A provider method for configuring where the tracked events should been saved
13393  *    this.setTrackingUrl = function(url) {
13394  *      trackingUrl = url;
13395  *    };
13396  *
13397  *    // The service factory function
13398  *    this.$get = ['$http', function($http) {
13399  *      var trackedEvents = {};
13400  *      return {
13401  *        // Call this to track an event
13402  *        event: function(event) {
13403  *          var count = trackedEvents[event] || 0;
13404  *          count += 1;
13405  *          trackedEvents[event] = count;
13406  *          return count;
13407  *        },
13408  *        // Call this to save the tracked events to the trackingUrl
13409  *        save: function() {
13410  *          $http.post(trackingUrl, trackedEvents);
13411  *        }
13412  *      };
13413  *    }];
13414  *  }
13415  *
13416  *  describe('eventTracker', function() {
13417  *    var postSpy;
13418  *
13419  *    beforeEach(module(function($provide) {
13420  *      // Register the eventTracker provider
13421  *      $provide.provider('eventTracker', EventTrackerProvider);
13422  *    }));
13423  *
13424  *    beforeEach(module(function(eventTrackerProvider) {
13425  *      // Configure eventTracker provider
13426  *      eventTrackerProvider.setTrackingUrl('/custom-track');
13427  *    }));
13428  *
13429  *    it('tracks events', inject(function(eventTracker) {
13430  *      expect(eventTracker.event('login')).toEqual(1);
13431  *      expect(eventTracker.event('login')).toEqual(2);
13432  *    }));
13433  *
13434  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
13435  *      postSpy = spyOn($http, 'post');
13436  *      eventTracker.event('login');
13437  *      eventTracker.save();
13438  *      expect(postSpy).toHaveBeenCalled();
13439  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
13440  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
13441  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
13442  *    }));
13443  *  });
13444  * ```
13445  */
13446
13447 /**
13448  * @ngdoc method
13449  * @name $provide#factory
13450  * @description
13451  *
13452  * Register a **service factory**, which will be called to return the service instance.
13453  * This is short for registering a service where its provider consists of only a `$get` property,
13454  * which is the given service factory function.
13455  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
13456  * configure your service in a provider.
13457  *
13458  * @param {string} name The name of the instance.
13459  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
13460  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
13461  * @returns {Object} registered provider instance
13462  *
13463  * @example
13464  * Here is an example of registering a service
13465  * ```js
13466  *   $provide.factory('ping', ['$http', function($http) {
13467  *     return function ping() {
13468  *       return $http.send('/ping');
13469  *     };
13470  *   }]);
13471  * ```
13472  * You would then inject and use this service like this:
13473  * ```js
13474  *   someModule.controller('Ctrl', ['ping', function(ping) {
13475  *     ping();
13476  *   }]);
13477  * ```
13478  */
13479
13480
13481 /**
13482  * @ngdoc method
13483  * @name $provide#service
13484  * @description
13485  *
13486  * Register a **service constructor**, which will be invoked with `new` to create the service
13487  * instance.
13488  * This is short for registering a service where its provider's `$get` property is a factory
13489  * function that returns an instance instantiated by the injector from the service constructor
13490  * function.
13491  *
13492  * Internally it looks a bit like this:
13493  *
13494  * ```
13495  * {
13496  *   $get: function() {
13497  *     return $injector.instantiate(constructor);
13498  *   }
13499  * }
13500  * ```
13501  *
13502  *
13503  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
13504  * as a type/class.
13505  *
13506  * @param {string} name The name of the instance.
13507  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
13508  *     that will be instantiated.
13509  * @returns {Object} registered provider instance
13510  *
13511  * @example
13512  * Here is an example of registering a service using
13513  * {@link auto.$provide#service $provide.service(class)}.
13514  * ```js
13515  *   var Ping = function($http) {
13516  *     this.$http = $http;
13517  *   };
13518  *
13519  *   Ping.$inject = ['$http'];
13520  *
13521  *   Ping.prototype.send = function() {
13522  *     return this.$http.get('/ping');
13523  *   };
13524  *   $provide.service('ping', Ping);
13525  * ```
13526  * You would then inject and use this service like this:
13527  * ```js
13528  *   someModule.controller('Ctrl', ['ping', function(ping) {
13529  *     ping.send();
13530  *   }]);
13531  * ```
13532  */
13533
13534
13535 /**
13536  * @ngdoc method
13537  * @name $provide#value
13538  * @description
13539  *
13540  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
13541  * number, an array, an object or a function. This is short for registering a service where its
13542  * provider's `$get` property is a factory function that takes no arguments and returns the **value
13543  * service**. That also means it is not possible to inject other services into a value service.
13544  *
13545  * Value services are similar to constant services, except that they cannot be injected into a
13546  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
13547  * an Angular {@link auto.$provide#decorator decorator}.
13548  *
13549  * @param {string} name The name of the instance.
13550  * @param {*} value The value.
13551  * @returns {Object} registered provider instance
13552  *
13553  * @example
13554  * Here are some examples of creating value services.
13555  * ```js
13556  *   $provide.value('ADMIN_USER', 'admin');
13557  *
13558  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
13559  *
13560  *   $provide.value('halfOf', function(value) {
13561  *     return value / 2;
13562  *   });
13563  * ```
13564  */
13565
13566
13567 /**
13568  * @ngdoc method
13569  * @name $provide#constant
13570  * @description
13571  *
13572  * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
13573  * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
13574  * possible to inject other services into a constant.
13575  *
13576  * But unlike {@link auto.$provide#value value}, a constant can be
13577  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
13578  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
13579  *
13580  * @param {string} name The name of the constant.
13581  * @param {*} value The constant value.
13582  * @returns {Object} registered instance
13583  *
13584  * @example
13585  * Here a some examples of creating constants:
13586  * ```js
13587  *   $provide.constant('SHARD_HEIGHT', 306);
13588  *
13589  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
13590  *
13591  *   $provide.constant('double', function(value) {
13592  *     return value * 2;
13593  *   });
13594  * ```
13595  */
13596
13597
13598 /**
13599  * @ngdoc method
13600  * @name $provide#decorator
13601  * @description
13602  *
13603  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
13604  * intercepts the creation of a service, allowing it to override or modify the behavior of the
13605  * service. The object returned by the decorator may be the original service, or a new service
13606  * object which replaces or wraps and delegates to the original service.
13607  *
13608  * @param {string} name The name of the service to decorate.
13609  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
13610  *    instantiated and should return the decorated service instance. The function is called using
13611  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
13612  *    Local injection arguments:
13613  *
13614  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
13615  *      decorated or delegated to.
13616  *
13617  * @example
13618  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
13619  * calls to {@link ng.$log#error $log.warn()}.
13620  * ```js
13621  *   $provide.decorator('$log', ['$delegate', function($delegate) {
13622  *     $delegate.warn = $delegate.error;
13623  *     return $delegate;
13624  *   }]);
13625  * ```
13626  */
13627
13628
13629 function createInjector(modulesToLoad, strictDi) {
13630   strictDi = (strictDi === true);
13631   var INSTANTIATING = {},
13632       providerSuffix = 'Provider',
13633       path = [],
13634       loadedModules = new HashMap([], true),
13635       providerCache = {
13636         $provide: {
13637             provider: supportObject(provider),
13638             factory: supportObject(factory),
13639             service: supportObject(service),
13640             value: supportObject(value),
13641             constant: supportObject(constant),
13642             decorator: decorator
13643           }
13644       },
13645       providerInjector = (providerCache.$injector =
13646           createInternalInjector(providerCache, function(serviceName, caller) {
13647             if (angular.isString(caller)) {
13648               path.push(caller);
13649             }
13650             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
13651           })),
13652       instanceCache = {},
13653       protoInstanceInjector =
13654           createInternalInjector(instanceCache, function(serviceName, caller) {
13655             var provider = providerInjector.get(serviceName + providerSuffix, caller);
13656             return instanceInjector.invoke(
13657                 provider.$get, provider, undefined, serviceName);
13658           }),
13659       instanceInjector = protoInstanceInjector;
13660
13661   providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
13662   var runBlocks = loadModules(modulesToLoad);
13663   instanceInjector = protoInstanceInjector.get('$injector');
13664   instanceInjector.strictDi = strictDi;
13665   forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
13666
13667   return instanceInjector;
13668
13669   ////////////////////////////////////
13670   // $provider
13671   ////////////////////////////////////
13672
13673   function supportObject(delegate) {
13674     return function(key, value) {
13675       if (isObject(key)) {
13676         forEach(key, reverseParams(delegate));
13677       } else {
13678         return delegate(key, value);
13679       }
13680     };
13681   }
13682
13683   function provider(name, provider_) {
13684     assertNotHasOwnProperty(name, 'service');
13685     if (isFunction(provider_) || isArray(provider_)) {
13686       provider_ = providerInjector.instantiate(provider_);
13687     }
13688     if (!provider_.$get) {
13689       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
13690     }
13691     return providerCache[name + providerSuffix] = provider_;
13692   }
13693
13694   function enforceReturnValue(name, factory) {
13695     return function enforcedReturnValue() {
13696       var result = instanceInjector.invoke(factory, this);
13697       if (isUndefined(result)) {
13698         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
13699       }
13700       return result;
13701     };
13702   }
13703
13704   function factory(name, factoryFn, enforce) {
13705     return provider(name, {
13706       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
13707     });
13708   }
13709
13710   function service(name, constructor) {
13711     return factory(name, ['$injector', function($injector) {
13712       return $injector.instantiate(constructor);
13713     }]);
13714   }
13715
13716   function value(name, val) { return factory(name, valueFn(val), false); }
13717
13718   function constant(name, value) {
13719     assertNotHasOwnProperty(name, 'constant');
13720     providerCache[name] = value;
13721     instanceCache[name] = value;
13722   }
13723
13724   function decorator(serviceName, decorFn) {
13725     var origProvider = providerInjector.get(serviceName + providerSuffix),
13726         orig$get = origProvider.$get;
13727
13728     origProvider.$get = function() {
13729       var origInstance = instanceInjector.invoke(orig$get, origProvider);
13730       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
13731     };
13732   }
13733
13734   ////////////////////////////////////
13735   // Module Loading
13736   ////////////////////////////////////
13737   function loadModules(modulesToLoad) {
13738     assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
13739     var runBlocks = [], moduleFn;
13740     forEach(modulesToLoad, function(module) {
13741       if (loadedModules.get(module)) return;
13742       loadedModules.put(module, true);
13743
13744       function runInvokeQueue(queue) {
13745         var i, ii;
13746         for (i = 0, ii = queue.length; i < ii; i++) {
13747           var invokeArgs = queue[i],
13748               provider = providerInjector.get(invokeArgs[0]);
13749
13750           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
13751         }
13752       }
13753
13754       try {
13755         if (isString(module)) {
13756           moduleFn = angularModule(module);
13757           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
13758           runInvokeQueue(moduleFn._invokeQueue);
13759           runInvokeQueue(moduleFn._configBlocks);
13760         } else if (isFunction(module)) {
13761             runBlocks.push(providerInjector.invoke(module));
13762         } else if (isArray(module)) {
13763             runBlocks.push(providerInjector.invoke(module));
13764         } else {
13765           assertArgFn(module, 'module');
13766         }
13767       } catch (e) {
13768         if (isArray(module)) {
13769           module = module[module.length - 1];
13770         }
13771         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
13772           // Safari & FF's stack traces don't contain error.message content
13773           // unlike those of Chrome and IE
13774           // So if stack doesn't contain message, we create a new string that contains both.
13775           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
13776           /* jshint -W022 */
13777           e = e.message + '\n' + e.stack;
13778         }
13779         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
13780                   module, e.stack || e.message || e);
13781       }
13782     });
13783     return runBlocks;
13784   }
13785
13786   ////////////////////////////////////
13787   // internal Injector
13788   ////////////////////////////////////
13789
13790   function createInternalInjector(cache, factory) {
13791
13792     function getService(serviceName, caller) {
13793       if (cache.hasOwnProperty(serviceName)) {
13794         if (cache[serviceName] === INSTANTIATING) {
13795           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
13796                     serviceName + ' <- ' + path.join(' <- '));
13797         }
13798         return cache[serviceName];
13799       } else {
13800         try {
13801           path.unshift(serviceName);
13802           cache[serviceName] = INSTANTIATING;
13803           return cache[serviceName] = factory(serviceName, caller);
13804         } catch (err) {
13805           if (cache[serviceName] === INSTANTIATING) {
13806             delete cache[serviceName];
13807           }
13808           throw err;
13809         } finally {
13810           path.shift();
13811         }
13812       }
13813     }
13814
13815
13816     function injectionArgs(fn, locals, serviceName) {
13817       var args = [],
13818           $inject = createInjector.$$annotate(fn, strictDi, serviceName);
13819
13820       for (var i = 0, length = $inject.length; i < length; i++) {
13821         var key = $inject[i];
13822         if (typeof key !== 'string') {
13823           throw $injectorMinErr('itkn',
13824                   'Incorrect injection token! Expected service name as string, got {0}', key);
13825         }
13826         args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
13827                                                          getService(key, serviceName));
13828       }
13829       return args;
13830     }
13831
13832     function isClass(func) {
13833       // IE 9-11 do not support classes and IE9 leaks with the code below.
13834       if (msie <= 11) {
13835         return false;
13836       }
13837       // Workaround for MS Edge.
13838       // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
13839       return typeof func === 'function'
13840         && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
13841     }
13842
13843     function invoke(fn, self, locals, serviceName) {
13844       if (typeof locals === 'string') {
13845         serviceName = locals;
13846         locals = null;
13847       }
13848
13849       var args = injectionArgs(fn, locals, serviceName);
13850       if (isArray(fn)) {
13851         fn = fn[fn.length - 1];
13852       }
13853
13854       if (!isClass(fn)) {
13855         // http://jsperf.com/angularjs-invoke-apply-vs-switch
13856         // #5388
13857         return fn.apply(self, args);
13858       } else {
13859         args.unshift(null);
13860         return new (Function.prototype.bind.apply(fn, args))();
13861       }
13862     }
13863
13864
13865     function instantiate(Type, locals, serviceName) {
13866       // Check if Type is annotated and use just the given function at n-1 as parameter
13867       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
13868       var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
13869       var args = injectionArgs(Type, locals, serviceName);
13870       // Empty object at position 0 is ignored for invocation with `new`, but required.
13871       args.unshift(null);
13872       return new (Function.prototype.bind.apply(ctor, args))();
13873     }
13874
13875
13876     return {
13877       invoke: invoke,
13878       instantiate: instantiate,
13879       get: getService,
13880       annotate: createInjector.$$annotate,
13881       has: function(name) {
13882         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
13883       }
13884     };
13885   }
13886 }
13887
13888 createInjector.$$annotate = annotate;
13889
13890 /**
13891  * @ngdoc provider
13892  * @name $anchorScrollProvider
13893  *
13894  * @description
13895  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
13896  * {@link ng.$location#hash $location.hash()} changes.
13897  */
13898 function $AnchorScrollProvider() {
13899
13900   var autoScrollingEnabled = true;
13901
13902   /**
13903    * @ngdoc method
13904    * @name $anchorScrollProvider#disableAutoScrolling
13905    *
13906    * @description
13907    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
13908    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
13909    * Use this method to disable automatic scrolling.
13910    *
13911    * If automatic scrolling is disabled, one must explicitly call
13912    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
13913    * current hash.
13914    */
13915   this.disableAutoScrolling = function() {
13916     autoScrollingEnabled = false;
13917   };
13918
13919   /**
13920    * @ngdoc service
13921    * @name $anchorScroll
13922    * @kind function
13923    * @requires $window
13924    * @requires $location
13925    * @requires $rootScope
13926    *
13927    * @description
13928    * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
13929    * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
13930    * in the
13931    * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
13932    *
13933    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
13934    * match any anchor whenever it changes. This can be disabled by calling
13935    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
13936    *
13937    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
13938    * vertical scroll-offset (either fixed or dynamic).
13939    *
13940    * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
13941    *                       {@link ng.$location#hash $location.hash()} will be used.
13942    *
13943    * @property {(number|function|jqLite)} yOffset
13944    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
13945    * positioned elements at the top of the page, such as navbars, headers etc.
13946    *
13947    * `yOffset` can be specified in various ways:
13948    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
13949    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
13950    *   a number representing the offset (in pixels).<br /><br />
13951    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
13952    *   the top of the page to the element's bottom will be used as offset.<br />
13953    *   **Note**: The element will be taken into account only as long as its `position` is set to
13954    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
13955    *   their height and/or positioning according to the viewport's size.
13956    *
13957    * <br />
13958    * <div class="alert alert-warning">
13959    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
13960    * not some child element.
13961    * </div>
13962    *
13963    * @example
13964      <example module="anchorScrollExample">
13965        <file name="index.html">
13966          <div id="scrollArea" ng-controller="ScrollController">
13967            <a ng-click="gotoBottom()">Go to bottom</a>
13968            <a id="bottom"></a> You're at the bottom!
13969          </div>
13970        </file>
13971        <file name="script.js">
13972          angular.module('anchorScrollExample', [])
13973            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
13974              function ($scope, $location, $anchorScroll) {
13975                $scope.gotoBottom = function() {
13976                  // set the location.hash to the id of
13977                  // the element you wish to scroll to.
13978                  $location.hash('bottom');
13979
13980                  // call $anchorScroll()
13981                  $anchorScroll();
13982                };
13983              }]);
13984        </file>
13985        <file name="style.css">
13986          #scrollArea {
13987            height: 280px;
13988            overflow: auto;
13989          }
13990
13991          #bottom {
13992            display: block;
13993            margin-top: 2000px;
13994          }
13995        </file>
13996      </example>
13997    *
13998    * <hr />
13999    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
14000    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
14001    *
14002    * @example
14003      <example module="anchorScrollOffsetExample">
14004        <file name="index.html">
14005          <div class="fixed-header" ng-controller="headerCtrl">
14006            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
14007              Go to anchor {{x}}
14008            </a>
14009          </div>
14010          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
14011            Anchor {{x}} of 5
14012          </div>
14013        </file>
14014        <file name="script.js">
14015          angular.module('anchorScrollOffsetExample', [])
14016            .run(['$anchorScroll', function($anchorScroll) {
14017              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
14018            }])
14019            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
14020              function ($anchorScroll, $location, $scope) {
14021                $scope.gotoAnchor = function(x) {
14022                  var newHash = 'anchor' + x;
14023                  if ($location.hash() !== newHash) {
14024                    // set the $location.hash to `newHash` and
14025                    // $anchorScroll will automatically scroll to it
14026                    $location.hash('anchor' + x);
14027                  } else {
14028                    // call $anchorScroll() explicitly,
14029                    // since $location.hash hasn't changed
14030                    $anchorScroll();
14031                  }
14032                };
14033              }
14034            ]);
14035        </file>
14036        <file name="style.css">
14037          body {
14038            padding-top: 50px;
14039          }
14040
14041          .anchor {
14042            border: 2px dashed DarkOrchid;
14043            padding: 10px 10px 200px 10px;
14044          }
14045
14046          .fixed-header {
14047            background-color: rgba(0, 0, 0, 0.2);
14048            height: 50px;
14049            position: fixed;
14050            top: 0; left: 0; right: 0;
14051          }
14052
14053          .fixed-header > a {
14054            display: inline-block;
14055            margin: 5px 15px;
14056          }
14057        </file>
14058      </example>
14059    */
14060   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
14061     var document = $window.document;
14062
14063     // Helper function to get first anchor from a NodeList
14064     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
14065     //  and working in all supported browsers.)
14066     function getFirstAnchor(list) {
14067       var result = null;
14068       Array.prototype.some.call(list, function(element) {
14069         if (nodeName_(element) === 'a') {
14070           result = element;
14071           return true;
14072         }
14073       });
14074       return result;
14075     }
14076
14077     function getYOffset() {
14078
14079       var offset = scroll.yOffset;
14080
14081       if (isFunction(offset)) {
14082         offset = offset();
14083       } else if (isElement(offset)) {
14084         var elem = offset[0];
14085         var style = $window.getComputedStyle(elem);
14086         if (style.position !== 'fixed') {
14087           offset = 0;
14088         } else {
14089           offset = elem.getBoundingClientRect().bottom;
14090         }
14091       } else if (!isNumber(offset)) {
14092         offset = 0;
14093       }
14094
14095       return offset;
14096     }
14097
14098     function scrollTo(elem) {
14099       if (elem) {
14100         elem.scrollIntoView();
14101
14102         var offset = getYOffset();
14103
14104         if (offset) {
14105           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
14106           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
14107           // top of the viewport.
14108           //
14109           // IF the number of pixels from the top of `elem` to the end of the page's content is less
14110           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
14111           // way down the page.
14112           //
14113           // This is often the case for elements near the bottom of the page.
14114           //
14115           // In such cases we do not need to scroll the whole `offset` up, just the difference between
14116           // the top of the element and the offset, which is enough to align the top of `elem` at the
14117           // desired position.
14118           var elemTop = elem.getBoundingClientRect().top;
14119           $window.scrollBy(0, elemTop - offset);
14120         }
14121       } else {
14122         $window.scrollTo(0, 0);
14123       }
14124     }
14125
14126     function scroll(hash) {
14127       hash = isString(hash) ? hash : $location.hash();
14128       var elm;
14129
14130       // empty hash, scroll to the top of the page
14131       if (!hash) scrollTo(null);
14132
14133       // element with given id
14134       else if ((elm = document.getElementById(hash))) scrollTo(elm);
14135
14136       // first anchor with given name :-D
14137       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
14138
14139       // no element and hash == 'top', scroll to the top of the page
14140       else if (hash === 'top') scrollTo(null);
14141     }
14142
14143     // does not scroll when user clicks on anchor link that is currently on
14144     // (no url change, no $location.hash() change), browser native does scroll
14145     if (autoScrollingEnabled) {
14146       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
14147         function autoScrollWatchAction(newVal, oldVal) {
14148           // skip the initial scroll if $location.hash is empty
14149           if (newVal === oldVal && newVal === '') return;
14150
14151           jqLiteDocumentLoaded(function() {
14152             $rootScope.$evalAsync(scroll);
14153           });
14154         });
14155     }
14156
14157     return scroll;
14158   }];
14159 }
14160
14161 var $animateMinErr = minErr('$animate');
14162 var ELEMENT_NODE = 1;
14163 var NG_ANIMATE_CLASSNAME = 'ng-animate';
14164
14165 function mergeClasses(a,b) {
14166   if (!a && !b) return '';
14167   if (!a) return b;
14168   if (!b) return a;
14169   if (isArray(a)) a = a.join(' ');
14170   if (isArray(b)) b = b.join(' ');
14171   return a + ' ' + b;
14172 }
14173
14174 function extractElementNode(element) {
14175   for (var i = 0; i < element.length; i++) {
14176     var elm = element[i];
14177     if (elm.nodeType === ELEMENT_NODE) {
14178       return elm;
14179     }
14180   }
14181 }
14182
14183 function splitClasses(classes) {
14184   if (isString(classes)) {
14185     classes = classes.split(' ');
14186   }
14187
14188   // Use createMap() to prevent class assumptions involving property names in
14189   // Object.prototype
14190   var obj = createMap();
14191   forEach(classes, function(klass) {
14192     // sometimes the split leaves empty string values
14193     // incase extra spaces were applied to the options
14194     if (klass.length) {
14195       obj[klass] = true;
14196     }
14197   });
14198   return obj;
14199 }
14200
14201 // if any other type of options value besides an Object value is
14202 // passed into the $animate.method() animation then this helper code
14203 // will be run which will ignore it. While this patch is not the
14204 // greatest solution to this, a lot of existing plugins depend on
14205 // $animate to either call the callback (< 1.2) or return a promise
14206 // that can be changed. This helper function ensures that the options
14207 // are wiped clean incase a callback function is provided.
14208 function prepareAnimateOptions(options) {
14209   return isObject(options)
14210       ? options
14211       : {};
14212 }
14213
14214 var $$CoreAnimateJsProvider = function() {
14215   this.$get = noop;
14216 };
14217
14218 // this is prefixed with Core since it conflicts with
14219 // the animateQueueProvider defined in ngAnimate/animateQueue.js
14220 var $$CoreAnimateQueueProvider = function() {
14221   var postDigestQueue = new HashMap();
14222   var postDigestElements = [];
14223
14224   this.$get = ['$$AnimateRunner', '$rootScope',
14225        function($$AnimateRunner,   $rootScope) {
14226     return {
14227       enabled: noop,
14228       on: noop,
14229       off: noop,
14230       pin: noop,
14231
14232       push: function(element, event, options, domOperation) {
14233         domOperation        && domOperation();
14234
14235         options = options || {};
14236         options.from        && element.css(options.from);
14237         options.to          && element.css(options.to);
14238
14239         if (options.addClass || options.removeClass) {
14240           addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
14241         }
14242
14243         var runner = new $$AnimateRunner(); // jshint ignore:line
14244
14245         // since there are no animations to run the runner needs to be
14246         // notified that the animation call is complete.
14247         runner.complete();
14248         return runner;
14249       }
14250     };
14251
14252
14253     function updateData(data, classes, value) {
14254       var changed = false;
14255       if (classes) {
14256         classes = isString(classes) ? classes.split(' ') :
14257                   isArray(classes) ? classes : [];
14258         forEach(classes, function(className) {
14259           if (className) {
14260             changed = true;
14261             data[className] = value;
14262           }
14263         });
14264       }
14265       return changed;
14266     }
14267
14268     function handleCSSClassChanges() {
14269       forEach(postDigestElements, function(element) {
14270         var data = postDigestQueue.get(element);
14271         if (data) {
14272           var existing = splitClasses(element.attr('class'));
14273           var toAdd = '';
14274           var toRemove = '';
14275           forEach(data, function(status, className) {
14276             var hasClass = !!existing[className];
14277             if (status !== hasClass) {
14278               if (status) {
14279                 toAdd += (toAdd.length ? ' ' : '') + className;
14280               } else {
14281                 toRemove += (toRemove.length ? ' ' : '') + className;
14282               }
14283             }
14284           });
14285
14286           forEach(element, function(elm) {
14287             toAdd    && jqLiteAddClass(elm, toAdd);
14288             toRemove && jqLiteRemoveClass(elm, toRemove);
14289           });
14290           postDigestQueue.remove(element);
14291         }
14292       });
14293       postDigestElements.length = 0;
14294     }
14295
14296
14297     function addRemoveClassesPostDigest(element, add, remove) {
14298       var data = postDigestQueue.get(element) || {};
14299
14300       var classesAdded = updateData(data, add, true);
14301       var classesRemoved = updateData(data, remove, false);
14302
14303       if (classesAdded || classesRemoved) {
14304
14305         postDigestQueue.put(element, data);
14306         postDigestElements.push(element);
14307
14308         if (postDigestElements.length === 1) {
14309           $rootScope.$$postDigest(handleCSSClassChanges);
14310         }
14311       }
14312     }
14313   }];
14314 };
14315
14316 /**
14317  * @ngdoc provider
14318  * @name $animateProvider
14319  *
14320  * @description
14321  * Default implementation of $animate that doesn't perform any animations, instead just
14322  * synchronously performs DOM updates and resolves the returned runner promise.
14323  *
14324  * In order to enable animations the `ngAnimate` module has to be loaded.
14325  *
14326  * To see the functional implementation check out `src/ngAnimate/animate.js`.
14327  */
14328 var $AnimateProvider = ['$provide', function($provide) {
14329   var provider = this;
14330
14331   this.$$registeredAnimations = Object.create(null);
14332
14333    /**
14334    * @ngdoc method
14335    * @name $animateProvider#register
14336    *
14337    * @description
14338    * Registers a new injectable animation factory function. The factory function produces the
14339    * animation object which contains callback functions for each event that is expected to be
14340    * animated.
14341    *
14342    *   * `eventFn`: `function(element, ... , doneFunction, options)`
14343    *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
14344    *   on the type of animation additional arguments will be injected into the animation function. The
14345    *   list below explains the function signatures for the different animation methods:
14346    *
14347    *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
14348    *   - addClass: function(element, addedClasses, doneFunction, options)
14349    *   - removeClass: function(element, removedClasses, doneFunction, options)
14350    *   - enter, leave, move: function(element, doneFunction, options)
14351    *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
14352    *
14353    *   Make sure to trigger the `doneFunction` once the animation is fully complete.
14354    *
14355    * ```js
14356    *   return {
14357    *     //enter, leave, move signature
14358    *     eventFn : function(element, done, options) {
14359    *       //code to run the animation
14360    *       //once complete, then run done()
14361    *       return function endFunction(wasCancelled) {
14362    *         //code to cancel the animation
14363    *       }
14364    *     }
14365    *   }
14366    * ```
14367    *
14368    * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
14369    * @param {Function} factory The factory function that will be executed to return the animation
14370    *                           object.
14371    */
14372   this.register = function(name, factory) {
14373     if (name && name.charAt(0) !== '.') {
14374       throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
14375     }
14376
14377     var key = name + '-animation';
14378     provider.$$registeredAnimations[name.substr(1)] = key;
14379     $provide.factory(key, factory);
14380   };
14381
14382   /**
14383    * @ngdoc method
14384    * @name $animateProvider#classNameFilter
14385    *
14386    * @description
14387    * Sets and/or returns the CSS class regular expression that is checked when performing
14388    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
14389    * therefore enable $animate to attempt to perform an animation on any element that is triggered.
14390    * When setting the `classNameFilter` value, animations will only be performed on elements
14391    * that successfully match the filter expression. This in turn can boost performance
14392    * for low-powered devices as well as applications containing a lot of structural operations.
14393    * @param {RegExp=} expression The className expression which will be checked against all animations
14394    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
14395    */
14396   this.classNameFilter = function(expression) {
14397     if (arguments.length === 1) {
14398       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
14399       if (this.$$classNameFilter) {
14400         var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
14401         if (reservedRegex.test(this.$$classNameFilter.toString())) {
14402           throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
14403
14404         }
14405       }
14406     }
14407     return this.$$classNameFilter;
14408   };
14409
14410   this.$get = ['$$animateQueue', function($$animateQueue) {
14411     function domInsert(element, parentElement, afterElement) {
14412       // if for some reason the previous element was removed
14413       // from the dom sometime before this code runs then let's
14414       // just stick to using the parent element as the anchor
14415       if (afterElement) {
14416         var afterNode = extractElementNode(afterElement);
14417         if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
14418           afterElement = null;
14419         }
14420       }
14421       afterElement ? afterElement.after(element) : parentElement.prepend(element);
14422     }
14423
14424     /**
14425      * @ngdoc service
14426      * @name $animate
14427      * @description The $animate service exposes a series of DOM utility methods that provide support
14428      * for animation hooks. The default behavior is the application of DOM operations, however,
14429      * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
14430      * to ensure that animation runs with the triggered DOM operation.
14431      *
14432      * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
14433      * included and only when it is active then the animation hooks that `$animate` triggers will be
14434      * functional. Once active then all structural `ng-` directives will trigger animations as they perform
14435      * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
14436      * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
14437      *
14438      * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
14439      *
14440      * To learn more about enabling animation support, click here to visit the
14441      * {@link ngAnimate ngAnimate module page}.
14442      */
14443     return {
14444       // we don't call it directly since non-existant arguments may
14445       // be interpreted as null within the sub enabled function
14446
14447       /**
14448        *
14449        * @ngdoc method
14450        * @name $animate#on
14451        * @kind function
14452        * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
14453        *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
14454        *    is fired with the following params:
14455        *
14456        * ```js
14457        * $animate.on('enter', container,
14458        *    function callback(element, phase) {
14459        *      // cool we detected an enter animation within the container
14460        *    }
14461        * );
14462        * ```
14463        *
14464        * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
14465        * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
14466        *     as well as among its children
14467        * @param {Function} callback the callback function that will be fired when the listener is triggered
14468        *
14469        * The arguments present in the callback function are:
14470        * * `element` - The captured DOM element that the animation was fired on.
14471        * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
14472        */
14473       on: $$animateQueue.on,
14474
14475       /**
14476        *
14477        * @ngdoc method
14478        * @name $animate#off
14479        * @kind function
14480        * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
14481        * can be used in three different ways depending on the arguments:
14482        *
14483        * ```js
14484        * // remove all the animation event listeners listening for `enter`
14485        * $animate.off('enter');
14486        *
14487        * // remove listeners for all animation events from the container element
14488        * $animate.off(container);
14489        *
14490        * // remove all the animation event listeners listening for `enter` on the given element and its children
14491        * $animate.off('enter', container);
14492        *
14493        * // remove the event listener function provided by `callback` that is set
14494        * // to listen for `enter` on the given `container` as well as its children
14495        * $animate.off('enter', container, callback);
14496        * ```
14497        *
14498        * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
14499        * addClass, removeClass, etc...), or the container element. If it is the element, all other
14500        * arguments are ignored.
14501        * @param {DOMElement=} container the container element the event listener was placed on
14502        * @param {Function=} callback the callback function that was registered as the listener
14503        */
14504       off: $$animateQueue.off,
14505
14506       /**
14507        * @ngdoc method
14508        * @name $animate#pin
14509        * @kind function
14510        * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
14511        *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
14512        *    element despite being outside the realm of the application or within another application. Say for example if the application
14513        *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
14514        *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
14515        *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
14516        *
14517        *    Note that this feature is only active when the `ngAnimate` module is used.
14518        *
14519        * @param {DOMElement} element the external element that will be pinned
14520        * @param {DOMElement} parentElement the host parent element that will be associated with the external element
14521        */
14522       pin: $$animateQueue.pin,
14523
14524       /**
14525        *
14526        * @ngdoc method
14527        * @name $animate#enabled
14528        * @kind function
14529        * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
14530        * function can be called in four ways:
14531        *
14532        * ```js
14533        * // returns true or false
14534        * $animate.enabled();
14535        *
14536        * // changes the enabled state for all animations
14537        * $animate.enabled(false);
14538        * $animate.enabled(true);
14539        *
14540        * // returns true or false if animations are enabled for an element
14541        * $animate.enabled(element);
14542        *
14543        * // changes the enabled state for an element and its children
14544        * $animate.enabled(element, true);
14545        * $animate.enabled(element, false);
14546        * ```
14547        *
14548        * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
14549        * @param {boolean=} enabled whether or not the animations will be enabled for the element
14550        *
14551        * @return {boolean} whether or not animations are enabled
14552        */
14553       enabled: $$animateQueue.enabled,
14554
14555       /**
14556        * @ngdoc method
14557        * @name $animate#cancel
14558        * @kind function
14559        * @description Cancels the provided animation.
14560        *
14561        * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
14562        */
14563       cancel: function(runner) {
14564         runner.end && runner.end();
14565       },
14566
14567       /**
14568        *
14569        * @ngdoc method
14570        * @name $animate#enter
14571        * @kind function
14572        * @description Inserts the element into the DOM either after the `after` element (if provided) or
14573        *   as the first child within the `parent` element and then triggers an animation.
14574        *   A promise is returned that will be resolved during the next digest once the animation
14575        *   has completed.
14576        *
14577        * @param {DOMElement} element the element which will be inserted into the DOM
14578        * @param {DOMElement} parent the parent element which will append the element as
14579        *   a child (so long as the after element is not present)
14580        * @param {DOMElement=} after the sibling element after which the element will be appended
14581        * @param {object=} options an optional collection of options/styles that will be applied to the element
14582        *
14583        * @return {Promise} the animation callback promise
14584        */
14585       enter: function(element, parent, after, options) {
14586         parent = parent && jqLite(parent);
14587         after = after && jqLite(after);
14588         parent = parent || after.parent();
14589         domInsert(element, parent, after);
14590         return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
14591       },
14592
14593       /**
14594        *
14595        * @ngdoc method
14596        * @name $animate#move
14597        * @kind function
14598        * @description Inserts (moves) the element into its new position in the DOM either after
14599        *   the `after` element (if provided) or as the first child within the `parent` element
14600        *   and then triggers an animation. A promise is returned that will be resolved
14601        *   during the next digest once the animation has completed.
14602        *
14603        * @param {DOMElement} element the element which will be moved into the new DOM position
14604        * @param {DOMElement} parent the parent element which will append the element as
14605        *   a child (so long as the after element is not present)
14606        * @param {DOMElement=} after the sibling element after which the element will be appended
14607        * @param {object=} options an optional collection of options/styles that will be applied to the element
14608        *
14609        * @return {Promise} the animation callback promise
14610        */
14611       move: function(element, parent, after, options) {
14612         parent = parent && jqLite(parent);
14613         after = after && jqLite(after);
14614         parent = parent || after.parent();
14615         domInsert(element, parent, after);
14616         return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
14617       },
14618
14619       /**
14620        * @ngdoc method
14621        * @name $animate#leave
14622        * @kind function
14623        * @description Triggers an animation and then removes the element from the DOM.
14624        * When the function is called a promise is returned that will be resolved during the next
14625        * digest once the animation has completed.
14626        *
14627        * @param {DOMElement} element the element which will be removed from the DOM
14628        * @param {object=} options an optional collection of options/styles that will be applied to the element
14629        *
14630        * @return {Promise} the animation callback promise
14631        */
14632       leave: function(element, options) {
14633         return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
14634           element.remove();
14635         });
14636       },
14637
14638       /**
14639        * @ngdoc method
14640        * @name $animate#addClass
14641        * @kind function
14642        *
14643        * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
14644        *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
14645        *   animation if element already contains the CSS class or if the class is removed at a later step.
14646        *   Note that class-based animations are treated differently compared to structural animations
14647        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14648        *   depending if CSS or JavaScript animations are used.
14649        *
14650        * @param {DOMElement} element the element which the CSS classes will be applied to
14651        * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
14652        * @param {object=} options an optional collection of options/styles that will be applied to the element
14653        *
14654        * @return {Promise} the animation callback promise
14655        */
14656       addClass: function(element, className, options) {
14657         options = prepareAnimateOptions(options);
14658         options.addClass = mergeClasses(options.addclass, className);
14659         return $$animateQueue.push(element, 'addClass', options);
14660       },
14661
14662       /**
14663        * @ngdoc method
14664        * @name $animate#removeClass
14665        * @kind function
14666        *
14667        * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
14668        *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
14669        *   animation if element does not contain the CSS class or if the class is added at a later step.
14670        *   Note that class-based animations are treated differently compared to structural animations
14671        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14672        *   depending if CSS or JavaScript animations are used.
14673        *
14674        * @param {DOMElement} element the element which the CSS classes will be applied to
14675        * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
14676        * @param {object=} options an optional collection of options/styles that will be applied to the element
14677        *
14678        * @return {Promise} the animation callback promise
14679        */
14680       removeClass: function(element, className, options) {
14681         options = prepareAnimateOptions(options);
14682         options.removeClass = mergeClasses(options.removeClass, className);
14683         return $$animateQueue.push(element, 'removeClass', options);
14684       },
14685
14686       /**
14687        * @ngdoc method
14688        * @name $animate#setClass
14689        * @kind function
14690        *
14691        * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
14692        *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
14693        *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
14694        *    passed. Note that class-based animations are treated differently compared to structural animations
14695        *    (like enter, move and leave) since the CSS classes may be added/removed at different points
14696        *    depending if CSS or JavaScript animations are used.
14697        *
14698        * @param {DOMElement} element the element which the CSS classes will be applied to
14699        * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
14700        * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
14701        * @param {object=} options an optional collection of options/styles that will be applied to the element
14702        *
14703        * @return {Promise} the animation callback promise
14704        */
14705       setClass: function(element, add, remove, options) {
14706         options = prepareAnimateOptions(options);
14707         options.addClass = mergeClasses(options.addClass, add);
14708         options.removeClass = mergeClasses(options.removeClass, remove);
14709         return $$animateQueue.push(element, 'setClass', options);
14710       },
14711
14712       /**
14713        * @ngdoc method
14714        * @name $animate#animate
14715        * @kind function
14716        *
14717        * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
14718        * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
14719        * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
14720        * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
14721        * style in `to`, the style in `from` is applied immediately, and no animation is run.
14722        * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
14723        * method (or as part of the `options` parameter):
14724        *
14725        * ```js
14726        * ngModule.animation('.my-inline-animation', function() {
14727        *   return {
14728        *     animate : function(element, from, to, done, options) {
14729        *       //animation
14730        *       done();
14731        *     }
14732        *   }
14733        * });
14734        * ```
14735        *
14736        * @param {DOMElement} element the element which the CSS styles will be applied to
14737        * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
14738        * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
14739        * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
14740        *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
14741        *    (Note that if no animation is detected then this value will not be applied to the element.)
14742        * @param {object=} options an optional collection of options/styles that will be applied to the element
14743        *
14744        * @return {Promise} the animation callback promise
14745        */
14746       animate: function(element, from, to, className, options) {
14747         options = prepareAnimateOptions(options);
14748         options.from = options.from ? extend(options.from, from) : from;
14749         options.to   = options.to   ? extend(options.to, to)     : to;
14750
14751         className = className || 'ng-inline-animate';
14752         options.tempClasses = mergeClasses(options.tempClasses, className);
14753         return $$animateQueue.push(element, 'animate', options);
14754       }
14755     };
14756   }];
14757 }];
14758
14759 var $$AnimateAsyncRunFactoryProvider = function() {
14760   this.$get = ['$$rAF', function($$rAF) {
14761     var waitQueue = [];
14762
14763     function waitForTick(fn) {
14764       waitQueue.push(fn);
14765       if (waitQueue.length > 1) return;
14766       $$rAF(function() {
14767         for (var i = 0; i < waitQueue.length; i++) {
14768           waitQueue[i]();
14769         }
14770         waitQueue = [];
14771       });
14772     }
14773
14774     return function() {
14775       var passed = false;
14776       waitForTick(function() {
14777         passed = true;
14778       });
14779       return function(callback) {
14780         passed ? callback() : waitForTick(callback);
14781       };
14782     };
14783   }];
14784 };
14785
14786 var $$AnimateRunnerFactoryProvider = function() {
14787   this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
14788        function($q,   $sniffer,   $$animateAsyncRun,   $document,   $timeout) {
14789
14790     var INITIAL_STATE = 0;
14791     var DONE_PENDING_STATE = 1;
14792     var DONE_COMPLETE_STATE = 2;
14793
14794     AnimateRunner.chain = function(chain, callback) {
14795       var index = 0;
14796
14797       next();
14798       function next() {
14799         if (index === chain.length) {
14800           callback(true);
14801           return;
14802         }
14803
14804         chain[index](function(response) {
14805           if (response === false) {
14806             callback(false);
14807             return;
14808           }
14809           index++;
14810           next();
14811         });
14812       }
14813     };
14814
14815     AnimateRunner.all = function(runners, callback) {
14816       var count = 0;
14817       var status = true;
14818       forEach(runners, function(runner) {
14819         runner.done(onProgress);
14820       });
14821
14822       function onProgress(response) {
14823         status = status && response;
14824         if (++count === runners.length) {
14825           callback(status);
14826         }
14827       }
14828     };
14829
14830     function AnimateRunner(host) {
14831       this.setHost(host);
14832
14833       var rafTick = $$animateAsyncRun();
14834       var timeoutTick = function(fn) {
14835         $timeout(fn, 0, false);
14836       };
14837
14838       this._doneCallbacks = [];
14839       this._tick = function(fn) {
14840         var doc = $document[0];
14841
14842         // the document may not be ready or attached
14843         // to the module for some internal tests
14844         if (doc && doc.hidden) {
14845           timeoutTick(fn);
14846         } else {
14847           rafTick(fn);
14848         }
14849       };
14850       this._state = 0;
14851     }
14852
14853     AnimateRunner.prototype = {
14854       setHost: function(host) {
14855         this.host = host || {};
14856       },
14857
14858       done: function(fn) {
14859         if (this._state === DONE_COMPLETE_STATE) {
14860           fn();
14861         } else {
14862           this._doneCallbacks.push(fn);
14863         }
14864       },
14865
14866       progress: noop,
14867
14868       getPromise: function() {
14869         if (!this.promise) {
14870           var self = this;
14871           this.promise = $q(function(resolve, reject) {
14872             self.done(function(status) {
14873               status === false ? reject() : resolve();
14874             });
14875           });
14876         }
14877         return this.promise;
14878       },
14879
14880       then: function(resolveHandler, rejectHandler) {
14881         return this.getPromise().then(resolveHandler, rejectHandler);
14882       },
14883
14884       'catch': function(handler) {
14885         return this.getPromise()['catch'](handler);
14886       },
14887
14888       'finally': function(handler) {
14889         return this.getPromise()['finally'](handler);
14890       },
14891
14892       pause: function() {
14893         if (this.host.pause) {
14894           this.host.pause();
14895         }
14896       },
14897
14898       resume: function() {
14899         if (this.host.resume) {
14900           this.host.resume();
14901         }
14902       },
14903
14904       end: function() {
14905         if (this.host.end) {
14906           this.host.end();
14907         }
14908         this._resolve(true);
14909       },
14910
14911       cancel: function() {
14912         if (this.host.cancel) {
14913           this.host.cancel();
14914         }
14915         this._resolve(false);
14916       },
14917
14918       complete: function(response) {
14919         var self = this;
14920         if (self._state === INITIAL_STATE) {
14921           self._state = DONE_PENDING_STATE;
14922           self._tick(function() {
14923             self._resolve(response);
14924           });
14925         }
14926       },
14927
14928       _resolve: function(response) {
14929         if (this._state !== DONE_COMPLETE_STATE) {
14930           forEach(this._doneCallbacks, function(fn) {
14931             fn(response);
14932           });
14933           this._doneCallbacks.length = 0;
14934           this._state = DONE_COMPLETE_STATE;
14935         }
14936       }
14937     };
14938
14939     return AnimateRunner;
14940   }];
14941 };
14942
14943 /**
14944  * @ngdoc service
14945  * @name $animateCss
14946  * @kind object
14947  *
14948  * @description
14949  * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
14950  * then the `$animateCss` service will actually perform animations.
14951  *
14952  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
14953  */
14954 var $CoreAnimateCssProvider = function() {
14955   this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
14956
14957     return function(element, initialOptions) {
14958       // all of the animation functions should create
14959       // a copy of the options data, however, if a
14960       // parent service has already created a copy then
14961       // we should stick to using that
14962       var options = initialOptions || {};
14963       if (!options.$$prepared) {
14964         options = copy(options);
14965       }
14966
14967       // there is no point in applying the styles since
14968       // there is no animation that goes on at all in
14969       // this version of $animateCss.
14970       if (options.cleanupStyles) {
14971         options.from = options.to = null;
14972       }
14973
14974       if (options.from) {
14975         element.css(options.from);
14976         options.from = null;
14977       }
14978
14979       /* jshint newcap: false */
14980       var closed, runner = new $$AnimateRunner();
14981       return {
14982         start: run,
14983         end: run
14984       };
14985
14986       function run() {
14987         $$rAF(function() {
14988           applyAnimationContents();
14989           if (!closed) {
14990             runner.complete();
14991           }
14992           closed = true;
14993         });
14994         return runner;
14995       }
14996
14997       function applyAnimationContents() {
14998         if (options.addClass) {
14999           element.addClass(options.addClass);
15000           options.addClass = null;
15001         }
15002         if (options.removeClass) {
15003           element.removeClass(options.removeClass);
15004           options.removeClass = null;
15005         }
15006         if (options.to) {
15007           element.css(options.to);
15008           options.to = null;
15009         }
15010       }
15011     };
15012   }];
15013 };
15014
15015 /* global stripHash: true */
15016
15017 /**
15018  * ! This is a private undocumented service !
15019  *
15020  * @name $browser
15021  * @requires $log
15022  * @description
15023  * This object has two goals:
15024  *
15025  * - hide all the global state in the browser caused by the window object
15026  * - abstract away all the browser specific features and inconsistencies
15027  *
15028  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
15029  * service, which can be used for convenient testing of the application without the interaction with
15030  * the real browser apis.
15031  */
15032 /**
15033  * @param {object} window The global window object.
15034  * @param {object} document jQuery wrapped document.
15035  * @param {object} $log window.console or an object with the same interface.
15036  * @param {object} $sniffer $sniffer service
15037  */
15038 function Browser(window, document, $log, $sniffer) {
15039   var self = this,
15040       location = window.location,
15041       history = window.history,
15042       setTimeout = window.setTimeout,
15043       clearTimeout = window.clearTimeout,
15044       pendingDeferIds = {};
15045
15046   self.isMock = false;
15047
15048   var outstandingRequestCount = 0;
15049   var outstandingRequestCallbacks = [];
15050
15051   // TODO(vojta): remove this temporary api
15052   self.$$completeOutstandingRequest = completeOutstandingRequest;
15053   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
15054
15055   /**
15056    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
15057    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
15058    */
15059   function completeOutstandingRequest(fn) {
15060     try {
15061       fn.apply(null, sliceArgs(arguments, 1));
15062     } finally {
15063       outstandingRequestCount--;
15064       if (outstandingRequestCount === 0) {
15065         while (outstandingRequestCallbacks.length) {
15066           try {
15067             outstandingRequestCallbacks.pop()();
15068           } catch (e) {
15069             $log.error(e);
15070           }
15071         }
15072       }
15073     }
15074   }
15075
15076   function getHash(url) {
15077     var index = url.indexOf('#');
15078     return index === -1 ? '' : url.substr(index);
15079   }
15080
15081   /**
15082    * @private
15083    * Note: this method is used only by scenario runner
15084    * TODO(vojta): prefix this method with $$ ?
15085    * @param {function()} callback Function that will be called when no outstanding request
15086    */
15087   self.notifyWhenNoOutstandingRequests = function(callback) {
15088     if (outstandingRequestCount === 0) {
15089       callback();
15090     } else {
15091       outstandingRequestCallbacks.push(callback);
15092     }
15093   };
15094
15095   //////////////////////////////////////////////////////////////
15096   // URL API
15097   //////////////////////////////////////////////////////////////
15098
15099   var cachedState, lastHistoryState,
15100       lastBrowserUrl = location.href,
15101       baseElement = document.find('base'),
15102       pendingLocation = null,
15103       getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
15104         try {
15105           return history.state;
15106         } catch (e) {
15107           // MSIE can reportedly throw when there is no state (UNCONFIRMED).
15108         }
15109       };
15110
15111   cacheState();
15112   lastHistoryState = cachedState;
15113
15114   /**
15115    * @name $browser#url
15116    *
15117    * @description
15118    * GETTER:
15119    * Without any argument, this method just returns current value of location.href.
15120    *
15121    * SETTER:
15122    * With at least one argument, this method sets url to new value.
15123    * If html5 history api supported, pushState/replaceState is used, otherwise
15124    * location.href/location.replace is used.
15125    * Returns its own instance to allow chaining
15126    *
15127    * NOTE: this api is intended for use only by the $location service. Please use the
15128    * {@link ng.$location $location service} to change url.
15129    *
15130    * @param {string} url New url (when used as setter)
15131    * @param {boolean=} replace Should new url replace current history record?
15132    * @param {object=} state object to use with pushState/replaceState
15133    */
15134   self.url = function(url, replace, state) {
15135     // In modern browsers `history.state` is `null` by default; treating it separately
15136     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
15137     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
15138     if (isUndefined(state)) {
15139       state = null;
15140     }
15141
15142     // Android Browser BFCache causes location, history reference to become stale.
15143     if (location !== window.location) location = window.location;
15144     if (history !== window.history) history = window.history;
15145
15146     // setter
15147     if (url) {
15148       var sameState = lastHistoryState === state;
15149
15150       // Don't change anything if previous and current URLs and states match. This also prevents
15151       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
15152       // See https://github.com/angular/angular.js/commit/ffb2701
15153       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
15154         return self;
15155       }
15156       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
15157       lastBrowserUrl = url;
15158       lastHistoryState = state;
15159       // Don't use history API if only the hash changed
15160       // due to a bug in IE10/IE11 which leads
15161       // to not firing a `hashchange` nor `popstate` event
15162       // in some cases (see #9143).
15163       if ($sniffer.history && (!sameBase || !sameState)) {
15164         history[replace ? 'replaceState' : 'pushState'](state, '', url);
15165         cacheState();
15166         // Do the assignment again so that those two variables are referentially identical.
15167         lastHistoryState = cachedState;
15168       } else {
15169         if (!sameBase || pendingLocation) {
15170           pendingLocation = url;
15171         }
15172         if (replace) {
15173           location.replace(url);
15174         } else if (!sameBase) {
15175           location.href = url;
15176         } else {
15177           location.hash = getHash(url);
15178         }
15179         if (location.href !== url) {
15180           pendingLocation = url;
15181         }
15182       }
15183       return self;
15184     // getter
15185     } else {
15186       // - pendingLocation is needed as browsers don't allow to read out
15187       //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
15188       //   https://openradar.appspot.com/22186109).
15189       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
15190       return pendingLocation || location.href.replace(/%27/g,"'");
15191     }
15192   };
15193
15194   /**
15195    * @name $browser#state
15196    *
15197    * @description
15198    * This method is a getter.
15199    *
15200    * Return history.state or null if history.state is undefined.
15201    *
15202    * @returns {object} state
15203    */
15204   self.state = function() {
15205     return cachedState;
15206   };
15207
15208   var urlChangeListeners = [],
15209       urlChangeInit = false;
15210
15211   function cacheStateAndFireUrlChange() {
15212     pendingLocation = null;
15213     cacheState();
15214     fireUrlChange();
15215   }
15216
15217   // This variable should be used *only* inside the cacheState function.
15218   var lastCachedState = null;
15219   function cacheState() {
15220     // This should be the only place in $browser where `history.state` is read.
15221     cachedState = getCurrentState();
15222     cachedState = isUndefined(cachedState) ? null : cachedState;
15223
15224     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
15225     if (equals(cachedState, lastCachedState)) {
15226       cachedState = lastCachedState;
15227     }
15228     lastCachedState = cachedState;
15229   }
15230
15231   function fireUrlChange() {
15232     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
15233       return;
15234     }
15235
15236     lastBrowserUrl = self.url();
15237     lastHistoryState = cachedState;
15238     forEach(urlChangeListeners, function(listener) {
15239       listener(self.url(), cachedState);
15240     });
15241   }
15242
15243   /**
15244    * @name $browser#onUrlChange
15245    *
15246    * @description
15247    * Register callback function that will be called, when url changes.
15248    *
15249    * It's only called when the url is changed from outside of angular:
15250    * - user types different url into address bar
15251    * - user clicks on history (forward/back) button
15252    * - user clicks on a link
15253    *
15254    * It's not called when url is changed by $browser.url() method
15255    *
15256    * The listener gets called with new url as parameter.
15257    *
15258    * NOTE: this api is intended for use only by the $location service. Please use the
15259    * {@link ng.$location $location service} to monitor url changes in angular apps.
15260    *
15261    * @param {function(string)} listener Listener function to be called when url changes.
15262    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
15263    */
15264   self.onUrlChange = function(callback) {
15265     // TODO(vojta): refactor to use node's syntax for events
15266     if (!urlChangeInit) {
15267       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
15268       // don't fire popstate when user change the address bar and don't fire hashchange when url
15269       // changed by push/replaceState
15270
15271       // html5 history api - popstate event
15272       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
15273       // hashchange event
15274       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
15275
15276       urlChangeInit = true;
15277     }
15278
15279     urlChangeListeners.push(callback);
15280     return callback;
15281   };
15282
15283   /**
15284    * @private
15285    * Remove popstate and hashchange handler from window.
15286    *
15287    * NOTE: this api is intended for use only by $rootScope.
15288    */
15289   self.$$applicationDestroyed = function() {
15290     jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
15291   };
15292
15293   /**
15294    * Checks whether the url has changed outside of Angular.
15295    * Needs to be exported to be able to check for changes that have been done in sync,
15296    * as hashchange/popstate events fire in async.
15297    */
15298   self.$$checkUrlChange = fireUrlChange;
15299
15300   //////////////////////////////////////////////////////////////
15301   // Misc API
15302   //////////////////////////////////////////////////////////////
15303
15304   /**
15305    * @name $browser#baseHref
15306    *
15307    * @description
15308    * Returns current <base href>
15309    * (always relative - without domain)
15310    *
15311    * @returns {string} The current base href
15312    */
15313   self.baseHref = function() {
15314     var href = baseElement.attr('href');
15315     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
15316   };
15317
15318   /**
15319    * @name $browser#defer
15320    * @param {function()} fn A function, who's execution should be deferred.
15321    * @param {number=} [delay=0] of milliseconds to defer the function execution.
15322    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
15323    *
15324    * @description
15325    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
15326    *
15327    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
15328    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
15329    * via `$browser.defer.flush()`.
15330    *
15331    */
15332   self.defer = function(fn, delay) {
15333     var timeoutId;
15334     outstandingRequestCount++;
15335     timeoutId = setTimeout(function() {
15336       delete pendingDeferIds[timeoutId];
15337       completeOutstandingRequest(fn);
15338     }, delay || 0);
15339     pendingDeferIds[timeoutId] = true;
15340     return timeoutId;
15341   };
15342
15343
15344   /**
15345    * @name $browser#defer.cancel
15346    *
15347    * @description
15348    * Cancels a deferred task identified with `deferId`.
15349    *
15350    * @param {*} deferId Token returned by the `$browser.defer` function.
15351    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
15352    *                    canceled.
15353    */
15354   self.defer.cancel = function(deferId) {
15355     if (pendingDeferIds[deferId]) {
15356       delete pendingDeferIds[deferId];
15357       clearTimeout(deferId);
15358       completeOutstandingRequest(noop);
15359       return true;
15360     }
15361     return false;
15362   };
15363
15364 }
15365
15366 function $BrowserProvider() {
15367   this.$get = ['$window', '$log', '$sniffer', '$document',
15368       function($window, $log, $sniffer, $document) {
15369         return new Browser($window, $document, $log, $sniffer);
15370       }];
15371 }
15372
15373 /**
15374  * @ngdoc service
15375  * @name $cacheFactory
15376  *
15377  * @description
15378  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
15379  * them.
15380  *
15381  * ```js
15382  *
15383  *  var cache = $cacheFactory('cacheId');
15384  *  expect($cacheFactory.get('cacheId')).toBe(cache);
15385  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
15386  *
15387  *  cache.put("key", "value");
15388  *  cache.put("another key", "another value");
15389  *
15390  *  // We've specified no options on creation
15391  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
15392  *
15393  * ```
15394  *
15395  *
15396  * @param {string} cacheId Name or id of the newly created cache.
15397  * @param {object=} options Options object that specifies the cache behavior. Properties:
15398  *
15399  *   - `{number=}` `capacity` â€” turns the cache into LRU cache.
15400  *
15401  * @returns {object} Newly created cache object with the following set of methods:
15402  *
15403  * - `{object}` `info()` â€” Returns id, size, and options of cache.
15404  * - `{{*}}` `put({string} key, {*} value)` â€” Puts a new key-value pair into the cache and returns
15405  *   it.
15406  * - `{{*}}` `get({string} key)` â€” Returns cached value for `key` or undefined for cache miss.
15407  * - `{void}` `remove({string} key)` â€” Removes a key-value pair from the cache.
15408  * - `{void}` `removeAll()` â€” Removes all cached values.
15409  * - `{void}` `destroy()` â€” Removes references to this cache from $cacheFactory.
15410  *
15411  * @example
15412    <example module="cacheExampleApp">
15413      <file name="index.html">
15414        <div ng-controller="CacheController">
15415          <input ng-model="newCacheKey" placeholder="Key">
15416          <input ng-model="newCacheValue" placeholder="Value">
15417          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
15418
15419          <p ng-if="keys.length">Cached Values</p>
15420          <div ng-repeat="key in keys">
15421            <span ng-bind="key"></span>
15422            <span>: </span>
15423            <b ng-bind="cache.get(key)"></b>
15424          </div>
15425
15426          <p>Cache Info</p>
15427          <div ng-repeat="(key, value) in cache.info()">
15428            <span ng-bind="key"></span>
15429            <span>: </span>
15430            <b ng-bind="value"></b>
15431          </div>
15432        </div>
15433      </file>
15434      <file name="script.js">
15435        angular.module('cacheExampleApp', []).
15436          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
15437            $scope.keys = [];
15438            $scope.cache = $cacheFactory('cacheId');
15439            $scope.put = function(key, value) {
15440              if (angular.isUndefined($scope.cache.get(key))) {
15441                $scope.keys.push(key);
15442              }
15443              $scope.cache.put(key, angular.isUndefined(value) ? null : value);
15444            };
15445          }]);
15446      </file>
15447      <file name="style.css">
15448        p {
15449          margin: 10px 0 3px;
15450        }
15451      </file>
15452    </example>
15453  */
15454 function $CacheFactoryProvider() {
15455
15456   this.$get = function() {
15457     var caches = {};
15458
15459     function cacheFactory(cacheId, options) {
15460       if (cacheId in caches) {
15461         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
15462       }
15463
15464       var size = 0,
15465           stats = extend({}, options, {id: cacheId}),
15466           data = createMap(),
15467           capacity = (options && options.capacity) || Number.MAX_VALUE,
15468           lruHash = createMap(),
15469           freshEnd = null,
15470           staleEnd = null;
15471
15472       /**
15473        * @ngdoc type
15474        * @name $cacheFactory.Cache
15475        *
15476        * @description
15477        * A cache object used to store and retrieve data, primarily used by
15478        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
15479        * templates and other data.
15480        *
15481        * ```js
15482        *  angular.module('superCache')
15483        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
15484        *      return $cacheFactory('super-cache');
15485        *    }]);
15486        * ```
15487        *
15488        * Example test:
15489        *
15490        * ```js
15491        *  it('should behave like a cache', inject(function(superCache) {
15492        *    superCache.put('key', 'value');
15493        *    superCache.put('another key', 'another value');
15494        *
15495        *    expect(superCache.info()).toEqual({
15496        *      id: 'super-cache',
15497        *      size: 2
15498        *    });
15499        *
15500        *    superCache.remove('another key');
15501        *    expect(superCache.get('another key')).toBeUndefined();
15502        *
15503        *    superCache.removeAll();
15504        *    expect(superCache.info()).toEqual({
15505        *      id: 'super-cache',
15506        *      size: 0
15507        *    });
15508        *  }));
15509        * ```
15510        */
15511       return caches[cacheId] = {
15512
15513         /**
15514          * @ngdoc method
15515          * @name $cacheFactory.Cache#put
15516          * @kind function
15517          *
15518          * @description
15519          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
15520          * retrieved later, and incrementing the size of the cache if the key was not already
15521          * present in the cache. If behaving like an LRU cache, it will also remove stale
15522          * entries from the set.
15523          *
15524          * It will not insert undefined values into the cache.
15525          *
15526          * @param {string} key the key under which the cached data is stored.
15527          * @param {*} value the value to store alongside the key. If it is undefined, the key
15528          *    will not be stored.
15529          * @returns {*} the value stored.
15530          */
15531         put: function(key, value) {
15532           if (isUndefined(value)) return;
15533           if (capacity < Number.MAX_VALUE) {
15534             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
15535
15536             refresh(lruEntry);
15537           }
15538
15539           if (!(key in data)) size++;
15540           data[key] = value;
15541
15542           if (size > capacity) {
15543             this.remove(staleEnd.key);
15544           }
15545
15546           return value;
15547         },
15548
15549         /**
15550          * @ngdoc method
15551          * @name $cacheFactory.Cache#get
15552          * @kind function
15553          *
15554          * @description
15555          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
15556          *
15557          * @param {string} key the key of the data to be retrieved
15558          * @returns {*} the value stored.
15559          */
15560         get: function(key) {
15561           if (capacity < Number.MAX_VALUE) {
15562             var lruEntry = lruHash[key];
15563
15564             if (!lruEntry) return;
15565
15566             refresh(lruEntry);
15567           }
15568
15569           return data[key];
15570         },
15571
15572
15573         /**
15574          * @ngdoc method
15575          * @name $cacheFactory.Cache#remove
15576          * @kind function
15577          *
15578          * @description
15579          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
15580          *
15581          * @param {string} key the key of the entry to be removed
15582          */
15583         remove: function(key) {
15584           if (capacity < Number.MAX_VALUE) {
15585             var lruEntry = lruHash[key];
15586
15587             if (!lruEntry) return;
15588
15589             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
15590             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
15591             link(lruEntry.n,lruEntry.p);
15592
15593             delete lruHash[key];
15594           }
15595
15596           if (!(key in data)) return;
15597
15598           delete data[key];
15599           size--;
15600         },
15601
15602
15603         /**
15604          * @ngdoc method
15605          * @name $cacheFactory.Cache#removeAll
15606          * @kind function
15607          *
15608          * @description
15609          * Clears the cache object of any entries.
15610          */
15611         removeAll: function() {
15612           data = createMap();
15613           size = 0;
15614           lruHash = createMap();
15615           freshEnd = staleEnd = null;
15616         },
15617
15618
15619         /**
15620          * @ngdoc method
15621          * @name $cacheFactory.Cache#destroy
15622          * @kind function
15623          *
15624          * @description
15625          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
15626          * removing it from the {@link $cacheFactory $cacheFactory} set.
15627          */
15628         destroy: function() {
15629           data = null;
15630           stats = null;
15631           lruHash = null;
15632           delete caches[cacheId];
15633         },
15634
15635
15636         /**
15637          * @ngdoc method
15638          * @name $cacheFactory.Cache#info
15639          * @kind function
15640          *
15641          * @description
15642          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
15643          *
15644          * @returns {object} an object with the following properties:
15645          *   <ul>
15646          *     <li>**id**: the id of the cache instance</li>
15647          *     <li>**size**: the number of entries kept in the cache instance</li>
15648          *     <li>**...**: any additional properties from the options object when creating the
15649          *       cache.</li>
15650          *   </ul>
15651          */
15652         info: function() {
15653           return extend({}, stats, {size: size});
15654         }
15655       };
15656
15657
15658       /**
15659        * makes the `entry` the freshEnd of the LRU linked list
15660        */
15661       function refresh(entry) {
15662         if (entry != freshEnd) {
15663           if (!staleEnd) {
15664             staleEnd = entry;
15665           } else if (staleEnd == entry) {
15666             staleEnd = entry.n;
15667           }
15668
15669           link(entry.n, entry.p);
15670           link(entry, freshEnd);
15671           freshEnd = entry;
15672           freshEnd.n = null;
15673         }
15674       }
15675
15676
15677       /**
15678        * bidirectionally links two entries of the LRU linked list
15679        */
15680       function link(nextEntry, prevEntry) {
15681         if (nextEntry != prevEntry) {
15682           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
15683           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
15684         }
15685       }
15686     }
15687
15688
15689   /**
15690    * @ngdoc method
15691    * @name $cacheFactory#info
15692    *
15693    * @description
15694    * Get information about all the caches that have been created
15695    *
15696    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
15697    */
15698     cacheFactory.info = function() {
15699       var info = {};
15700       forEach(caches, function(cache, cacheId) {
15701         info[cacheId] = cache.info();
15702       });
15703       return info;
15704     };
15705
15706
15707   /**
15708    * @ngdoc method
15709    * @name $cacheFactory#get
15710    *
15711    * @description
15712    * Get access to a cache object by the `cacheId` used when it was created.
15713    *
15714    * @param {string} cacheId Name or id of a cache to access.
15715    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
15716    */
15717     cacheFactory.get = function(cacheId) {
15718       return caches[cacheId];
15719     };
15720
15721
15722     return cacheFactory;
15723   };
15724 }
15725
15726 /**
15727  * @ngdoc service
15728  * @name $templateCache
15729  *
15730  * @description
15731  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
15732  * can load templates directly into the cache in a `script` tag, or by consuming the
15733  * `$templateCache` service directly.
15734  *
15735  * Adding via the `script` tag:
15736  *
15737  * ```html
15738  *   <script type="text/ng-template" id="templateId.html">
15739  *     <p>This is the content of the template</p>
15740  *   </script>
15741  * ```
15742  *
15743  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
15744  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
15745  * element with ng-app attribute), otherwise the template will be ignored.
15746  *
15747  * Adding via the `$templateCache` service:
15748  *
15749  * ```js
15750  * var myApp = angular.module('myApp', []);
15751  * myApp.run(function($templateCache) {
15752  *   $templateCache.put('templateId.html', 'This is the content of the template');
15753  * });
15754  * ```
15755  *
15756  * To retrieve the template later, simply use it in your HTML:
15757  * ```html
15758  * <div ng-include=" 'templateId.html' "></div>
15759  * ```
15760  *
15761  * or get it via Javascript:
15762  * ```js
15763  * $templateCache.get('templateId.html')
15764  * ```
15765  *
15766  * See {@link ng.$cacheFactory $cacheFactory}.
15767  *
15768  */
15769 function $TemplateCacheProvider() {
15770   this.$get = ['$cacheFactory', function($cacheFactory) {
15771     return $cacheFactory('templates');
15772   }];
15773 }
15774
15775 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15776  *     Any commits to this file should be reviewed with security in mind.  *
15777  *   Changes to this file can potentially create security vulnerabilities. *
15778  *          An approval from 2 Core members with history of modifying      *
15779  *                         this file is required.                          *
15780  *                                                                         *
15781  *  Does the change somehow allow for arbitrary javascript to be executed? *
15782  *    Or allows for someone to change the prototype of built-in objects?   *
15783  *     Or gives undesired access to variables likes document or window?    *
15784  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15785
15786 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
15787  *
15788  * DOM-related variables:
15789  *
15790  * - "node" - DOM Node
15791  * - "element" - DOM Element or Node
15792  * - "$node" or "$element" - jqLite-wrapped node or element
15793  *
15794  *
15795  * Compiler related stuff:
15796  *
15797  * - "linkFn" - linking fn of a single directive
15798  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
15799  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
15800  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
15801  */
15802
15803
15804 /**
15805  * @ngdoc service
15806  * @name $compile
15807  * @kind function
15808  *
15809  * @description
15810  * Compiles an HTML string or DOM into a template and produces a template function, which
15811  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
15812  *
15813  * The compilation is a process of walking the DOM tree and matching DOM elements to
15814  * {@link ng.$compileProvider#directive directives}.
15815  *
15816  * <div class="alert alert-warning">
15817  * **Note:** This document is an in-depth reference of all directive options.
15818  * For a gentle introduction to directives with examples of common use cases,
15819  * see the {@link guide/directive directive guide}.
15820  * </div>
15821  *
15822  * ## Comprehensive Directive API
15823  *
15824  * There are many different options for a directive.
15825  *
15826  * The difference resides in the return value of the factory function.
15827  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
15828  * or just the `postLink` function (all other properties will have the default values).
15829  *
15830  * <div class="alert alert-success">
15831  * **Best Practice:** It's recommended to use the "directive definition object" form.
15832  * </div>
15833  *
15834  * Here's an example directive declared with a Directive Definition Object:
15835  *
15836  * ```js
15837  *   var myModule = angular.module(...);
15838  *
15839  *   myModule.directive('directiveName', function factory(injectables) {
15840  *     var directiveDefinitionObject = {
15841  *       priority: 0,
15842  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
15843  *       // or
15844  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
15845  *       transclude: false,
15846  *       restrict: 'A',
15847  *       templateNamespace: 'html',
15848  *       scope: false,
15849  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
15850  *       controllerAs: 'stringIdentifier',
15851  *       bindToController: false,
15852  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
15853  *       compile: function compile(tElement, tAttrs, transclude) {
15854  *         return {
15855  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15856  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
15857  *         }
15858  *         // or
15859  *         // return function postLink( ... ) { ... }
15860  *       },
15861  *       // or
15862  *       // link: {
15863  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15864  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
15865  *       // }
15866  *       // or
15867  *       // link: function postLink( ... ) { ... }
15868  *     };
15869  *     return directiveDefinitionObject;
15870  *   });
15871  * ```
15872  *
15873  * <div class="alert alert-warning">
15874  * **Note:** Any unspecified options will use the default value. You can see the default values below.
15875  * </div>
15876  *
15877  * Therefore the above can be simplified as:
15878  *
15879  * ```js
15880  *   var myModule = angular.module(...);
15881  *
15882  *   myModule.directive('directiveName', function factory(injectables) {
15883  *     var directiveDefinitionObject = {
15884  *       link: function postLink(scope, iElement, iAttrs) { ... }
15885  *     };
15886  *     return directiveDefinitionObject;
15887  *     // or
15888  *     // return function postLink(scope, iElement, iAttrs) { ... }
15889  *   });
15890  * ```
15891  *
15892  *
15893  *
15894  * ### Directive Definition Object
15895  *
15896  * The directive definition object provides instructions to the {@link ng.$compile
15897  * compiler}. The attributes are:
15898  *
15899  * #### `multiElement`
15900  * When this property is set to true, the HTML compiler will collect DOM nodes between
15901  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
15902  * together as the directive elements. It is recommended that this feature be used on directives
15903  * which are not strictly behavioral (such as {@link ngClick}), and which
15904  * do not manipulate or replace child nodes (such as {@link ngInclude}).
15905  *
15906  * #### `priority`
15907  * When there are multiple directives defined on a single DOM element, sometimes it
15908  * is necessary to specify the order in which the directives are applied. The `priority` is used
15909  * to sort the directives before their `compile` functions get called. Priority is defined as a
15910  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
15911  * are also run in priority order, but post-link functions are run in reverse order. The order
15912  * of directives with the same priority is undefined. The default priority is `0`.
15913  *
15914  * #### `terminal`
15915  * If set to true then the current `priority` will be the last set of directives
15916  * which will execute (any directives at the current priority will still execute
15917  * as the order of execution on same `priority` is undefined). Note that expressions
15918  * and other directives used in the directive's template will also be excluded from execution.
15919  *
15920  * #### `scope`
15921  * The scope property can be `true`, an object or a falsy value:
15922  *
15923  * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
15924  *
15925  * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
15926  * the directive's element. If multiple directives on the same element request a new scope,
15927  * only one new scope is created. The new scope rule does not apply for the root of the template
15928  * since the root of the template always gets a new scope.
15929  *
15930  * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
15931  * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
15932  * scope. This is useful when creating reusable components, which should not accidentally read or modify
15933  * data in the parent scope.
15934  *
15935  * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
15936  * directive's element. These local properties are useful for aliasing values for templates. The keys in
15937  * the object hash map to the name of the property on the isolate scope; the values define how the property
15938  * is bound to the parent scope, via matching attributes on the directive's element:
15939  *
15940  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
15941  *   always a string since DOM attributes are strings. If no `attr` name is specified then the
15942  *   attribute name is assumed to be the same as the local name. Given `<my-component
15943  *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
15944  *   the directive's scope property `localName` will reflect the interpolated value of `hello
15945  *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
15946  *   scope. The `name` is read from the parent scope (not the directive's scope).
15947  *
15948  * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
15949  *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
15950  *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
15951  *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
15952  *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
15953  *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
15954  *   `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
15955  *   `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
15956  *   optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
15957  *   will be thrown upon discovering changes to the local value, since it will be impossible to sync
15958  *   them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
15959  *   method is used for tracking changes, and the equality check is based on object identity.
15960  *   However, if an object literal or an array literal is passed as the binding expression, the
15961  *   equality check is done by value (using the {@link angular.equals} function). It's also possible
15962  *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
15963  *   `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
15964  *
15965   * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
15966  *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
15967  *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
15968  *   local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
15969  *
15970  *   For example, given `<my-component my-attr="parentModel">` and directive definition of
15971  *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
15972  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
15973  *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
15974  *   two caveats:
15975  *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
15976  *     sets the same value. That means if your bound value is an object, changes to its properties
15977  *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
15978  *     2. one-way binding watches changes to the **identity** of the parent value. That means the
15979  *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
15980  *     to the value has changed. In most cases, this should not be of concern, but can be important
15981  *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
15982  *     If you now change a property of the object in your parent scope, the change will not be
15983  *     propagated to the isolated scope, because the identity of the object on the parent scope
15984  *     has not changed. Instead you must assign a new object.
15985  *
15986  *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
15987  *   back to the parent. However, it does not make this completely impossible.
15988  *
15989  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
15990  *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
15991  *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
15992  *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
15993  *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
15994  *   via an expression to the parent scope. This can be done by passing a map of local variable names
15995  *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
15996  *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
15997  *
15998  * In general it's possible to apply more than one directive to one element, but there might be limitations
15999  * depending on the type of scope required by the directives. The following points will help explain these limitations.
16000  * For simplicity only two directives are taken into account, but it is also applicable for several directives:
16001  *
16002  * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
16003  * * **child scope** + **no scope** =>  Both directives will share one single child scope
16004  * * **child scope** + **child scope** =>  Both directives will share one single child scope
16005  * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
16006  * its parent's scope
16007  * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
16008  * be applied to the same element.
16009  * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
16010  * cannot be applied to the same element.
16011  *
16012  *
16013  * #### `bindToController`
16014  * This property is used to bind scope properties directly to the controller. It can be either
16015  * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
16016  * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
16017  * definition: `controller: 'myCtrl as myAlias'`.
16018  *
16019  * When an isolate scope is used for a directive (see above), `bindToController: true` will
16020  * allow a component to have its properties bound to the controller, rather than to scope.
16021  *
16022  * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
16023  * properties. You can access these bindings once they have been initialized by providing a controller method called
16024  * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
16025  * initialized.
16026  *
16027  * <div class="alert alert-warning">
16028  * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
16029  * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
16030  * code that relies upon bindings inside a `$onInit` method on the controller, instead.
16031  * </div>
16032  *
16033  * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
16034  * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
16035  * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
16036  * scope (useful for component directives).
16037  *
16038  * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
16039  *
16040  *
16041  * #### `controller`
16042  * Controller constructor function. The controller is instantiated before the
16043  * pre-linking phase and can be accessed by other directives (see
16044  * `require` attribute). This allows the directives to communicate with each other and augment
16045  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
16046  *
16047  * * `$scope` - Current scope associated with the element
16048  * * `$element` - Current element
16049  * * `$attrs` - Current attributes object for the element
16050  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
16051  *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
16052  *    * `scope`: (optional) override the scope.
16053  *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
16054  *    * `futureParentElement` (optional):
16055  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
16056  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
16057  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
16058  *          and when the `cloneLinkinFn` is passed,
16059  *          as those elements need to created and cloned in a special way when they are defined outside their
16060  *          usual containers (e.g. like `<svg>`).
16061  *        * See also the `directive.templateNamespace` property.
16062  *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
16063  *      then the default translusion is provided.
16064  *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
16065  *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
16066  *
16067  * The controller can provide the following methods that act as life-cycle hooks:
16068  * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
16069  *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
16070  *   this element). This is a good place to put initialization code for your controller.
16071  * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
16072  *   `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
16073  *   object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
16074  *   component such as cloning the bound value to prevent accidental mutation of the outer value.
16075  * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
16076  *   external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
16077  *   the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
16078  *   components will have their `$onDestroy()` hook called before child components.
16079  * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
16080  *   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
16081  *   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
16082  *   they are waiting for their template to load asynchronously and their own compilation and linking has been
16083  *   suspended until that occurs.
16084  *
16085  *
16086  * #### `require`
16087  * Require another directive and inject its controller as the fourth argument to the linking function. The
16088  * `require` property can be a string, an array or an object:
16089  * * a **string** containing the name of the directive to pass to the linking function
16090  * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
16091  * linking function will be an array of controllers in the same order as the names in the `require` property
16092  * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
16093  * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
16094  * controllers.
16095  *
16096  * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
16097  * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
16098  * have been constructed but before `$onInit` is called.
16099  * See the {@link $compileProvider#component} helper for an example of how this can be used.
16100  *
16101  * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
16102  * raised (unless no link function is specified and the required controllers are not being bound to the directive
16103  * controller, in which case error checking is skipped). The name can be prefixed with:
16104  *
16105  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
16106  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
16107  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
16108  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
16109  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
16110  *   `null` to the `link` fn if not found.
16111  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
16112  *   `null` to the `link` fn if not found.
16113  *
16114  *
16115  * #### `controllerAs`
16116  * Identifier name for a reference to the controller in the directive's scope.
16117  * This allows the controller to be referenced from the directive template. This is especially
16118  * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
16119  * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
16120  * `controllerAs` reference might overwrite a property that already exists on the parent scope.
16121  *
16122  *
16123  * #### `restrict`
16124  * String of subset of `EACM` which restricts the directive to a specific directive
16125  * declaration style. If omitted, the defaults (elements and attributes) are used.
16126  *
16127  * * `E` - Element name (default): `<my-directive></my-directive>`
16128  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
16129  * * `C` - Class: `<div class="my-directive: exp;"></div>`
16130  * * `M` - Comment: `<!-- directive: my-directive exp -->`
16131  *
16132  *
16133  * #### `templateNamespace`
16134  * String representing the document type used by the markup in the template.
16135  * AngularJS needs this information as those elements need to be created and cloned
16136  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
16137  *
16138  * * `html` - All root nodes in the template are HTML. Root nodes may also be
16139  *   top-level elements such as `<svg>` or `<math>`.
16140  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
16141  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
16142  *
16143  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
16144  *
16145  * #### `template`
16146  * HTML markup that may:
16147  * * Replace the contents of the directive's element (default).
16148  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
16149  * * Wrap the contents of the directive's element (if `transclude` is true).
16150  *
16151  * Value may be:
16152  *
16153  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
16154  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
16155  *   function api below) and returns a string value.
16156  *
16157  *
16158  * #### `templateUrl`
16159  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
16160  *
16161  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
16162  * for later when the template has been resolved.  In the meantime it will continue to compile and link
16163  * sibling and parent elements as though this element had not contained any directives.
16164  *
16165  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
16166  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
16167  * case when only one deeply nested directive has `templateUrl`.
16168  *
16169  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
16170  *
16171  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
16172  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
16173  * a string value representing the url.  In either case, the template URL is passed through {@link
16174  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
16175  *
16176  *
16177  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
16178  * specify what the template should replace. Defaults to `false`.
16179  *
16180  * * `true` - the template will replace the directive's element.
16181  * * `false` - the template will replace the contents of the directive's element.
16182  *
16183  * The replacement process migrates all of the attributes / classes from the old element to the new
16184  * one. See the {@link guide/directive#template-expanding-directive
16185  * Directives Guide} for an example.
16186  *
16187  * There are very few scenarios where element replacement is required for the application function,
16188  * the main one being reusable custom components that are used within SVG contexts
16189  * (because SVG doesn't work with custom elements in the DOM tree).
16190  *
16191  * #### `transclude`
16192  * Extract the contents of the element where the directive appears and make it available to the directive.
16193  * The contents are compiled and provided to the directive as a **transclusion function**. See the
16194  * {@link $compile#transclusion Transclusion} section below.
16195  *
16196  *
16197  * #### `compile`
16198  *
16199  * ```js
16200  *   function compile(tElement, tAttrs, transclude) { ... }
16201  * ```
16202  *
16203  * The compile function deals with transforming the template DOM. Since most directives do not do
16204  * template transformation, it is not used often. The compile function takes the following arguments:
16205  *
16206  *   * `tElement` - template element - The element where the directive has been declared. It is
16207  *     safe to do template transformation on the element and child elements only.
16208  *
16209  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
16210  *     between all directive compile functions.
16211  *
16212  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
16213  *
16214  * <div class="alert alert-warning">
16215  * **Note:** The template instance and the link instance may be different objects if the template has
16216  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
16217  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
16218  * should be done in a linking function rather than in a compile function.
16219  * </div>
16220
16221  * <div class="alert alert-warning">
16222  * **Note:** The compile function cannot handle directives that recursively use themselves in their
16223  * own templates or compile functions. Compiling these directives results in an infinite loop and
16224  * stack overflow errors.
16225  *
16226  * This can be avoided by manually using $compile in the postLink function to imperatively compile
16227  * a directive's template instead of relying on automatic template compilation via `template` or
16228  * `templateUrl` declaration or manual compilation inside the compile function.
16229  * </div>
16230  *
16231  * <div class="alert alert-danger">
16232  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
16233  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
16234  *   to the link function instead.
16235  * </div>
16236
16237  * A compile function can have a return value which can be either a function or an object.
16238  *
16239  * * returning a (post-link) function - is equivalent to registering the linking function via the
16240  *   `link` property of the config object when the compile function is empty.
16241  *
16242  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
16243  *   control when a linking function should be called during the linking phase. See info about
16244  *   pre-linking and post-linking functions below.
16245  *
16246  *
16247  * #### `link`
16248  * This property is used only if the `compile` property is not defined.
16249  *
16250  * ```js
16251  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
16252  * ```
16253  *
16254  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
16255  * executed after the template has been cloned. This is where most of the directive logic will be
16256  * put.
16257  *
16258  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
16259  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
16260  *
16261  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
16262  *     manipulate the children of the element only in `postLink` function since the children have
16263  *     already been linked.
16264  *
16265  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
16266  *     between all directive linking functions.
16267  *
16268  *   * `controller` - the directive's required controller instance(s) - Instances are shared
16269  *     among all directives, which allows the directives to use the controllers as a communication
16270  *     channel. The exact value depends on the directive's `require` property:
16271  *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
16272  *       * `string`: the controller instance
16273  *       * `array`: array of controller instances
16274  *
16275  *     If a required controller cannot be found, and it is optional, the instance is `null`,
16276  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
16277  *
16278  *     Note that you can also require the directive's own controller - it will be made available like
16279  *     any other controller.
16280  *
16281  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
16282  *     This is the same as the `$transclude`
16283  *     parameter of directive controllers, see there for details.
16284  *     `function([scope], cloneLinkingFn, futureParentElement)`.
16285  *
16286  * #### Pre-linking function
16287  *
16288  * Executed before the child elements are linked. Not safe to do DOM transformation since the
16289  * compiler linking function will fail to locate the correct elements for linking.
16290  *
16291  * #### Post-linking function
16292  *
16293  * Executed after the child elements are linked.
16294  *
16295  * Note that child elements that contain `templateUrl` directives will not have been compiled
16296  * and linked since they are waiting for their template to load asynchronously and their own
16297  * compilation and linking has been suspended until that occurs.
16298  *
16299  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
16300  * for their async templates to be resolved.
16301  *
16302  *
16303  * ### Transclusion
16304  *
16305  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
16306  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
16307  * scope from where they were taken.
16308  *
16309  * Transclusion is used (often with {@link ngTransclude}) to insert the
16310  * original contents of a directive's element into a specified place in the template of the directive.
16311  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
16312  * content has access to the properties on the scope from which it was taken, even if the directive
16313  * has isolated scope.
16314  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
16315  *
16316  * This makes it possible for the widget to have private state for its template, while the transcluded
16317  * content has access to its originating scope.
16318  *
16319  * <div class="alert alert-warning">
16320  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
16321  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
16322  * Testing Transclusion Directives}.
16323  * </div>
16324  *
16325  * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
16326  * directive's element, the entire element or multiple parts of the element contents:
16327  *
16328  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
16329  * * `'element'` - transclude the whole of the directive's element including any directives on this
16330  *   element that defined at a lower priority than this directive. When used, the `template`
16331  *   property is ignored.
16332  * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
16333  *
16334  * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
16335  *
16336  * This object is a map where the keys are the name of the slot to fill and the value is an element selector
16337  * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
16338  * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
16339  *
16340  * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
16341  *
16342  * If the element selector is prefixed with a `?` then that slot is optional.
16343  *
16344  * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
16345  * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
16346  *
16347  * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
16348  * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
16349  * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
16350  * injectable into the directive's controller.
16351  *
16352  *
16353  * #### Transclusion Functions
16354  *
16355  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
16356  * function** to the directive's `link` function and `controller`. This transclusion function is a special
16357  * **linking function** that will return the compiled contents linked to a new transclusion scope.
16358  *
16359  * <div class="alert alert-info">
16360  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
16361  * ngTransclude will deal with it for us.
16362  * </div>
16363  *
16364  * If you want to manually control the insertion and removal of the transcluded content in your directive
16365  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
16366  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
16367  *
16368  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
16369  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
16370  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
16371  *
16372  * <div class="alert alert-info">
16373  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
16374  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
16375  * </div>
16376  *
16377  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
16378  * attach function**:
16379  *
16380  * ```js
16381  * var transcludedContent, transclusionScope;
16382  *
16383  * $transclude(function(clone, scope) {
16384  *   element.append(clone);
16385  *   transcludedContent = clone;
16386  *   transclusionScope = scope;
16387  * });
16388  * ```
16389  *
16390  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
16391  * associated transclusion scope:
16392  *
16393  * ```js
16394  * transcludedContent.remove();
16395  * transclusionScope.$destroy();
16396  * ```
16397  *
16398  * <div class="alert alert-info">
16399  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
16400  * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
16401  * then you are also responsible for calling `$destroy` on the transclusion scope.
16402  * </div>
16403  *
16404  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
16405  * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
16406  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
16407  *
16408  *
16409  * #### Transclusion Scopes
16410  *
16411  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
16412  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
16413  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
16414  * was taken.
16415  *
16416  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
16417  * like this:
16418  *
16419  * ```html
16420  * <div ng-app>
16421  *   <div isolate>
16422  *     <div transclusion>
16423  *     </div>
16424  *   </div>
16425  * </div>
16426  * ```
16427  *
16428  * The `$parent` scope hierarchy will look like this:
16429  *
16430    ```
16431    - $rootScope
16432      - isolate
16433        - transclusion
16434    ```
16435  *
16436  * but the scopes will inherit prototypically from different scopes to their `$parent`.
16437  *
16438    ```
16439    - $rootScope
16440      - transclusion
16441    - isolate
16442    ```
16443  *
16444  *
16445  * ### Attributes
16446  *
16447  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
16448  * `link()` or `compile()` functions. It has a variety of uses.
16449  *
16450  * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
16451  *   'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
16452  *   to the attributes.
16453  *
16454  * * *Directive inter-communication:* All directives share the same instance of the attributes
16455  *   object which allows the directives to use the attributes object as inter directive
16456  *   communication.
16457  *
16458  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
16459  *   allowing other directives to read the interpolated value.
16460  *
16461  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
16462  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
16463  *   the only way to easily get the actual value because during the linking phase the interpolation
16464  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
16465  *
16466  * ```js
16467  * function linkingFn(scope, elm, attrs, ctrl) {
16468  *   // get the attribute value
16469  *   console.log(attrs.ngModel);
16470  *
16471  *   // change the attribute
16472  *   attrs.$set('ngModel', 'new value');
16473  *
16474  *   // observe changes to interpolated attribute
16475  *   attrs.$observe('ngModel', function(value) {
16476  *     console.log('ngModel has changed value to ' + value);
16477  *   });
16478  * }
16479  * ```
16480  *
16481  * ## Example
16482  *
16483  * <div class="alert alert-warning">
16484  * **Note**: Typically directives are registered with `module.directive`. The example below is
16485  * to illustrate how `$compile` works.
16486  * </div>
16487  *
16488  <example module="compileExample">
16489    <file name="index.html">
16490     <script>
16491       angular.module('compileExample', [], function($compileProvider) {
16492         // configure new 'compile' directive by passing a directive
16493         // factory function. The factory function injects the '$compile'
16494         $compileProvider.directive('compile', function($compile) {
16495           // directive factory creates a link function
16496           return function(scope, element, attrs) {
16497             scope.$watch(
16498               function(scope) {
16499                  // watch the 'compile' expression for changes
16500                 return scope.$eval(attrs.compile);
16501               },
16502               function(value) {
16503                 // when the 'compile' expression changes
16504                 // assign it into the current DOM
16505                 element.html(value);
16506
16507                 // compile the new DOM and link it to the current
16508                 // scope.
16509                 // NOTE: we only compile .childNodes so that
16510                 // we don't get into infinite loop compiling ourselves
16511                 $compile(element.contents())(scope);
16512               }
16513             );
16514           };
16515         });
16516       })
16517       .controller('GreeterController', ['$scope', function($scope) {
16518         $scope.name = 'Angular';
16519         $scope.html = 'Hello {{name}}';
16520       }]);
16521     </script>
16522     <div ng-controller="GreeterController">
16523       <input ng-model="name"> <br/>
16524       <textarea ng-model="html"></textarea> <br/>
16525       <div compile="html"></div>
16526     </div>
16527    </file>
16528    <file name="protractor.js" type="protractor">
16529      it('should auto compile', function() {
16530        var textarea = $('textarea');
16531        var output = $('div[compile]');
16532        // The initial state reads 'Hello Angular'.
16533        expect(output.getText()).toBe('Hello Angular');
16534        textarea.clear();
16535        textarea.sendKeys('{{name}}!');
16536        expect(output.getText()).toBe('Angular!');
16537      });
16538    </file>
16539  </example>
16540
16541  *
16542  *
16543  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
16544  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
16545  *
16546  * <div class="alert alert-danger">
16547  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
16548  *   e.g. will not use the right outer scope. Please pass the transclude function as a
16549  *   `parentBoundTranscludeFn` to the link function instead.
16550  * </div>
16551  *
16552  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
16553  *                 root element(s), not their children)
16554  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
16555  * (a DOM element/tree) to a scope. Where:
16556  *
16557  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
16558  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
16559  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
16560  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
16561  *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
16562  *
16563  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
16564  *      * `scope` - is the current scope with which the linking function is working with.
16565  *
16566  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
16567  *  keys may be used to control linking behavior:
16568  *
16569  *      * `parentBoundTranscludeFn` - the transclude function made available to
16570  *        directives; if given, it will be passed through to the link functions of
16571  *        directives found in `element` during compilation.
16572  *      * `transcludeControllers` - an object hash with keys that map controller names
16573  *        to a hash with the key `instance`, which maps to the controller instance;
16574  *        if given, it will make the controllers available to directives on the compileNode:
16575  *        ```
16576  *        {
16577  *          parent: {
16578  *            instance: parentControllerInstance
16579  *          }
16580  *        }
16581  *        ```
16582  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
16583  *        the cloned elements; only needed for transcludes that are allowed to contain non html
16584  *        elements (e.g. SVG elements). See also the directive.controller property.
16585  *
16586  * Calling the linking function returns the element of the template. It is either the original
16587  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
16588  *
16589  * After linking the view is not updated until after a call to $digest which typically is done by
16590  * Angular automatically.
16591  *
16592  * If you need access to the bound view, there are two ways to do it:
16593  *
16594  * - If you are not asking the linking function to clone the template, create the DOM element(s)
16595  *   before you send them to the compiler and keep this reference around.
16596  *   ```js
16597  *     var element = $compile('<p>{{total}}</p>')(scope);
16598  *   ```
16599  *
16600  * - if on the other hand, you need the element to be cloned, the view reference from the original
16601  *   example would not point to the clone, but rather to the original template that was cloned. In
16602  *   this case, you can access the clone via the cloneAttachFn:
16603  *   ```js
16604  *     var templateElement = angular.element('<p>{{total}}</p>'),
16605  *         scope = ....;
16606  *
16607  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
16608  *       //attach the clone to DOM document at the right place
16609  *     });
16610  *
16611  *     //now we have reference to the cloned DOM via `clonedElement`
16612  *   ```
16613  *
16614  *
16615  * For information on how the compiler works, see the
16616  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
16617  */
16618
16619 var $compileMinErr = minErr('$compile');
16620
16621 function UNINITIALIZED_VALUE() {}
16622 var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
16623
16624 /**
16625  * @ngdoc provider
16626  * @name $compileProvider
16627  *
16628  * @description
16629  */
16630 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
16631 function $CompileProvider($provide, $$sanitizeUriProvider) {
16632   var hasDirectives = {},
16633       Suffix = 'Directive',
16634       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
16635       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
16636       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
16637       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
16638
16639   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
16640   // The assumption is that future DOM event attribute names will begin with
16641   // 'on' and be composed of only English letters.
16642   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
16643   var bindingCache = createMap();
16644
16645   function parseIsolateBindings(scope, directiveName, isController) {
16646     var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
16647
16648     var bindings = createMap();
16649
16650     forEach(scope, function(definition, scopeName) {
16651       if (definition in bindingCache) {
16652         bindings[scopeName] = bindingCache[definition];
16653         return;
16654       }
16655       var match = definition.match(LOCAL_REGEXP);
16656
16657       if (!match) {
16658         throw $compileMinErr('iscp',
16659             "Invalid {3} for directive '{0}'." +
16660             " Definition: {... {1}: '{2}' ...}",
16661             directiveName, scopeName, definition,
16662             (isController ? "controller bindings definition" :
16663             "isolate scope definition"));
16664       }
16665
16666       bindings[scopeName] = {
16667         mode: match[1][0],
16668         collection: match[2] === '*',
16669         optional: match[3] === '?',
16670         attrName: match[4] || scopeName
16671       };
16672       if (match[4]) {
16673         bindingCache[definition] = bindings[scopeName];
16674       }
16675     });
16676
16677     return bindings;
16678   }
16679
16680   function parseDirectiveBindings(directive, directiveName) {
16681     var bindings = {
16682       isolateScope: null,
16683       bindToController: null
16684     };
16685     if (isObject(directive.scope)) {
16686       if (directive.bindToController === true) {
16687         bindings.bindToController = parseIsolateBindings(directive.scope,
16688                                                          directiveName, true);
16689         bindings.isolateScope = {};
16690       } else {
16691         bindings.isolateScope = parseIsolateBindings(directive.scope,
16692                                                      directiveName, false);
16693       }
16694     }
16695     if (isObject(directive.bindToController)) {
16696       bindings.bindToController =
16697           parseIsolateBindings(directive.bindToController, directiveName, true);
16698     }
16699     if (isObject(bindings.bindToController)) {
16700       var controller = directive.controller;
16701       var controllerAs = directive.controllerAs;
16702       if (!controller) {
16703         // There is no controller, there may or may not be a controllerAs property
16704         throw $compileMinErr('noctrl',
16705               "Cannot bind to controller without directive '{0}'s controller.",
16706               directiveName);
16707       } else if (!identifierForController(controller, controllerAs)) {
16708         // There is a controller, but no identifier or controllerAs property
16709         throw $compileMinErr('noident',
16710               "Cannot bind to controller without identifier for directive '{0}'.",
16711               directiveName);
16712       }
16713     }
16714     return bindings;
16715   }
16716
16717   function assertValidDirectiveName(name) {
16718     var letter = name.charAt(0);
16719     if (!letter || letter !== lowercase(letter)) {
16720       throw $compileMinErr('baddir', "Directive/Component name '{0}' is invalid. The first character must be a lowercase letter", name);
16721     }
16722     if (name !== name.trim()) {
16723       throw $compileMinErr('baddir',
16724             "Directive/Component name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
16725             name);
16726     }
16727   }
16728
16729   /**
16730    * @ngdoc method
16731    * @name $compileProvider#directive
16732    * @kind function
16733    *
16734    * @description
16735    * Register a new directive with the compiler.
16736    *
16737    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
16738    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
16739    *    names and the values are the factories.
16740    * @param {Function|Array} directiveFactory An injectable directive factory function. See the
16741    *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
16742    * @returns {ng.$compileProvider} Self for chaining.
16743    */
16744   this.directive = function registerDirective(name, directiveFactory) {
16745     assertNotHasOwnProperty(name, 'directive');
16746     if (isString(name)) {
16747       assertValidDirectiveName(name);
16748       assertArg(directiveFactory, 'directiveFactory');
16749       if (!hasDirectives.hasOwnProperty(name)) {
16750         hasDirectives[name] = [];
16751         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
16752           function($injector, $exceptionHandler) {
16753             var directives = [];
16754             forEach(hasDirectives[name], function(directiveFactory, index) {
16755               try {
16756                 var directive = $injector.invoke(directiveFactory);
16757                 if (isFunction(directive)) {
16758                   directive = { compile: valueFn(directive) };
16759                 } else if (!directive.compile && directive.link) {
16760                   directive.compile = valueFn(directive.link);
16761                 }
16762                 directive.priority = directive.priority || 0;
16763                 directive.index = index;
16764                 directive.name = directive.name || name;
16765                 directive.require = directive.require || (directive.controller && directive.name);
16766                 directive.restrict = directive.restrict || 'EA';
16767                 directive.$$moduleName = directiveFactory.$$moduleName;
16768                 directives.push(directive);
16769               } catch (e) {
16770                 $exceptionHandler(e);
16771               }
16772             });
16773             return directives;
16774           }]);
16775       }
16776       hasDirectives[name].push(directiveFactory);
16777     } else {
16778       forEach(name, reverseParams(registerDirective));
16779     }
16780     return this;
16781   };
16782
16783   /**
16784    * @ngdoc method
16785    * @name $compileProvider#component
16786    * @module ng
16787    * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
16788    * @param {Object} options Component definition object (a simplified
16789    *    {@link ng.$compile#directive-definition-object directive definition object}),
16790    *    with the following properties (all optional):
16791    *
16792    *    - `controller` â€“ `{(string|function()=}` â€“ controller constructor function that should be
16793    *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
16794    *      registered controller} if passed as a string. An empty `noop` function by default.
16795    *    - `controllerAs` â€“ `{string=}` â€“ identifier name for to reference the controller in the component's scope.
16796    *      If present, the controller will be published to scope under the `controllerAs` name.
16797    *      If not present, this will default to be `$ctrl`.
16798    *    - `template` â€“ `{string=|function()=}` â€“ html template as a string or a function that
16799    *      returns an html template as a string which should be used as the contents of this component.
16800    *      Empty string by default.
16801    *
16802    *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
16803    *      the following locals:
16804    *
16805    *      - `$element` - Current element
16806    *      - `$attrs` - Current attributes object for the element
16807    *
16808    *    - `templateUrl` â€“ `{string=|function()=}` â€“ path or function that returns a path to an html
16809    *      template that should be used  as the contents of this component.
16810    *
16811    *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
16812    *      the following locals:
16813    *
16814    *      - `$element` - Current element
16815    *      - `$attrs` - Current attributes object for the element
16816    *
16817    *    - `bindings` â€“ `{object=}` â€“ defines bindings between DOM attributes and component properties.
16818    *      Component properties are always bound to the component controller and not to the scope.
16819    *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
16820    *    - `transclude` â€“ `{boolean=}` â€“ whether {@link $compile#transclusion content transclusion} is enabled.
16821    *      Disabled by default.
16822    *    - `require` - `{Object<string, string>=}` - requires the controllers of other directives and binds them to
16823    *      this component's controller. The object keys specify the property names under which the required
16824    *      controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
16825    *    - `$...` â€“ additional properties to attach to the directive factory function and the controller
16826    *      constructor function. (This is used by the component router to annotate)
16827    *
16828    * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
16829    * @description
16830    * Register a **component definition** with the compiler. This is a shorthand for registering a special
16831    * type of directive, which represents a self-contained UI component in your application. Such components
16832    * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
16833    *
16834    * Component definitions are very simple and do not require as much configuration as defining general
16835    * directives. Component definitions usually consist only of a template and a controller backing it.
16836    *
16837    * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
16838    * `bindToController`. They always have **isolate scope** and are restricted to elements.
16839    *
16840    * Here are a few examples of how you would usually define components:
16841    *
16842    * ```js
16843    *   var myMod = angular.module(...);
16844    *   myMod.component('myComp', {
16845    *     template: '<div>My name is {{$ctrl.name}}</div>',
16846    *     controller: function() {
16847    *       this.name = 'shahar';
16848    *     }
16849    *   });
16850    *
16851    *   myMod.component('myComp', {
16852    *     template: '<div>My name is {{$ctrl.name}}</div>',
16853    *     bindings: {name: '@'}
16854    *   });
16855    *
16856    *   myMod.component('myComp', {
16857    *     templateUrl: 'views/my-comp.html',
16858    *     controller: 'MyCtrl',
16859    *     controllerAs: 'ctrl',
16860    *     bindings: {name: '@'}
16861    *   });
16862    *
16863    * ```
16864    * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
16865    *
16866    * <br />
16867    * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
16868    */
16869   this.component = function registerComponent(name, options) {
16870     var controller = options.controller || function() {};
16871
16872     function factory($injector) {
16873       function makeInjectable(fn) {
16874         if (isFunction(fn) || isArray(fn)) {
16875           return function(tElement, tAttrs) {
16876             return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
16877           };
16878         } else {
16879           return fn;
16880         }
16881       }
16882
16883       var template = (!options.template && !options.templateUrl ? '' : options.template);
16884       var ddo = {
16885         controller: controller,
16886         controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
16887         template: makeInjectable(template),
16888         templateUrl: makeInjectable(options.templateUrl),
16889         transclude: options.transclude,
16890         scope: {},
16891         bindToController: options.bindings || {},
16892         restrict: 'E',
16893         require: options.require
16894       };
16895
16896       // Copy annotations (starting with $) over to the DDO
16897       forEach(options, function(val, key) {
16898         if (key.charAt(0) === '$') ddo[key] = val;
16899       });
16900
16901       return ddo;
16902     }
16903
16904     // TODO(pete) remove the following `forEach` before we release 1.6.0
16905     // The component-router@0.2.0 looks for the annotations on the controller constructor
16906     // Nothing in Angular looks for annotations on the factory function but we can't remove
16907     // it from 1.5.x yet.
16908
16909     // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
16910     // These could be used by libraries such as the new component router
16911     forEach(options, function(val, key) {
16912       if (key.charAt(0) === '$') {
16913         factory[key] = val;
16914         // Don't try to copy over annotations to named controller
16915         if (isFunction(controller)) controller[key] = val;
16916       }
16917     });
16918
16919     factory.$inject = ['$injector'];
16920
16921     return this.directive(name, factory);
16922   };
16923
16924
16925   /**
16926    * @ngdoc method
16927    * @name $compileProvider#aHrefSanitizationWhitelist
16928    * @kind function
16929    *
16930    * @description
16931    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16932    * urls during a[href] sanitization.
16933    *
16934    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
16935    *
16936    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16937    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16938    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16939    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16940    *
16941    * @param {RegExp=} regexp New regexp to whitelist urls with.
16942    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16943    *    chaining otherwise.
16944    */
16945   this.aHrefSanitizationWhitelist = function(regexp) {
16946     if (isDefined(regexp)) {
16947       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
16948       return this;
16949     } else {
16950       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
16951     }
16952   };
16953
16954
16955   /**
16956    * @ngdoc method
16957    * @name $compileProvider#imgSrcSanitizationWhitelist
16958    * @kind function
16959    *
16960    * @description
16961    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16962    * urls during img[src] sanitization.
16963    *
16964    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16965    *
16966    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16967    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16968    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16969    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16970    *
16971    * @param {RegExp=} regexp New regexp to whitelist urls with.
16972    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16973    *    chaining otherwise.
16974    */
16975   this.imgSrcSanitizationWhitelist = function(regexp) {
16976     if (isDefined(regexp)) {
16977       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
16978       return this;
16979     } else {
16980       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
16981     }
16982   };
16983
16984   /**
16985    * @ngdoc method
16986    * @name  $compileProvider#debugInfoEnabled
16987    *
16988    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
16989    * current debugInfoEnabled state
16990    * @returns {*} current value if used as getter or itself (chaining) if used as setter
16991    *
16992    * @kind function
16993    *
16994    * @description
16995    * Call this method to enable/disable various debug runtime information in the compiler such as adding
16996    * binding information and a reference to the current scope on to DOM elements.
16997    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
16998    * * `ng-binding` CSS class
16999    * * `$binding` data property containing an array of the binding expressions
17000    *
17001    * You may want to disable this in production for a significant performance boost. See
17002    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
17003    *
17004    * The default value is true.
17005    */
17006   var debugInfoEnabled = true;
17007   this.debugInfoEnabled = function(enabled) {
17008     if (isDefined(enabled)) {
17009       debugInfoEnabled = enabled;
17010       return this;
17011     }
17012     return debugInfoEnabled;
17013   };
17014
17015
17016   var TTL = 10;
17017   /**
17018    * @ngdoc method
17019    * @name $compileProvider#onChangesTtl
17020    * @description
17021    *
17022    * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and
17023    * assuming that the model is unstable.
17024    *
17025    * The current default is 10 iterations.
17026    *
17027    * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result
17028    * in several iterations of calls to these hooks. However if an application needs more than the default 10
17029    * iterations to stabilize then you should investigate what is causing the model to continuously change during
17030    * the `$onChanges` hook execution.
17031    *
17032    * Increasing the TTL could have performance implications, so you should not change it without proper justification.
17033    *
17034    * @param {number} limit The number of `$onChanges` hook iterations.
17035    * @returns {number|object} the current limit (or `this` if called as a setter for chaining)
17036    */
17037   this.onChangesTtl = function(value) {
17038     if (arguments.length) {
17039       TTL = value;
17040       return this;
17041     }
17042     return TTL;
17043   };
17044
17045   this.$get = [
17046             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
17047             '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
17048     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
17049              $controller,   $rootScope,   $sce,   $animate,   $$sanitizeUri) {
17050
17051     var SIMPLE_ATTR_NAME = /^\w/;
17052     var specialAttrHolder = window.document.createElement('div');
17053
17054
17055
17056     var onChangesTtl = TTL;
17057     // The onChanges hooks should all be run together in a single digest
17058     // When changes occur, the call to trigger their hooks will be added to this queue
17059     var onChangesQueue;
17060
17061     // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
17062     function flushOnChangesQueue() {
17063       try {
17064         if (!(--onChangesTtl)) {
17065           // We have hit the TTL limit so reset everything
17066           onChangesQueue = undefined;
17067           throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
17068         }
17069         // We must run this hook in an apply since the $$postDigest runs outside apply
17070         $rootScope.$apply(function() {
17071           for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
17072             onChangesQueue[i]();
17073           }
17074           // Reset the queue to trigger a new schedule next time there is a change
17075           onChangesQueue = undefined;
17076         });
17077       } finally {
17078         onChangesTtl++;
17079       }
17080     }
17081
17082
17083     function Attributes(element, attributesToCopy) {
17084       if (attributesToCopy) {
17085         var keys = Object.keys(attributesToCopy);
17086         var i, l, key;
17087
17088         for (i = 0, l = keys.length; i < l; i++) {
17089           key = keys[i];
17090           this[key] = attributesToCopy[key];
17091         }
17092       } else {
17093         this.$attr = {};
17094       }
17095
17096       this.$$element = element;
17097     }
17098
17099     Attributes.prototype = {
17100       /**
17101        * @ngdoc method
17102        * @name $compile.directive.Attributes#$normalize
17103        * @kind function
17104        *
17105        * @description
17106        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
17107        * `data-`) to its normalized, camelCase form.
17108        *
17109        * Also there is special case for Moz prefix starting with upper case letter.
17110        *
17111        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
17112        *
17113        * @param {string} name Name to normalize
17114        */
17115       $normalize: directiveNormalize,
17116
17117
17118       /**
17119        * @ngdoc method
17120        * @name $compile.directive.Attributes#$addClass
17121        * @kind function
17122        *
17123        * @description
17124        * Adds the CSS class value specified by the classVal parameter to the element. If animations
17125        * are enabled then an animation will be triggered for the class addition.
17126        *
17127        * @param {string} classVal The className value that will be added to the element
17128        */
17129       $addClass: function(classVal) {
17130         if (classVal && classVal.length > 0) {
17131           $animate.addClass(this.$$element, classVal);
17132         }
17133       },
17134
17135       /**
17136        * @ngdoc method
17137        * @name $compile.directive.Attributes#$removeClass
17138        * @kind function
17139        *
17140        * @description
17141        * Removes the CSS class value specified by the classVal parameter from the element. If
17142        * animations are enabled then an animation will be triggered for the class removal.
17143        *
17144        * @param {string} classVal The className value that will be removed from the element
17145        */
17146       $removeClass: function(classVal) {
17147         if (classVal && classVal.length > 0) {
17148           $animate.removeClass(this.$$element, classVal);
17149         }
17150       },
17151
17152       /**
17153        * @ngdoc method
17154        * @name $compile.directive.Attributes#$updateClass
17155        * @kind function
17156        *
17157        * @description
17158        * Adds and removes the appropriate CSS class values to the element based on the difference
17159        * between the new and old CSS class values (specified as newClasses and oldClasses).
17160        *
17161        * @param {string} newClasses The current CSS className value
17162        * @param {string} oldClasses The former CSS className value
17163        */
17164       $updateClass: function(newClasses, oldClasses) {
17165         var toAdd = tokenDifference(newClasses, oldClasses);
17166         if (toAdd && toAdd.length) {
17167           $animate.addClass(this.$$element, toAdd);
17168         }
17169
17170         var toRemove = tokenDifference(oldClasses, newClasses);
17171         if (toRemove && toRemove.length) {
17172           $animate.removeClass(this.$$element, toRemove);
17173         }
17174       },
17175
17176       /**
17177        * Set a normalized attribute on the element in a way such that all directives
17178        * can share the attribute. This function properly handles boolean attributes.
17179        * @param {string} key Normalized key. (ie ngAttribute)
17180        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
17181        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
17182        *     Defaults to true.
17183        * @param {string=} attrName Optional none normalized name. Defaults to key.
17184        */
17185       $set: function(key, value, writeAttr, attrName) {
17186         // TODO: decide whether or not to throw an error if "class"
17187         //is set through this function since it may cause $updateClass to
17188         //become unstable.
17189
17190         var node = this.$$element[0],
17191             booleanKey = getBooleanAttrName(node, key),
17192             aliasedKey = getAliasedAttrName(key),
17193             observer = key,
17194             nodeName;
17195
17196         if (booleanKey) {
17197           this.$$element.prop(key, value);
17198           attrName = booleanKey;
17199         } else if (aliasedKey) {
17200           this[aliasedKey] = value;
17201           observer = aliasedKey;
17202         }
17203
17204         this[key] = value;
17205
17206         // translate normalized key to actual key
17207         if (attrName) {
17208           this.$attr[key] = attrName;
17209         } else {
17210           attrName = this.$attr[key];
17211           if (!attrName) {
17212             this.$attr[key] = attrName = snake_case(key, '-');
17213           }
17214         }
17215
17216         nodeName = nodeName_(this.$$element);
17217
17218         if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
17219             (nodeName === 'img' && key === 'src')) {
17220           // sanitize a[href] and img[src] values
17221           this[key] = value = $$sanitizeUri(value, key === 'src');
17222         } else if (nodeName === 'img' && key === 'srcset') {
17223           // sanitize img[srcset] values
17224           var result = "";
17225
17226           // first check if there are spaces because it's not the same pattern
17227           var trimmedSrcset = trim(value);
17228           //                (   999x   ,|   999w   ,|   ,|,   )
17229           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
17230           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
17231
17232           // split srcset into tuple of uri and descriptor except for the last item
17233           var rawUris = trimmedSrcset.split(pattern);
17234
17235           // for each tuples
17236           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
17237           for (var i = 0; i < nbrUrisWith2parts; i++) {
17238             var innerIdx = i * 2;
17239             // sanitize the uri
17240             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
17241             // add the descriptor
17242             result += (" " + trim(rawUris[innerIdx + 1]));
17243           }
17244
17245           // split the last item into uri and descriptor
17246           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
17247
17248           // sanitize the last uri
17249           result += $$sanitizeUri(trim(lastTuple[0]), true);
17250
17251           // and add the last descriptor if any
17252           if (lastTuple.length === 2) {
17253             result += (" " + trim(lastTuple[1]));
17254           }
17255           this[key] = value = result;
17256         }
17257
17258         if (writeAttr !== false) {
17259           if (value === null || isUndefined(value)) {
17260             this.$$element.removeAttr(attrName);
17261           } else {
17262             if (SIMPLE_ATTR_NAME.test(attrName)) {
17263               this.$$element.attr(attrName, value);
17264             } else {
17265               setSpecialAttr(this.$$element[0], attrName, value);
17266             }
17267           }
17268         }
17269
17270         // fire observers
17271         var $$observers = this.$$observers;
17272         $$observers && forEach($$observers[observer], function(fn) {
17273           try {
17274             fn(value);
17275           } catch (e) {
17276             $exceptionHandler(e);
17277           }
17278         });
17279       },
17280
17281
17282       /**
17283        * @ngdoc method
17284        * @name $compile.directive.Attributes#$observe
17285        * @kind function
17286        *
17287        * @description
17288        * Observes an interpolated attribute.
17289        *
17290        * The observer function will be invoked once during the next `$digest` following
17291        * compilation. The observer is then invoked whenever the interpolated value
17292        * changes.
17293        *
17294        * @param {string} key Normalized key. (ie ngAttribute) .
17295        * @param {function(interpolatedValue)} fn Function that will be called whenever
17296                 the interpolated value of the attribute changes.
17297        *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
17298        *        guide} for more info.
17299        * @returns {function()} Returns a deregistration function for this observer.
17300        */
17301       $observe: function(key, fn) {
17302         var attrs = this,
17303             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
17304             listeners = ($$observers[key] || ($$observers[key] = []));
17305
17306         listeners.push(fn);
17307         $rootScope.$evalAsync(function() {
17308           if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
17309             // no one registered attribute interpolation function, so lets call it manually
17310             fn(attrs[key]);
17311           }
17312         });
17313
17314         return function() {
17315           arrayRemove(listeners, fn);
17316         };
17317       }
17318     };
17319
17320     function setSpecialAttr(element, attrName, value) {
17321       // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
17322       // so we have to jump through some hoops to get such an attribute
17323       // https://github.com/angular/angular.js/pull/13318
17324       specialAttrHolder.innerHTML = "<span " + attrName + ">";
17325       var attributes = specialAttrHolder.firstChild.attributes;
17326       var attribute = attributes[0];
17327       // We have to remove the attribute from its container element before we can add it to the destination element
17328       attributes.removeNamedItem(attribute.name);
17329       attribute.value = value;
17330       element.attributes.setNamedItem(attribute);
17331     }
17332
17333     function safeAddClass($element, className) {
17334       try {
17335         $element.addClass(className);
17336       } catch (e) {
17337         // ignore, since it means that we are trying to set class on
17338         // SVG element, where class name is read-only.
17339       }
17340     }
17341
17342
17343     var startSymbol = $interpolate.startSymbol(),
17344         endSymbol = $interpolate.endSymbol(),
17345         denormalizeTemplate = (startSymbol == '{{' && endSymbol  == '}}')
17346             ? identity
17347             : function denormalizeTemplate(template) {
17348               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
17349         },
17350         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
17351     var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
17352
17353     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
17354       var bindings = $element.data('$binding') || [];
17355
17356       if (isArray(binding)) {
17357         bindings = bindings.concat(binding);
17358       } else {
17359         bindings.push(binding);
17360       }
17361
17362       $element.data('$binding', bindings);
17363     } : noop;
17364
17365     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
17366       safeAddClass($element, 'ng-binding');
17367     } : noop;
17368
17369     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
17370       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
17371       $element.data(dataName, scope);
17372     } : noop;
17373
17374     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
17375       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
17376     } : noop;
17377
17378     compile.$$createComment = function(directiveName, comment) {
17379       var content = '';
17380       if (debugInfoEnabled) {
17381         content = ' ' + (directiveName || '') + ': ' + (comment || '') + ' ';
17382       }
17383       return window.document.createComment(content);
17384     };
17385
17386     return compile;
17387
17388     //================================
17389
17390     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
17391                         previousCompileContext) {
17392       if (!($compileNodes instanceof jqLite)) {
17393         // jquery always rewraps, whereas we need to preserve the original selector so that we can
17394         // modify it.
17395         $compileNodes = jqLite($compileNodes);
17396       }
17397
17398       var NOT_EMPTY = /\S+/;
17399
17400       // We can not compile top level text elements since text nodes can be merged and we will
17401       // not be able to attach scope data to them, so we will wrap them in <span>
17402       for (var i = 0, len = $compileNodes.length; i < len; i++) {
17403         var domNode = $compileNodes[i];
17404
17405         if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
17406           jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
17407         }
17408       }
17409
17410       var compositeLinkFn =
17411               compileNodes($compileNodes, transcludeFn, $compileNodes,
17412                            maxPriority, ignoreDirective, previousCompileContext);
17413       compile.$$addScopeClass($compileNodes);
17414       var namespace = null;
17415       return function publicLinkFn(scope, cloneConnectFn, options) {
17416         assertArg(scope, 'scope');
17417
17418         if (previousCompileContext && previousCompileContext.needsNewScope) {
17419           // A parent directive did a replace and a directive on this element asked
17420           // for transclusion, which caused us to lose a layer of element on which
17421           // we could hold the new transclusion scope, so we will create it manually
17422           // here.
17423           scope = scope.$parent.$new();
17424         }
17425
17426         options = options || {};
17427         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
17428           transcludeControllers = options.transcludeControllers,
17429           futureParentElement = options.futureParentElement;
17430
17431         // When `parentBoundTranscludeFn` is passed, it is a
17432         // `controllersBoundTransclude` function (it was previously passed
17433         // as `transclude` to directive.link) so we must unwrap it to get
17434         // its `boundTranscludeFn`
17435         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
17436           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
17437         }
17438
17439         if (!namespace) {
17440           namespace = detectNamespaceForChildElements(futureParentElement);
17441         }
17442         var $linkNode;
17443         if (namespace !== 'html') {
17444           // When using a directive with replace:true and templateUrl the $compileNodes
17445           // (or a child element inside of them)
17446           // might change, so we need to recreate the namespace adapted compileNodes
17447           // for call to the link function.
17448           // Note: This will already clone the nodes...
17449           $linkNode = jqLite(
17450             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
17451           );
17452         } else if (cloneConnectFn) {
17453           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
17454           // and sometimes changes the structure of the DOM.
17455           $linkNode = JQLitePrototype.clone.call($compileNodes);
17456         } else {
17457           $linkNode = $compileNodes;
17458         }
17459
17460         if (transcludeControllers) {
17461           for (var controllerName in transcludeControllers) {
17462             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
17463           }
17464         }
17465
17466         compile.$$addScopeInfo($linkNode, scope);
17467
17468         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
17469         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
17470         return $linkNode;
17471       };
17472     }
17473
17474     function detectNamespaceForChildElements(parentElement) {
17475       // TODO: Make this detect MathML as well...
17476       var node = parentElement && parentElement[0];
17477       if (!node) {
17478         return 'html';
17479       } else {
17480         return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
17481       }
17482     }
17483
17484     /**
17485      * Compile function matches each node in nodeList against the directives. Once all directives
17486      * for a particular node are collected their compile functions are executed. The compile
17487      * functions return values - the linking functions - are combined into a composite linking
17488      * function, which is the a linking function for the node.
17489      *
17490      * @param {NodeList} nodeList an array of nodes or NodeList to compile
17491      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
17492      *        scope argument is auto-generated to the new child of the transcluded parent scope.
17493      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
17494      *        the rootElement must be set the jqLite collection of the compile root. This is
17495      *        needed so that the jqLite collection items can be replaced with widgets.
17496      * @param {number=} maxPriority Max directive priority.
17497      * @returns {Function} A composite linking function of all of the matched directives or null.
17498      */
17499     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
17500                             previousCompileContext) {
17501       var linkFns = [],
17502           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
17503
17504       for (var i = 0; i < nodeList.length; i++) {
17505         attrs = new Attributes();
17506
17507         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
17508         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
17509                                         ignoreDirective);
17510
17511         nodeLinkFn = (directives.length)
17512             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
17513                                       null, [], [], previousCompileContext)
17514             : null;
17515
17516         if (nodeLinkFn && nodeLinkFn.scope) {
17517           compile.$$addScopeClass(attrs.$$element);
17518         }
17519
17520         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
17521                       !(childNodes = nodeList[i].childNodes) ||
17522                       !childNodes.length)
17523             ? null
17524             : compileNodes(childNodes,
17525                  nodeLinkFn ? (
17526                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
17527                      && nodeLinkFn.transclude) : transcludeFn);
17528
17529         if (nodeLinkFn || childLinkFn) {
17530           linkFns.push(i, nodeLinkFn, childLinkFn);
17531           linkFnFound = true;
17532           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
17533         }
17534
17535         //use the previous context only for the first element in the virtual group
17536         previousCompileContext = null;
17537       }
17538
17539       // return a linking function if we have found anything, null otherwise
17540       return linkFnFound ? compositeLinkFn : null;
17541
17542       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
17543         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
17544         var stableNodeList;
17545
17546
17547         if (nodeLinkFnFound) {
17548           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
17549           // offsets don't get screwed up
17550           var nodeListLength = nodeList.length;
17551           stableNodeList = new Array(nodeListLength);
17552
17553           // create a sparse array by only copying the elements which have a linkFn
17554           for (i = 0; i < linkFns.length; i+=3) {
17555             idx = linkFns[i];
17556             stableNodeList[idx] = nodeList[idx];
17557           }
17558         } else {
17559           stableNodeList = nodeList;
17560         }
17561
17562         for (i = 0, ii = linkFns.length; i < ii;) {
17563           node = stableNodeList[linkFns[i++]];
17564           nodeLinkFn = linkFns[i++];
17565           childLinkFn = linkFns[i++];
17566
17567           if (nodeLinkFn) {
17568             if (nodeLinkFn.scope) {
17569               childScope = scope.$new();
17570               compile.$$addScopeInfo(jqLite(node), childScope);
17571             } else {
17572               childScope = scope;
17573             }
17574
17575             if (nodeLinkFn.transcludeOnThisElement) {
17576               childBoundTranscludeFn = createBoundTranscludeFn(
17577                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
17578
17579             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
17580               childBoundTranscludeFn = parentBoundTranscludeFn;
17581
17582             } else if (!parentBoundTranscludeFn && transcludeFn) {
17583               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
17584
17585             } else {
17586               childBoundTranscludeFn = null;
17587             }
17588
17589             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
17590
17591           } else if (childLinkFn) {
17592             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
17593           }
17594         }
17595       }
17596     }
17597
17598     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
17599       function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
17600
17601         if (!transcludedScope) {
17602           transcludedScope = scope.$new(false, containingScope);
17603           transcludedScope.$$transcluded = true;
17604         }
17605
17606         return transcludeFn(transcludedScope, cloneFn, {
17607           parentBoundTranscludeFn: previousBoundTranscludeFn,
17608           transcludeControllers: controllers,
17609           futureParentElement: futureParentElement
17610         });
17611       }
17612
17613       // We need  to attach the transclusion slots onto the `boundTranscludeFn`
17614       // so that they are available inside the `controllersBoundTransclude` function
17615       var boundSlots = boundTranscludeFn.$$slots = createMap();
17616       for (var slotName in transcludeFn.$$slots) {
17617         if (transcludeFn.$$slots[slotName]) {
17618           boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
17619         } else {
17620           boundSlots[slotName] = null;
17621         }
17622       }
17623
17624       return boundTranscludeFn;
17625     }
17626
17627     /**
17628      * Looks for directives on the given node and adds them to the directive collection which is
17629      * sorted.
17630      *
17631      * @param node Node to search.
17632      * @param directives An array to which the directives are added to. This array is sorted before
17633      *        the function returns.
17634      * @param attrs The shared attrs object which is used to populate the normalized attributes.
17635      * @param {number=} maxPriority Max directive priority.
17636      */
17637     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
17638       var nodeType = node.nodeType,
17639           attrsMap = attrs.$attr,
17640           match,
17641           className;
17642
17643       switch (nodeType) {
17644         case NODE_TYPE_ELEMENT: /* Element */
17645           // use the node name: <directive>
17646           addDirective(directives,
17647               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
17648
17649           // iterate over the attributes
17650           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
17651                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
17652             var attrStartName = false;
17653             var attrEndName = false;
17654
17655             attr = nAttrs[j];
17656             name = attr.name;
17657             value = trim(attr.value);
17658
17659             // support ngAttr attribute binding
17660             ngAttrName = directiveNormalize(name);
17661             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
17662               name = name.replace(PREFIX_REGEXP, '')
17663                 .substr(8).replace(/_(.)/g, function(match, letter) {
17664                   return letter.toUpperCase();
17665                 });
17666             }
17667
17668             var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
17669             if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
17670               attrStartName = name;
17671               attrEndName = name.substr(0, name.length - 5) + 'end';
17672               name = name.substr(0, name.length - 6);
17673             }
17674
17675             nName = directiveNormalize(name.toLowerCase());
17676             attrsMap[nName] = name;
17677             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
17678                 attrs[nName] = value;
17679                 if (getBooleanAttrName(node, nName)) {
17680                   attrs[nName] = true; // presence means true
17681                 }
17682             }
17683             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
17684             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
17685                           attrEndName);
17686           }
17687
17688           // use class as directive
17689           className = node.className;
17690           if (isObject(className)) {
17691               // Maybe SVGAnimatedString
17692               className = className.animVal;
17693           }
17694           if (isString(className) && className !== '') {
17695             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
17696               nName = directiveNormalize(match[2]);
17697               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
17698                 attrs[nName] = trim(match[3]);
17699               }
17700               className = className.substr(match.index + match[0].length);
17701             }
17702           }
17703           break;
17704         case NODE_TYPE_TEXT: /* Text Node */
17705           if (msie === 11) {
17706             // Workaround for #11781
17707             while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
17708               node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
17709               node.parentNode.removeChild(node.nextSibling);
17710             }
17711           }
17712           addTextInterpolateDirective(directives, node.nodeValue);
17713           break;
17714         case NODE_TYPE_COMMENT: /* Comment */
17715           try {
17716             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
17717             if (match) {
17718               nName = directiveNormalize(match[1]);
17719               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
17720                 attrs[nName] = trim(match[2]);
17721               }
17722             }
17723           } catch (e) {
17724             // turns out that under some circumstances IE9 throws errors when one attempts to read
17725             // comment's node value.
17726             // Just ignore it and continue. (Can't seem to reproduce in test case.)
17727           }
17728           break;
17729       }
17730
17731       directives.sort(byPriority);
17732       return directives;
17733     }
17734
17735     /**
17736      * Given a node with an directive-start it collects all of the siblings until it finds
17737      * directive-end.
17738      * @param node
17739      * @param attrStart
17740      * @param attrEnd
17741      * @returns {*}
17742      */
17743     function groupScan(node, attrStart, attrEnd) {
17744       var nodes = [];
17745       var depth = 0;
17746       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
17747         do {
17748           if (!node) {
17749             throw $compileMinErr('uterdir',
17750                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
17751                       attrStart, attrEnd);
17752           }
17753           if (node.nodeType == NODE_TYPE_ELEMENT) {
17754             if (node.hasAttribute(attrStart)) depth++;
17755             if (node.hasAttribute(attrEnd)) depth--;
17756           }
17757           nodes.push(node);
17758           node = node.nextSibling;
17759         } while (depth > 0);
17760       } else {
17761         nodes.push(node);
17762       }
17763
17764       return jqLite(nodes);
17765     }
17766
17767     /**
17768      * Wrapper for linking function which converts normal linking function into a grouped
17769      * linking function.
17770      * @param linkFn
17771      * @param attrStart
17772      * @param attrEnd
17773      * @returns {Function}
17774      */
17775     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
17776       return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
17777         element = groupScan(element[0], attrStart, attrEnd);
17778         return linkFn(scope, element, attrs, controllers, transcludeFn);
17779       };
17780     }
17781
17782     /**
17783      * A function generator that is used to support both eager and lazy compilation
17784      * linking function.
17785      * @param eager
17786      * @param $compileNodes
17787      * @param transcludeFn
17788      * @param maxPriority
17789      * @param ignoreDirective
17790      * @param previousCompileContext
17791      * @returns {Function}
17792      */
17793     function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
17794       var compiled;
17795
17796       if (eager) {
17797         return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17798       }
17799       return function lazyCompilation() {
17800         if (!compiled) {
17801           compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17802
17803           // Null out all of these references in order to make them eligible for garbage collection
17804           // since this is a potentially long lived closure
17805           $compileNodes = transcludeFn = previousCompileContext = null;
17806         }
17807         return compiled.apply(this, arguments);
17808       };
17809     }
17810
17811     /**
17812      * Once the directives have been collected, their compile functions are executed. This method
17813      * is responsible for inlining directive templates as well as terminating the application
17814      * of the directives if the terminal directive has been reached.
17815      *
17816      * @param {Array} directives Array of collected directives to execute their compile function.
17817      *        this needs to be pre-sorted by priority order.
17818      * @param {Node} compileNode The raw DOM node to apply the compile functions to
17819      * @param {Object} templateAttrs The shared attribute function
17820      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
17821      *                                                  scope argument is auto-generated to the new
17822      *                                                  child of the transcluded parent scope.
17823      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
17824      *                              argument has the root jqLite array so that we can replace nodes
17825      *                              on it.
17826      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
17827      *                                           compiling the transclusion.
17828      * @param {Array.<Function>} preLinkFns
17829      * @param {Array.<Function>} postLinkFns
17830      * @param {Object} previousCompileContext Context used for previous compilation of the current
17831      *                                        node
17832      * @returns {Function} linkFn
17833      */
17834     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
17835                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
17836                                    previousCompileContext) {
17837       previousCompileContext = previousCompileContext || {};
17838
17839       var terminalPriority = -Number.MAX_VALUE,
17840           newScopeDirective = previousCompileContext.newScopeDirective,
17841           controllerDirectives = previousCompileContext.controllerDirectives,
17842           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
17843           templateDirective = previousCompileContext.templateDirective,
17844           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
17845           hasTranscludeDirective = false,
17846           hasTemplate = false,
17847           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
17848           $compileNode = templateAttrs.$$element = jqLite(compileNode),
17849           directive,
17850           directiveName,
17851           $template,
17852           replaceDirective = originalReplaceDirective,
17853           childTranscludeFn = transcludeFn,
17854           linkFn,
17855           didScanForMultipleTransclusion = false,
17856           mightHaveMultipleTransclusionError = false,
17857           directiveValue;
17858
17859       // executes all directives on the current element
17860       for (var i = 0, ii = directives.length; i < ii; i++) {
17861         directive = directives[i];
17862         var attrStart = directive.$$start;
17863         var attrEnd = directive.$$end;
17864
17865         // collect multiblock sections
17866         if (attrStart) {
17867           $compileNode = groupScan(compileNode, attrStart, attrEnd);
17868         }
17869         $template = undefined;
17870
17871         if (terminalPriority > directive.priority) {
17872           break; // prevent further processing of directives
17873         }
17874
17875         if (directiveValue = directive.scope) {
17876
17877           // skip the check for directives with async templates, we'll check the derived sync
17878           // directive when the template arrives
17879           if (!directive.templateUrl) {
17880             if (isObject(directiveValue)) {
17881               // This directive is trying to add an isolated scope.
17882               // Check that there is no scope of any kind already
17883               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
17884                                 directive, $compileNode);
17885               newIsolateScopeDirective = directive;
17886             } else {
17887               // This directive is trying to add a child scope.
17888               // Check that there is no isolated scope already
17889               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
17890                                 $compileNode);
17891             }
17892           }
17893
17894           newScopeDirective = newScopeDirective || directive;
17895         }
17896
17897         directiveName = directive.name;
17898
17899         // If we encounter a condition that can result in transclusion on the directive,
17900         // then scan ahead in the remaining directives for others that may cause a multiple
17901         // transclusion error to be thrown during the compilation process.  If a matching directive
17902         // is found, then we know that when we encounter a transcluded directive, we need to eagerly
17903         // compile the `transclude` function rather than doing it lazily in order to throw
17904         // exceptions at the correct time
17905         if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
17906             || (directive.transclude && !directive.$$tlb))) {
17907                 var candidateDirective;
17908
17909                 for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
17910                     if ((candidateDirective.transclude && !candidateDirective.$$tlb)
17911                         || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
17912                         mightHaveMultipleTransclusionError = true;
17913                         break;
17914                     }
17915                 }
17916
17917                 didScanForMultipleTransclusion = true;
17918         }
17919
17920         if (!directive.templateUrl && directive.controller) {
17921           directiveValue = directive.controller;
17922           controllerDirectives = controllerDirectives || createMap();
17923           assertNoDuplicate("'" + directiveName + "' controller",
17924               controllerDirectives[directiveName], directive, $compileNode);
17925           controllerDirectives[directiveName] = directive;
17926         }
17927
17928         if (directiveValue = directive.transclude) {
17929           hasTranscludeDirective = true;
17930
17931           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
17932           // This option should only be used by directives that know how to safely handle element transclusion,
17933           // where the transcluded nodes are added or replaced after linking.
17934           if (!directive.$$tlb) {
17935             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
17936             nonTlbTranscludeDirective = directive;
17937           }
17938
17939           if (directiveValue == 'element') {
17940             hasElementTranscludeDirective = true;
17941             terminalPriority = directive.priority;
17942             $template = $compileNode;
17943             $compileNode = templateAttrs.$$element =
17944                 jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
17945             compileNode = $compileNode[0];
17946             replaceWith(jqCollection, sliceArgs($template), compileNode);
17947
17948             // Support: Chrome < 50
17949             // https://github.com/angular/angular.js/issues/14041
17950
17951             // In the versions of V8 prior to Chrome 50, the document fragment that is created
17952             // in the `replaceWith` function is improperly garbage collected despite still
17953             // being referenced by the `parentNode` property of all of the child nodes.  By adding
17954             // a reference to the fragment via a different property, we can avoid that incorrect
17955             // behavior.
17956             // TODO: remove this line after Chrome 50 has been released
17957             $template[0].$$parentNode = $template[0].parentNode;
17958
17959             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
17960                                         replaceDirective && replaceDirective.name, {
17961                                           // Don't pass in:
17962                                           // - controllerDirectives - otherwise we'll create duplicates controllers
17963                                           // - newIsolateScopeDirective or templateDirective - combining templates with
17964                                           //   element transclusion doesn't make sense.
17965                                           //
17966                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
17967                                           // on the same element more than once.
17968                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
17969                                         });
17970           } else {
17971
17972             var slots = createMap();
17973
17974             $template = jqLite(jqLiteClone(compileNode)).contents();
17975
17976             if (isObject(directiveValue)) {
17977
17978               // We have transclusion slots,
17979               // collect them up, compile them and store their transclusion functions
17980               $template = [];
17981
17982               var slotMap = createMap();
17983               var filledSlots = createMap();
17984
17985               // Parse the element selectors
17986               forEach(directiveValue, function(elementSelector, slotName) {
17987                 // If an element selector starts with a ? then it is optional
17988                 var optional = (elementSelector.charAt(0) === '?');
17989                 elementSelector = optional ? elementSelector.substring(1) : elementSelector;
17990
17991                 slotMap[elementSelector] = slotName;
17992
17993                 // We explicitly assign `null` since this implies that a slot was defined but not filled.
17994                 // Later when calling boundTransclusion functions with a slot name we only error if the
17995                 // slot is `undefined`
17996                 slots[slotName] = null;
17997
17998                 // filledSlots contains `true` for all slots that are either optional or have been
17999                 // filled. This is used to check that we have not missed any required slots
18000                 filledSlots[slotName] = optional;
18001               });
18002
18003               // Add the matching elements into their slot
18004               forEach($compileNode.contents(), function(node) {
18005                 var slotName = slotMap[directiveNormalize(nodeName_(node))];
18006                 if (slotName) {
18007                   filledSlots[slotName] = true;
18008                   slots[slotName] = slots[slotName] || [];
18009                   slots[slotName].push(node);
18010                 } else {
18011                   $template.push(node);
18012                 }
18013               });
18014
18015               // Check for required slots that were not filled
18016               forEach(filledSlots, function(filled, slotName) {
18017                 if (!filled) {
18018                   throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
18019                 }
18020               });
18021
18022               for (var slotName in slots) {
18023                 if (slots[slotName]) {
18024                   // Only define a transclusion function if the slot was filled
18025                   slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
18026                 }
18027               }
18028             }
18029
18030             $compileNode.empty(); // clear contents
18031             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
18032                 undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
18033             childTranscludeFn.$$slots = slots;
18034           }
18035         }
18036
18037         if (directive.template) {
18038           hasTemplate = true;
18039           assertNoDuplicate('template', templateDirective, directive, $compileNode);
18040           templateDirective = directive;
18041
18042           directiveValue = (isFunction(directive.template))
18043               ? directive.template($compileNode, templateAttrs)
18044               : directive.template;
18045
18046           directiveValue = denormalizeTemplate(directiveValue);
18047
18048           if (directive.replace) {
18049             replaceDirective = directive;
18050             if (jqLiteIsTextNode(directiveValue)) {
18051               $template = [];
18052             } else {
18053               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
18054             }
18055             compileNode = $template[0];
18056
18057             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
18058               throw $compileMinErr('tplrt',
18059                   "Template for directive '{0}' must have exactly one root element. {1}",
18060                   directiveName, '');
18061             }
18062
18063             replaceWith(jqCollection, $compileNode, compileNode);
18064
18065             var newTemplateAttrs = {$attr: {}};
18066
18067             // combine directives from the original node and from the template:
18068             // - take the array of directives for this element
18069             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
18070             // - collect directives from the template and sort them by priority
18071             // - combine directives as: processed + template + unprocessed
18072             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
18073             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
18074
18075             if (newIsolateScopeDirective || newScopeDirective) {
18076               // The original directive caused the current element to be replaced but this element
18077               // also needs to have a new scope, so we need to tell the template directives
18078               // that they would need to get their scope from further up, if they require transclusion
18079               markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
18080             }
18081             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
18082             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
18083
18084             ii = directives.length;
18085           } else {
18086             $compileNode.html(directiveValue);
18087           }
18088         }
18089
18090         if (directive.templateUrl) {
18091           hasTemplate = true;
18092           assertNoDuplicate('template', templateDirective, directive, $compileNode);
18093           templateDirective = directive;
18094
18095           if (directive.replace) {
18096             replaceDirective = directive;
18097           }
18098
18099           /* jshint -W021 */
18100           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
18101           /* jshint +W021 */
18102               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
18103                 controllerDirectives: controllerDirectives,
18104                 newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
18105                 newIsolateScopeDirective: newIsolateScopeDirective,
18106                 templateDirective: templateDirective,
18107                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
18108               });
18109           ii = directives.length;
18110         } else if (directive.compile) {
18111           try {
18112             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
18113             if (isFunction(linkFn)) {
18114               addLinkFns(null, linkFn, attrStart, attrEnd);
18115             } else if (linkFn) {
18116               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
18117             }
18118           } catch (e) {
18119             $exceptionHandler(e, startingTag($compileNode));
18120           }
18121         }
18122
18123         if (directive.terminal) {
18124           nodeLinkFn.terminal = true;
18125           terminalPriority = Math.max(terminalPriority, directive.priority);
18126         }
18127
18128       }
18129
18130       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
18131       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
18132       nodeLinkFn.templateOnThisElement = hasTemplate;
18133       nodeLinkFn.transclude = childTranscludeFn;
18134
18135       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
18136
18137       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
18138       return nodeLinkFn;
18139
18140       ////////////////////
18141
18142       function addLinkFns(pre, post, attrStart, attrEnd) {
18143         if (pre) {
18144           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
18145           pre.require = directive.require;
18146           pre.directiveName = directiveName;
18147           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
18148             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
18149           }
18150           preLinkFns.push(pre);
18151         }
18152         if (post) {
18153           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
18154           post.require = directive.require;
18155           post.directiveName = directiveName;
18156           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
18157             post = cloneAndAnnotateFn(post, {isolateScope: true});
18158           }
18159           postLinkFns.push(post);
18160         }
18161       }
18162
18163       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
18164         var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
18165             attrs, scopeBindingInfo;
18166
18167         if (compileNode === linkNode) {
18168           attrs = templateAttrs;
18169           $element = templateAttrs.$$element;
18170         } else {
18171           $element = jqLite(linkNode);
18172           attrs = new Attributes($element, templateAttrs);
18173         }
18174
18175         controllerScope = scope;
18176         if (newIsolateScopeDirective) {
18177           isolateScope = scope.$new(true);
18178         } else if (newScopeDirective) {
18179           controllerScope = scope.$parent;
18180         }
18181
18182         if (boundTranscludeFn) {
18183           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
18184           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
18185           transcludeFn = controllersBoundTransclude;
18186           transcludeFn.$$boundTransclude = boundTranscludeFn;
18187           // expose the slots on the `$transclude` function
18188           transcludeFn.isSlotFilled = function(slotName) {
18189             return !!boundTranscludeFn.$$slots[slotName];
18190           };
18191         }
18192
18193         if (controllerDirectives) {
18194           elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
18195         }
18196
18197         if (newIsolateScopeDirective) {
18198           // Initialize isolate scope bindings for new isolate scope directive.
18199           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
18200               templateDirective === newIsolateScopeDirective.$$originalDirective)));
18201           compile.$$addScopeClass($element, true);
18202           isolateScope.$$isolateBindings =
18203               newIsolateScopeDirective.$$isolateBindings;
18204           scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
18205                                         isolateScope.$$isolateBindings,
18206                                         newIsolateScopeDirective);
18207           if (scopeBindingInfo.removeWatches) {
18208             isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
18209           }
18210         }
18211
18212         // Initialize bindToController bindings
18213         for (var name in elementControllers) {
18214           var controllerDirective = controllerDirectives[name];
18215           var controller = elementControllers[name];
18216           var bindings = controllerDirective.$$bindings.bindToController;
18217
18218           if (controller.identifier && bindings) {
18219             controller.bindingInfo =
18220               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
18221           } else {
18222             controller.bindingInfo = {};
18223           }
18224
18225           var controllerResult = controller();
18226           if (controllerResult !== controller.instance) {
18227             // If the controller constructor has a return value, overwrite the instance
18228             // from setupControllers
18229             controller.instance = controllerResult;
18230             $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
18231             controller.bindingInfo.removeWatches && controller.bindingInfo.removeWatches();
18232             controller.bindingInfo =
18233               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
18234           }
18235         }
18236
18237         // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
18238         forEach(controllerDirectives, function(controllerDirective, name) {
18239           var require = controllerDirective.require;
18240           if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
18241             extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
18242           }
18243         });
18244
18245         // Handle the init and destroy lifecycle hooks on all controllers that have them
18246         forEach(elementControllers, function(controller) {
18247           var controllerInstance = controller.instance;
18248           if (isFunction(controllerInstance.$onChanges)) {
18249             controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
18250           }
18251           if (isFunction(controllerInstance.$onInit)) {
18252             controllerInstance.$onInit();
18253           }
18254           if (isFunction(controllerInstance.$onDestroy)) {
18255             controllerScope.$on('$destroy', function callOnDestroyHook() {
18256               controllerInstance.$onDestroy();
18257             });
18258           }
18259         });
18260
18261         // PRELINKING
18262         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
18263           linkFn = preLinkFns[i];
18264           invokeLinkFn(linkFn,
18265               linkFn.isolateScope ? isolateScope : scope,
18266               $element,
18267               attrs,
18268               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
18269               transcludeFn
18270           );
18271         }
18272
18273         // RECURSION
18274         // We only pass the isolate scope, if the isolate directive has a template,
18275         // otherwise the child elements do not belong to the isolate directive.
18276         var scopeToChild = scope;
18277         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
18278           scopeToChild = isolateScope;
18279         }
18280         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
18281
18282         // POSTLINKING
18283         for (i = postLinkFns.length - 1; i >= 0; i--) {
18284           linkFn = postLinkFns[i];
18285           invokeLinkFn(linkFn,
18286               linkFn.isolateScope ? isolateScope : scope,
18287               $element,
18288               attrs,
18289               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
18290               transcludeFn
18291           );
18292         }
18293
18294         // Trigger $postLink lifecycle hooks
18295         forEach(elementControllers, function(controller) {
18296           var controllerInstance = controller.instance;
18297           if (isFunction(controllerInstance.$postLink)) {
18298             controllerInstance.$postLink();
18299           }
18300         });
18301
18302         // This is the function that is injected as `$transclude`.
18303         // Note: all arguments are optional!
18304         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
18305           var transcludeControllers;
18306           // No scope passed in:
18307           if (!isScope(scope)) {
18308             slotName = futureParentElement;
18309             futureParentElement = cloneAttachFn;
18310             cloneAttachFn = scope;
18311             scope = undefined;
18312           }
18313
18314           if (hasElementTranscludeDirective) {
18315             transcludeControllers = elementControllers;
18316           }
18317           if (!futureParentElement) {
18318             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
18319           }
18320           if (slotName) {
18321             // slotTranscludeFn can be one of three things:
18322             //  * a transclude function - a filled slot
18323             //  * `null` - an optional slot that was not filled
18324             //  * `undefined` - a slot that was not declared (i.e. invalid)
18325             var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
18326             if (slotTranscludeFn) {
18327               return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18328             } else if (isUndefined(slotTranscludeFn)) {
18329               throw $compileMinErr('noslot',
18330                'No parent directive that requires a transclusion with slot name "{0}". ' +
18331                'Element: {1}',
18332                slotName, startingTag($element));
18333             }
18334           } else {
18335             return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18336           }
18337         }
18338       }
18339     }
18340
18341     function getControllers(directiveName, require, $element, elementControllers) {
18342       var value;
18343
18344       if (isString(require)) {
18345         var match = require.match(REQUIRE_PREFIX_REGEXP);
18346         var name = require.substring(match[0].length);
18347         var inheritType = match[1] || match[3];
18348         var optional = match[2] === '?';
18349
18350         //If only parents then start at the parent element
18351         if (inheritType === '^^') {
18352           $element = $element.parent();
18353         //Otherwise attempt getting the controller from elementControllers in case
18354         //the element is transcluded (and has no data) and to avoid .data if possible
18355         } else {
18356           value = elementControllers && elementControllers[name];
18357           value = value && value.instance;
18358         }
18359
18360         if (!value) {
18361           var dataName = '$' + name + 'Controller';
18362           value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
18363         }
18364
18365         if (!value && !optional) {
18366           throw $compileMinErr('ctreq',
18367               "Controller '{0}', required by directive '{1}', can't be found!",
18368               name, directiveName);
18369         }
18370       } else if (isArray(require)) {
18371         value = [];
18372         for (var i = 0, ii = require.length; i < ii; i++) {
18373           value[i] = getControllers(directiveName, require[i], $element, elementControllers);
18374         }
18375       } else if (isObject(require)) {
18376         value = {};
18377         forEach(require, function(controller, property) {
18378           value[property] = getControllers(directiveName, controller, $element, elementControllers);
18379         });
18380       }
18381
18382       return value || null;
18383     }
18384
18385     function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
18386       var elementControllers = createMap();
18387       for (var controllerKey in controllerDirectives) {
18388         var directive = controllerDirectives[controllerKey];
18389         var locals = {
18390           $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
18391           $element: $element,
18392           $attrs: attrs,
18393           $transclude: transcludeFn
18394         };
18395
18396         var controller = directive.controller;
18397         if (controller == '@') {
18398           controller = attrs[directive.name];
18399         }
18400
18401         var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
18402
18403         // For directives with element transclusion the element is a comment.
18404         // In this case .data will not attach any data.
18405         // Instead, we save the controllers for the element in a local hash and attach to .data
18406         // later, once we have the actual element.
18407         elementControllers[directive.name] = controllerInstance;
18408         $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
18409       }
18410       return elementControllers;
18411     }
18412
18413     // Depending upon the context in which a directive finds itself it might need to have a new isolated
18414     // or child scope created. For instance:
18415     // * if the directive has been pulled into a template because another directive with a higher priority
18416     // asked for element transclusion
18417     // * if the directive itself asks for transclusion but it is at the root of a template and the original
18418     // element was replaced. See https://github.com/angular/angular.js/issues/12936
18419     function markDirectiveScope(directives, isolateScope, newScope) {
18420       for (var j = 0, jj = directives.length; j < jj; j++) {
18421         directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
18422       }
18423     }
18424
18425     /**
18426      * looks up the directive and decorates it with exception handling and proper parameters. We
18427      * call this the boundDirective.
18428      *
18429      * @param {string} name name of the directive to look up.
18430      * @param {string} location The directive must be found in specific format.
18431      *   String containing any of theses characters:
18432      *
18433      *   * `E`: element name
18434      *   * `A': attribute
18435      *   * `C`: class
18436      *   * `M`: comment
18437      * @returns {boolean} true if directive was added.
18438      */
18439     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
18440                           endAttrName) {
18441       if (name === ignoreDirective) return null;
18442       var match = null;
18443       if (hasDirectives.hasOwnProperty(name)) {
18444         for (var directive, directives = $injector.get(name + Suffix),
18445             i = 0, ii = directives.length; i < ii; i++) {
18446           try {
18447             directive = directives[i];
18448             if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
18449                  directive.restrict.indexOf(location) != -1) {
18450               if (startAttrName) {
18451                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
18452               }
18453               if (!directive.$$bindings) {
18454                 var bindings = directive.$$bindings =
18455                     parseDirectiveBindings(directive, directive.name);
18456                 if (isObject(bindings.isolateScope)) {
18457                   directive.$$isolateBindings = bindings.isolateScope;
18458                 }
18459               }
18460               tDirectives.push(directive);
18461               match = directive;
18462             }
18463           } catch (e) { $exceptionHandler(e); }
18464         }
18465       }
18466       return match;
18467     }
18468
18469
18470     /**
18471      * looks up the directive and returns true if it is a multi-element directive,
18472      * and therefore requires DOM nodes between -start and -end markers to be grouped
18473      * together.
18474      *
18475      * @param {string} name name of the directive to look up.
18476      * @returns true if directive was registered as multi-element.
18477      */
18478     function directiveIsMultiElement(name) {
18479       if (hasDirectives.hasOwnProperty(name)) {
18480         for (var directive, directives = $injector.get(name + Suffix),
18481             i = 0, ii = directives.length; i < ii; i++) {
18482           directive = directives[i];
18483           if (directive.multiElement) {
18484             return true;
18485           }
18486         }
18487       }
18488       return false;
18489     }
18490
18491     /**
18492      * When the element is replaced with HTML template then the new attributes
18493      * on the template need to be merged with the existing attributes in the DOM.
18494      * The desired effect is to have both of the attributes present.
18495      *
18496      * @param {object} dst destination attributes (original DOM)
18497      * @param {object} src source attributes (from the directive template)
18498      */
18499     function mergeTemplateAttributes(dst, src) {
18500       var srcAttr = src.$attr,
18501           dstAttr = dst.$attr,
18502           $element = dst.$$element;
18503
18504       // reapply the old attributes to the new element
18505       forEach(dst, function(value, key) {
18506         if (key.charAt(0) != '$') {
18507           if (src[key] && src[key] !== value) {
18508             value += (key === 'style' ? ';' : ' ') + src[key];
18509           }
18510           dst.$set(key, value, true, srcAttr[key]);
18511         }
18512       });
18513
18514       // copy the new attributes on the old attrs object
18515       forEach(src, function(value, key) {
18516         if (key == 'class') {
18517           safeAddClass($element, value);
18518           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
18519         } else if (key == 'style') {
18520           $element.attr('style', $element.attr('style') + ';' + value);
18521           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
18522           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
18523           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
18524           // have an attribute like "has-own-property" or "data-has-own-property", etc.
18525         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
18526           dst[key] = value;
18527           dstAttr[key] = srcAttr[key];
18528         }
18529       });
18530     }
18531
18532
18533     function compileTemplateUrl(directives, $compileNode, tAttrs,
18534         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
18535       var linkQueue = [],
18536           afterTemplateNodeLinkFn,
18537           afterTemplateChildLinkFn,
18538           beforeTemplateCompileNode = $compileNode[0],
18539           origAsyncDirective = directives.shift(),
18540           derivedSyncDirective = inherit(origAsyncDirective, {
18541             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
18542           }),
18543           templateUrl = (isFunction(origAsyncDirective.templateUrl))
18544               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
18545               : origAsyncDirective.templateUrl,
18546           templateNamespace = origAsyncDirective.templateNamespace;
18547
18548       $compileNode.empty();
18549
18550       $templateRequest(templateUrl)
18551         .then(function(content) {
18552           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
18553
18554           content = denormalizeTemplate(content);
18555
18556           if (origAsyncDirective.replace) {
18557             if (jqLiteIsTextNode(content)) {
18558               $template = [];
18559             } else {
18560               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
18561             }
18562             compileNode = $template[0];
18563
18564             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
18565               throw $compileMinErr('tplrt',
18566                   "Template for directive '{0}' must have exactly one root element. {1}",
18567                   origAsyncDirective.name, templateUrl);
18568             }
18569
18570             tempTemplateAttrs = {$attr: {}};
18571             replaceWith($rootElement, $compileNode, compileNode);
18572             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
18573
18574             if (isObject(origAsyncDirective.scope)) {
18575               // the original directive that caused the template to be loaded async required
18576               // an isolate scope
18577               markDirectiveScope(templateDirectives, true);
18578             }
18579             directives = templateDirectives.concat(directives);
18580             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
18581           } else {
18582             compileNode = beforeTemplateCompileNode;
18583             $compileNode.html(content);
18584           }
18585
18586           directives.unshift(derivedSyncDirective);
18587
18588           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
18589               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
18590               previousCompileContext);
18591           forEach($rootElement, function(node, i) {
18592             if (node == compileNode) {
18593               $rootElement[i] = $compileNode[0];
18594             }
18595           });
18596           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
18597
18598           while (linkQueue.length) {
18599             var scope = linkQueue.shift(),
18600                 beforeTemplateLinkNode = linkQueue.shift(),
18601                 linkRootElement = linkQueue.shift(),
18602                 boundTranscludeFn = linkQueue.shift(),
18603                 linkNode = $compileNode[0];
18604
18605             if (scope.$$destroyed) continue;
18606
18607             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
18608               var oldClasses = beforeTemplateLinkNode.className;
18609
18610               if (!(previousCompileContext.hasElementTranscludeDirective &&
18611                   origAsyncDirective.replace)) {
18612                 // it was cloned therefore we have to clone as well.
18613                 linkNode = jqLiteClone(compileNode);
18614               }
18615               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
18616
18617               // Copy in CSS classes from original node
18618               safeAddClass(jqLite(linkNode), oldClasses);
18619             }
18620             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
18621               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
18622             } else {
18623               childBoundTranscludeFn = boundTranscludeFn;
18624             }
18625             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
18626               childBoundTranscludeFn);
18627           }
18628           linkQueue = null;
18629         });
18630
18631       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
18632         var childBoundTranscludeFn = boundTranscludeFn;
18633         if (scope.$$destroyed) return;
18634         if (linkQueue) {
18635           linkQueue.push(scope,
18636                          node,
18637                          rootElement,
18638                          childBoundTranscludeFn);
18639         } else {
18640           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
18641             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
18642           }
18643           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
18644         }
18645       };
18646     }
18647
18648
18649     /**
18650      * Sorting function for bound directives.
18651      */
18652     function byPriority(a, b) {
18653       var diff = b.priority - a.priority;
18654       if (diff !== 0) return diff;
18655       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
18656       return a.index - b.index;
18657     }
18658
18659     function assertNoDuplicate(what, previousDirective, directive, element) {
18660
18661       function wrapModuleNameIfDefined(moduleName) {
18662         return moduleName ?
18663           (' (module: ' + moduleName + ')') :
18664           '';
18665       }
18666
18667       if (previousDirective) {
18668         throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
18669             previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
18670             directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
18671       }
18672     }
18673
18674
18675     function addTextInterpolateDirective(directives, text) {
18676       var interpolateFn = $interpolate(text, true);
18677       if (interpolateFn) {
18678         directives.push({
18679           priority: 0,
18680           compile: function textInterpolateCompileFn(templateNode) {
18681             var templateNodeParent = templateNode.parent(),
18682                 hasCompileParent = !!templateNodeParent.length;
18683
18684             // When transcluding a template that has bindings in the root
18685             // we don't have a parent and thus need to add the class during linking fn.
18686             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
18687
18688             return function textInterpolateLinkFn(scope, node) {
18689               var parent = node.parent();
18690               if (!hasCompileParent) compile.$$addBindingClass(parent);
18691               compile.$$addBindingInfo(parent, interpolateFn.expressions);
18692               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
18693                 node[0].nodeValue = value;
18694               });
18695             };
18696           }
18697         });
18698       }
18699     }
18700
18701
18702     function wrapTemplate(type, template) {
18703       type = lowercase(type || 'html');
18704       switch (type) {
18705       case 'svg':
18706       case 'math':
18707         var wrapper = window.document.createElement('div');
18708         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
18709         return wrapper.childNodes[0].childNodes;
18710       default:
18711         return template;
18712       }
18713     }
18714
18715
18716     function getTrustedContext(node, attrNormalizedName) {
18717       if (attrNormalizedName == "srcdoc") {
18718         return $sce.HTML;
18719       }
18720       var tag = nodeName_(node);
18721       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
18722       if (attrNormalizedName == "xlinkHref" ||
18723           (tag == "form" && attrNormalizedName == "action") ||
18724           (tag != "img" && (attrNormalizedName == "src" ||
18725                             attrNormalizedName == "ngSrc"))) {
18726         return $sce.RESOURCE_URL;
18727       }
18728     }
18729
18730
18731     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
18732       var trustedContext = getTrustedContext(node, name);
18733       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
18734
18735       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
18736
18737       // no interpolation found -> ignore
18738       if (!interpolateFn) return;
18739
18740
18741       if (name === "multiple" && nodeName_(node) === "select") {
18742         throw $compileMinErr("selmulti",
18743             "Binding to the 'multiple' attribute is not supported. Element: {0}",
18744             startingTag(node));
18745       }
18746
18747       directives.push({
18748         priority: 100,
18749         compile: function() {
18750             return {
18751               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
18752                 var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
18753
18754                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
18755                   throw $compileMinErr('nodomevents',
18756                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
18757                           "ng- versions (such as ng-click instead of onclick) instead.");
18758                 }
18759
18760                 // If the attribute has changed since last $interpolate()ed
18761                 var newValue = attr[name];
18762                 if (newValue !== value) {
18763                   // we need to interpolate again since the attribute value has been updated
18764                   // (e.g. by another directive's compile function)
18765                   // ensure unset/empty values make interpolateFn falsy
18766                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
18767                   value = newValue;
18768                 }
18769
18770                 // if attribute was updated so that there is no interpolation going on we don't want to
18771                 // register any observers
18772                 if (!interpolateFn) return;
18773
18774                 // initialize attr object so that it's ready in case we need the value for isolate
18775                 // scope initialization, otherwise the value would not be available from isolate
18776                 // directive's linking fn during linking phase
18777                 attr[name] = interpolateFn(scope);
18778
18779                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
18780                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
18781                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
18782                     //special case for class attribute addition + removal
18783                     //so that class changes can tap into the animation
18784                     //hooks provided by the $animate service. Be sure to
18785                     //skip animations when the first digest occurs (when
18786                     //both the new and the old values are the same) since
18787                     //the CSS classes are the non-interpolated values
18788                     if (name === 'class' && newValue != oldValue) {
18789                       attr.$updateClass(newValue, oldValue);
18790                     } else {
18791                       attr.$set(name, newValue);
18792                     }
18793                   });
18794               }
18795             };
18796           }
18797       });
18798     }
18799
18800
18801     /**
18802      * This is a special jqLite.replaceWith, which can replace items which
18803      * have no parents, provided that the containing jqLite collection is provided.
18804      *
18805      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
18806      *                               in the root of the tree.
18807      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
18808      *                                  the shell, but replace its DOM node reference.
18809      * @param {Node} newNode The new DOM node.
18810      */
18811     function replaceWith($rootElement, elementsToRemove, newNode) {
18812       var firstElementToRemove = elementsToRemove[0],
18813           removeCount = elementsToRemove.length,
18814           parent = firstElementToRemove.parentNode,
18815           i, ii;
18816
18817       if ($rootElement) {
18818         for (i = 0, ii = $rootElement.length; i < ii; i++) {
18819           if ($rootElement[i] == firstElementToRemove) {
18820             $rootElement[i++] = newNode;
18821             for (var j = i, j2 = j + removeCount - 1,
18822                      jj = $rootElement.length;
18823                  j < jj; j++, j2++) {
18824               if (j2 < jj) {
18825                 $rootElement[j] = $rootElement[j2];
18826               } else {
18827                 delete $rootElement[j];
18828               }
18829             }
18830             $rootElement.length -= removeCount - 1;
18831
18832             // If the replaced element is also the jQuery .context then replace it
18833             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
18834             // http://api.jquery.com/context/
18835             if ($rootElement.context === firstElementToRemove) {
18836               $rootElement.context = newNode;
18837             }
18838             break;
18839           }
18840         }
18841       }
18842
18843       if (parent) {
18844         parent.replaceChild(newNode, firstElementToRemove);
18845       }
18846
18847       // Append all the `elementsToRemove` to a fragment. This will...
18848       // - remove them from the DOM
18849       // - allow them to still be traversed with .nextSibling
18850       // - allow a single fragment.qSA to fetch all elements being removed
18851       var fragment = window.document.createDocumentFragment();
18852       for (i = 0; i < removeCount; i++) {
18853         fragment.appendChild(elementsToRemove[i]);
18854       }
18855
18856       if (jqLite.hasData(firstElementToRemove)) {
18857         // Copy over user data (that includes Angular's $scope etc.). Don't copy private
18858         // data here because there's no public interface in jQuery to do that and copying over
18859         // event listeners (which is the main use of private data) wouldn't work anyway.
18860         jqLite.data(newNode, jqLite.data(firstElementToRemove));
18861
18862         // Remove $destroy event listeners from `firstElementToRemove`
18863         jqLite(firstElementToRemove).off('$destroy');
18864       }
18865
18866       // Cleanup any data/listeners on the elements and children.
18867       // This includes invoking the $destroy event on any elements with listeners.
18868       jqLite.cleanData(fragment.querySelectorAll('*'));
18869
18870       // Update the jqLite collection to only contain the `newNode`
18871       for (i = 1; i < removeCount; i++) {
18872         delete elementsToRemove[i];
18873       }
18874       elementsToRemove[0] = newNode;
18875       elementsToRemove.length = 1;
18876     }
18877
18878
18879     function cloneAndAnnotateFn(fn, annotation) {
18880       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
18881     }
18882
18883
18884     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
18885       try {
18886         linkFn(scope, $element, attrs, controllers, transcludeFn);
18887       } catch (e) {
18888         $exceptionHandler(e, startingTag($element));
18889       }
18890     }
18891
18892
18893     // Set up $watches for isolate scope and controller bindings. This process
18894     // only occurs for isolate scopes and new scopes with controllerAs.
18895     function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
18896       var removeWatchCollection = [];
18897       var initialChanges = {};
18898       var changes;
18899       forEach(bindings, function initializeBinding(definition, scopeName) {
18900         var attrName = definition.attrName,
18901         optional = definition.optional,
18902         mode = definition.mode, // @, =, or &
18903         lastValue,
18904         parentGet, parentSet, compare, removeWatch;
18905
18906         switch (mode) {
18907
18908           case '@':
18909             if (!optional && !hasOwnProperty.call(attrs, attrName)) {
18910               destination[scopeName] = attrs[attrName] = void 0;
18911             }
18912             attrs.$observe(attrName, function(value) {
18913               if (isString(value) || isBoolean(value)) {
18914                 var oldValue = destination[scopeName];
18915                 recordChanges(scopeName, value, oldValue);
18916                 destination[scopeName] = value;
18917               }
18918             });
18919             attrs.$$observers[attrName].$$scope = scope;
18920             lastValue = attrs[attrName];
18921             if (isString(lastValue)) {
18922               // If the attribute has been provided then we trigger an interpolation to ensure
18923               // the value is there for use in the link fn
18924               destination[scopeName] = $interpolate(lastValue)(scope);
18925             } else if (isBoolean(lastValue)) {
18926               // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
18927               // the value to boolean rather than a string, so we special case this situation
18928               destination[scopeName] = lastValue;
18929             }
18930             initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
18931             break;
18932
18933           case '=':
18934             if (!hasOwnProperty.call(attrs, attrName)) {
18935               if (optional) break;
18936               attrs[attrName] = void 0;
18937             }
18938             if (optional && !attrs[attrName]) break;
18939
18940             parentGet = $parse(attrs[attrName]);
18941             if (parentGet.literal) {
18942               compare = equals;
18943             } else {
18944               compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };
18945             }
18946             parentSet = parentGet.assign || function() {
18947               // reset the change, or we will throw this exception on every $digest
18948               lastValue = destination[scopeName] = parentGet(scope);
18949               throw $compileMinErr('nonassign',
18950                   "Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
18951                   attrs[attrName], attrName, directive.name);
18952             };
18953             lastValue = destination[scopeName] = parentGet(scope);
18954             var parentValueWatch = function parentValueWatch(parentValue) {
18955               if (!compare(parentValue, destination[scopeName])) {
18956                 // we are out of sync and need to copy
18957                 if (!compare(parentValue, lastValue)) {
18958                   // parent changed and it has precedence
18959                   destination[scopeName] = parentValue;
18960                 } else {
18961                   // if the parent can be assigned then do so
18962                   parentSet(scope, parentValue = destination[scopeName]);
18963                 }
18964               }
18965               return lastValue = parentValue;
18966             };
18967             parentValueWatch.$stateful = true;
18968             if (definition.collection) {
18969               removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
18970             } else {
18971               removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
18972             }
18973             removeWatchCollection.push(removeWatch);
18974             break;
18975
18976           case '<':
18977             if (!hasOwnProperty.call(attrs, attrName)) {
18978               if (optional) break;
18979               attrs[attrName] = void 0;
18980             }
18981             if (optional && !attrs[attrName]) break;
18982
18983             parentGet = $parse(attrs[attrName]);
18984
18985             destination[scopeName] = parentGet(scope);
18986             initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
18987
18988             removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
18989               if (newValue === oldValue) {
18990                 // If the new and old values are identical then this is the first time the watch has been triggered
18991                 // So instead we use the current value on the destination as the old value
18992                 oldValue = destination[scopeName];
18993               }
18994               recordChanges(scopeName, newValue, oldValue);
18995               destination[scopeName] = newValue;
18996             }, parentGet.literal);
18997
18998             removeWatchCollection.push(removeWatch);
18999             break;
19000
19001           case '&':
19002             // Don't assign Object.prototype method to scope
19003             parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
19004
19005             // Don't assign noop to destination if expression is not valid
19006             if (parentGet === noop && optional) break;
19007
19008             destination[scopeName] = function(locals) {
19009               return parentGet(scope, locals);
19010             };
19011             break;
19012         }
19013       });
19014
19015       function recordChanges(key, currentValue, previousValue) {
19016         if (isFunction(destination.$onChanges) && currentValue !== previousValue) {
19017           // If we have not already scheduled the top level onChangesQueue handler then do so now
19018           if (!onChangesQueue) {
19019             scope.$$postDigest(flushOnChangesQueue);
19020             onChangesQueue = [];
19021           }
19022           // If we have not already queued a trigger of onChanges for this controller then do so now
19023           if (!changes) {
19024             changes = {};
19025             onChangesQueue.push(triggerOnChangesHook);
19026           }
19027           // If the has been a change on this property already then we need to reuse the previous value
19028           if (changes[key]) {
19029             previousValue = changes[key].previousValue;
19030           }
19031           // Store this change
19032           changes[key] = new SimpleChange(previousValue, currentValue);
19033         }
19034       }
19035
19036       function triggerOnChangesHook() {
19037         destination.$onChanges(changes);
19038         // Now clear the changes so that we schedule onChanges when more changes arrive
19039         changes = undefined;
19040       }
19041
19042       return {
19043         initialChanges: initialChanges,
19044         removeWatches: removeWatchCollection.length && function removeWatches() {
19045           for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
19046             removeWatchCollection[i]();
19047           }
19048         }
19049       };
19050     }
19051   }];
19052 }
19053
19054 function SimpleChange(previous, current) {
19055   this.previousValue = previous;
19056   this.currentValue = current;
19057 }
19058 SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
19059
19060
19061 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
19062 /**
19063  * Converts all accepted directives format into proper directive name.
19064  * @param name Name to normalize
19065  */
19066 function directiveNormalize(name) {
19067   return camelCase(name.replace(PREFIX_REGEXP, ''));
19068 }
19069
19070 /**
19071  * @ngdoc type
19072  * @name $compile.directive.Attributes
19073  *
19074  * @description
19075  * A shared object between directive compile / linking functions which contains normalized DOM
19076  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
19077  * needed since all of these are treated as equivalent in Angular:
19078  *
19079  * ```
19080  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
19081  * ```
19082  */
19083
19084 /**
19085  * @ngdoc property
19086  * @name $compile.directive.Attributes#$attr
19087  *
19088  * @description
19089  * A map of DOM element attribute names to the normalized name. This is
19090  * needed to do reverse lookup from normalized name back to actual name.
19091  */
19092
19093
19094 /**
19095  * @ngdoc method
19096  * @name $compile.directive.Attributes#$set
19097  * @kind function
19098  *
19099  * @description
19100  * Set DOM element attribute value.
19101  *
19102  *
19103  * @param {string} name Normalized element attribute name of the property to modify. The name is
19104  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
19105  *          property to the original name.
19106  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
19107  */
19108
19109
19110
19111 /**
19112  * Closure compiler type information
19113  */
19114
19115 function nodesetLinkingFn(
19116   /* angular.Scope */ scope,
19117   /* NodeList */ nodeList,
19118   /* Element */ rootElement,
19119   /* function(Function) */ boundTranscludeFn
19120 ) {}
19121
19122 function directiveLinkingFn(
19123   /* nodesetLinkingFn */ nodesetLinkingFn,
19124   /* angular.Scope */ scope,
19125   /* Node */ node,
19126   /* Element */ rootElement,
19127   /* function(Function) */ boundTranscludeFn
19128 ) {}
19129
19130 function tokenDifference(str1, str2) {
19131   var values = '',
19132       tokens1 = str1.split(/\s+/),
19133       tokens2 = str2.split(/\s+/);
19134
19135   outer:
19136   for (var i = 0; i < tokens1.length; i++) {
19137     var token = tokens1[i];
19138     for (var j = 0; j < tokens2.length; j++) {
19139       if (token == tokens2[j]) continue outer;
19140     }
19141     values += (values.length > 0 ? ' ' : '') + token;
19142   }
19143   return values;
19144 }
19145
19146 function removeComments(jqNodes) {
19147   jqNodes = jqLite(jqNodes);
19148   var i = jqNodes.length;
19149
19150   if (i <= 1) {
19151     return jqNodes;
19152   }
19153
19154   while (i--) {
19155     var node = jqNodes[i];
19156     if (node.nodeType === NODE_TYPE_COMMENT) {
19157       splice.call(jqNodes, i, 1);
19158     }
19159   }
19160   return jqNodes;
19161 }
19162
19163 var $controllerMinErr = minErr('$controller');
19164
19165
19166 var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
19167 function identifierForController(controller, ident) {
19168   if (ident && isString(ident)) return ident;
19169   if (isString(controller)) {
19170     var match = CNTRL_REG.exec(controller);
19171     if (match) return match[3];
19172   }
19173 }
19174
19175
19176 /**
19177  * @ngdoc provider
19178  * @name $controllerProvider
19179  * @description
19180  * The {@link ng.$controller $controller service} is used by Angular to create new
19181  * controllers.
19182  *
19183  * This provider allows controller registration via the
19184  * {@link ng.$controllerProvider#register register} method.
19185  */
19186 function $ControllerProvider() {
19187   var controllers = {},
19188       globals = false;
19189
19190   /**
19191    * @ngdoc method
19192    * @name $controllerProvider#has
19193    * @param {string} name Controller name to check.
19194    */
19195   this.has = function(name) {
19196     return controllers.hasOwnProperty(name);
19197   };
19198
19199   /**
19200    * @ngdoc method
19201    * @name $controllerProvider#register
19202    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
19203    *    the names and the values are the constructors.
19204    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
19205    *    annotations in the array notation).
19206    */
19207   this.register = function(name, constructor) {
19208     assertNotHasOwnProperty(name, 'controller');
19209     if (isObject(name)) {
19210       extend(controllers, name);
19211     } else {
19212       controllers[name] = constructor;
19213     }
19214   };
19215
19216   /**
19217    * @ngdoc method
19218    * @name $controllerProvider#allowGlobals
19219    * @description If called, allows `$controller` to find controller constructors on `window`
19220    */
19221   this.allowGlobals = function() {
19222     globals = true;
19223   };
19224
19225
19226   this.$get = ['$injector', '$window', function($injector, $window) {
19227
19228     /**
19229      * @ngdoc service
19230      * @name $controller
19231      * @requires $injector
19232      *
19233      * @param {Function|string} constructor If called with a function then it's considered to be the
19234      *    controller constructor function. Otherwise it's considered to be a string which is used
19235      *    to retrieve the controller constructor using the following steps:
19236      *
19237      *    * check if a controller with given name is registered via `$controllerProvider`
19238      *    * check if evaluating the string on the current scope returns a constructor
19239      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
19240      *      `window` object (not recommended)
19241      *
19242      *    The string can use the `controller as property` syntax, where the controller instance is published
19243      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
19244      *    to work correctly.
19245      *
19246      * @param {Object} locals Injection locals for Controller.
19247      * @return {Object} Instance of given controller.
19248      *
19249      * @description
19250      * `$controller` service is responsible for instantiating controllers.
19251      *
19252      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
19253      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
19254      */
19255     return function $controller(expression, locals, later, ident) {
19256       // PRIVATE API:
19257       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
19258       //                     If true, $controller will allocate the object with the correct
19259       //                     prototype chain, but will not invoke the controller until a returned
19260       //                     callback is invoked.
19261       //   param `ident` --- An optional label which overrides the label parsed from the controller
19262       //                     expression, if any.
19263       var instance, match, constructor, identifier;
19264       later = later === true;
19265       if (ident && isString(ident)) {
19266         identifier = ident;
19267       }
19268
19269       if (isString(expression)) {
19270         match = expression.match(CNTRL_REG);
19271         if (!match) {
19272           throw $controllerMinErr('ctrlfmt',
19273             "Badly formed controller string '{0}'. " +
19274             "Must match `__name__ as __id__` or `__name__`.", expression);
19275         }
19276         constructor = match[1],
19277         identifier = identifier || match[3];
19278         expression = controllers.hasOwnProperty(constructor)
19279             ? controllers[constructor]
19280             : getter(locals.$scope, constructor, true) ||
19281                 (globals ? getter($window, constructor, true) : undefined);
19282
19283         assertArgFn(expression, constructor, true);
19284       }
19285
19286       if (later) {
19287         // Instantiate controller later:
19288         // This machinery is used to create an instance of the object before calling the
19289         // controller's constructor itself.
19290         //
19291         // This allows properties to be added to the controller before the constructor is
19292         // invoked. Primarily, this is used for isolate scope bindings in $compile.
19293         //
19294         // This feature is not intended for use by applications, and is thus not documented
19295         // publicly.
19296         // Object creation: http://jsperf.com/create-constructor/2
19297         var controllerPrototype = (isArray(expression) ?
19298           expression[expression.length - 1] : expression).prototype;
19299         instance = Object.create(controllerPrototype || null);
19300
19301         if (identifier) {
19302           addIdentifier(locals, identifier, instance, constructor || expression.name);
19303         }
19304
19305         var instantiate;
19306         return instantiate = extend(function $controllerInit() {
19307           var result = $injector.invoke(expression, instance, locals, constructor);
19308           if (result !== instance && (isObject(result) || isFunction(result))) {
19309             instance = result;
19310             if (identifier) {
19311               // If result changed, re-assign controllerAs value to scope.
19312               addIdentifier(locals, identifier, instance, constructor || expression.name);
19313             }
19314           }
19315           return instance;
19316         }, {
19317           instance: instance,
19318           identifier: identifier
19319         });
19320       }
19321
19322       instance = $injector.instantiate(expression, locals, constructor);
19323
19324       if (identifier) {
19325         addIdentifier(locals, identifier, instance, constructor || expression.name);
19326       }
19327
19328       return instance;
19329     };
19330
19331     function addIdentifier(locals, identifier, instance, name) {
19332       if (!(locals && isObject(locals.$scope))) {
19333         throw minErr('$controller')('noscp',
19334           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
19335           name, identifier);
19336       }
19337
19338       locals.$scope[identifier] = instance;
19339     }
19340   }];
19341 }
19342
19343 /**
19344  * @ngdoc service
19345  * @name $document
19346  * @requires $window
19347  *
19348  * @description
19349  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
19350  *
19351  * @example
19352    <example module="documentExample">
19353      <file name="index.html">
19354        <div ng-controller="ExampleController">
19355          <p>$document title: <b ng-bind="title"></b></p>
19356          <p>window.document title: <b ng-bind="windowTitle"></b></p>
19357        </div>
19358      </file>
19359      <file name="script.js">
19360        angular.module('documentExample', [])
19361          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
19362            $scope.title = $document[0].title;
19363            $scope.windowTitle = angular.element(window.document)[0].title;
19364          }]);
19365      </file>
19366    </example>
19367  */
19368 function $DocumentProvider() {
19369   this.$get = ['$window', function(window) {
19370     return jqLite(window.document);
19371   }];
19372 }
19373
19374 /**
19375  * @ngdoc service
19376  * @name $exceptionHandler
19377  * @requires ng.$log
19378  *
19379  * @description
19380  * Any uncaught exception in angular expressions is delegated to this service.
19381  * The default implementation simply delegates to `$log.error` which logs it into
19382  * the browser console.
19383  *
19384  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
19385  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
19386  *
19387  * ## Example:
19388  *
19389  * ```js
19390  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
19391  *     return function(exception, cause) {
19392  *       exception.message += ' (caused by "' + cause + '")';
19393  *       throw exception;
19394  *     };
19395  *   });
19396  * ```
19397  *
19398  * This example will override the normal action of `$exceptionHandler`, to make angular
19399  * exceptions fail hard when they happen, instead of just logging to the console.
19400  *
19401  * <hr />
19402  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
19403  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
19404  * (unless executed during a digest).
19405  *
19406  * If you wish, you can manually delegate exceptions, e.g.
19407  * `try { ... } catch(e) { $exceptionHandler(e); }`
19408  *
19409  * @param {Error} exception Exception associated with the error.
19410  * @param {string=} cause optional information about the context in which
19411  *       the error was thrown.
19412  *
19413  */
19414 function $ExceptionHandlerProvider() {
19415   this.$get = ['$log', function($log) {
19416     return function(exception, cause) {
19417       $log.error.apply($log, arguments);
19418     };
19419   }];
19420 }
19421
19422 var $$ForceReflowProvider = function() {
19423   this.$get = ['$document', function($document) {
19424     return function(domNode) {
19425       //the line below will force the browser to perform a repaint so
19426       //that all the animated elements within the animation frame will
19427       //be properly updated and drawn on screen. This is required to
19428       //ensure that the preparation animation is properly flushed so that
19429       //the active state picks up from there. DO NOT REMOVE THIS LINE.
19430       //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
19431       //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
19432       //WILL TAKE YEARS AWAY FROM YOUR LIFE.
19433       if (domNode) {
19434         if (!domNode.nodeType && domNode instanceof jqLite) {
19435           domNode = domNode[0];
19436         }
19437       } else {
19438         domNode = $document[0].body;
19439       }
19440       return domNode.offsetWidth + 1;
19441     };
19442   }];
19443 };
19444
19445 var APPLICATION_JSON = 'application/json';
19446 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
19447 var JSON_START = /^\[|^\{(?!\{)/;
19448 var JSON_ENDS = {
19449   '[': /]$/,
19450   '{': /}$/
19451 };
19452 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
19453 var $httpMinErr = minErr('$http');
19454 var $httpMinErrLegacyFn = function(method) {
19455   return function() {
19456     throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
19457   };
19458 };
19459
19460 function serializeValue(v) {
19461   if (isObject(v)) {
19462     return isDate(v) ? v.toISOString() : toJson(v);
19463   }
19464   return v;
19465 }
19466
19467
19468 function $HttpParamSerializerProvider() {
19469   /**
19470    * @ngdoc service
19471    * @name $httpParamSerializer
19472    * @description
19473    *
19474    * Default {@link $http `$http`} params serializer that converts objects to strings
19475    * according to the following rules:
19476    *
19477    * * `{'foo': 'bar'}` results in `foo=bar`
19478    * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
19479    * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
19480    * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
19481    *
19482    * Note that serializer will sort the request parameters alphabetically.
19483    * */
19484
19485   this.$get = function() {
19486     return function ngParamSerializer(params) {
19487       if (!params) return '';
19488       var parts = [];
19489       forEachSorted(params, function(value, key) {
19490         if (value === null || isUndefined(value)) return;
19491         if (isArray(value)) {
19492           forEach(value, function(v) {
19493             parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
19494           });
19495         } else {
19496           parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
19497         }
19498       });
19499
19500       return parts.join('&');
19501     };
19502   };
19503 }
19504
19505 function $HttpParamSerializerJQLikeProvider() {
19506   /**
19507    * @ngdoc service
19508    * @name $httpParamSerializerJQLike
19509    * @description
19510    *
19511    * Alternative {@link $http `$http`} params serializer that follows
19512    * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
19513    * The serializer will also sort the params alphabetically.
19514    *
19515    * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
19516    *
19517    * ```js
19518    * $http({
19519    *   url: myUrl,
19520    *   method: 'GET',
19521    *   params: myParams,
19522    *   paramSerializer: '$httpParamSerializerJQLike'
19523    * });
19524    * ```
19525    *
19526    * It is also possible to set it as the default `paramSerializer` in the
19527    * {@link $httpProvider#defaults `$httpProvider`}.
19528    *
19529    * Additionally, you can inject the serializer and use it explicitly, for example to serialize
19530    * form data for submission:
19531    *
19532    * ```js
19533    * .controller(function($http, $httpParamSerializerJQLike) {
19534    *   //...
19535    *
19536    *   $http({
19537    *     url: myUrl,
19538    *     method: 'POST',
19539    *     data: $httpParamSerializerJQLike(myData),
19540    *     headers: {
19541    *       'Content-Type': 'application/x-www-form-urlencoded'
19542    *     }
19543    *   });
19544    *
19545    * });
19546    * ```
19547    *
19548    * */
19549   this.$get = function() {
19550     return function jQueryLikeParamSerializer(params) {
19551       if (!params) return '';
19552       var parts = [];
19553       serialize(params, '', true);
19554       return parts.join('&');
19555
19556       function serialize(toSerialize, prefix, topLevel) {
19557         if (toSerialize === null || isUndefined(toSerialize)) return;
19558         if (isArray(toSerialize)) {
19559           forEach(toSerialize, function(value, index) {
19560             serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
19561           });
19562         } else if (isObject(toSerialize) && !isDate(toSerialize)) {
19563           forEachSorted(toSerialize, function(value, key) {
19564             serialize(value, prefix +
19565                 (topLevel ? '' : '[') +
19566                 key +
19567                 (topLevel ? '' : ']'));
19568           });
19569         } else {
19570           parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
19571         }
19572       }
19573     };
19574   };
19575 }
19576
19577 function defaultHttpResponseTransform(data, headers) {
19578   if (isString(data)) {
19579     // Strip json vulnerability protection prefix and trim whitespace
19580     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
19581
19582     if (tempData) {
19583       var contentType = headers('Content-Type');
19584       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
19585         data = fromJson(tempData);
19586       }
19587     }
19588   }
19589
19590   return data;
19591 }
19592
19593 function isJsonLike(str) {
19594     var jsonStart = str.match(JSON_START);
19595     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
19596 }
19597
19598 /**
19599  * Parse headers into key value object
19600  *
19601  * @param {string} headers Raw headers as a string
19602  * @returns {Object} Parsed headers as key value object
19603  */
19604 function parseHeaders(headers) {
19605   var parsed = createMap(), i;
19606
19607   function fillInParsed(key, val) {
19608     if (key) {
19609       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
19610     }
19611   }
19612
19613   if (isString(headers)) {
19614     forEach(headers.split('\n'), function(line) {
19615       i = line.indexOf(':');
19616       fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
19617     });
19618   } else if (isObject(headers)) {
19619     forEach(headers, function(headerVal, headerKey) {
19620       fillInParsed(lowercase(headerKey), trim(headerVal));
19621     });
19622   }
19623
19624   return parsed;
19625 }
19626
19627
19628 /**
19629  * Returns a function that provides access to parsed headers.
19630  *
19631  * Headers are lazy parsed when first requested.
19632  * @see parseHeaders
19633  *
19634  * @param {(string|Object)} headers Headers to provide access to.
19635  * @returns {function(string=)} Returns a getter function which if called with:
19636  *
19637  *   - if called with single an argument returns a single header value or null
19638  *   - if called with no arguments returns an object containing all headers.
19639  */
19640 function headersGetter(headers) {
19641   var headersObj;
19642
19643   return function(name) {
19644     if (!headersObj) headersObj =  parseHeaders(headers);
19645
19646     if (name) {
19647       var value = headersObj[lowercase(name)];
19648       if (value === void 0) {
19649         value = null;
19650       }
19651       return value;
19652     }
19653
19654     return headersObj;
19655   };
19656 }
19657
19658
19659 /**
19660  * Chain all given functions
19661  *
19662  * This function is used for both request and response transforming
19663  *
19664  * @param {*} data Data to transform.
19665  * @param {function(string=)} headers HTTP headers getter fn.
19666  * @param {number} status HTTP status code of the response.
19667  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
19668  * @returns {*} Transformed data.
19669  */
19670 function transformData(data, headers, status, fns) {
19671   if (isFunction(fns)) {
19672     return fns(data, headers, status);
19673   }
19674
19675   forEach(fns, function(fn) {
19676     data = fn(data, headers, status);
19677   });
19678
19679   return data;
19680 }
19681
19682
19683 function isSuccess(status) {
19684   return 200 <= status && status < 300;
19685 }
19686
19687
19688 /**
19689  * @ngdoc provider
19690  * @name $httpProvider
19691  * @description
19692  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
19693  * */
19694 function $HttpProvider() {
19695   /**
19696    * @ngdoc property
19697    * @name $httpProvider#defaults
19698    * @description
19699    *
19700    * Object containing default values for all {@link ng.$http $http} requests.
19701    *
19702    * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
19703    * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
19704    * by default. See {@link $http#caching $http Caching} for more information.
19705    *
19706    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
19707    * Defaults value is `'XSRF-TOKEN'`.
19708    *
19709    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
19710    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
19711    *
19712    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
19713    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
19714    * setting default headers.
19715    *     - **`defaults.headers.common`**
19716    *     - **`defaults.headers.post`**
19717    *     - **`defaults.headers.put`**
19718    *     - **`defaults.headers.patch`**
19719    *
19720    *
19721    * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
19722    *  used to the prepare string representation of request parameters (specified as an object).
19723    *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
19724    *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
19725    *
19726    **/
19727   var defaults = this.defaults = {
19728     // transform incoming response data
19729     transformResponse: [defaultHttpResponseTransform],
19730
19731     // transform outgoing request data
19732     transformRequest: [function(d) {
19733       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
19734     }],
19735
19736     // default headers
19737     headers: {
19738       common: {
19739         'Accept': 'application/json, text/plain, */*'
19740       },
19741       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
19742       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
19743       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
19744     },
19745
19746     xsrfCookieName: 'XSRF-TOKEN',
19747     xsrfHeaderName: 'X-XSRF-TOKEN',
19748
19749     paramSerializer: '$httpParamSerializer'
19750   };
19751
19752   var useApplyAsync = false;
19753   /**
19754    * @ngdoc method
19755    * @name $httpProvider#useApplyAsync
19756    * @description
19757    *
19758    * Configure $http service to combine processing of multiple http responses received at around
19759    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
19760    * significant performance improvement for bigger applications that make many HTTP requests
19761    * concurrently (common during application bootstrap).
19762    *
19763    * Defaults to false. If no value is specified, returns the current configured value.
19764    *
19765    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
19766    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
19767    *    to load and share the same digest cycle.
19768    *
19769    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
19770    *    otherwise, returns the current configured value.
19771    **/
19772   this.useApplyAsync = function(value) {
19773     if (isDefined(value)) {
19774       useApplyAsync = !!value;
19775       return this;
19776     }
19777     return useApplyAsync;
19778   };
19779
19780   var useLegacyPromise = true;
19781   /**
19782    * @ngdoc method
19783    * @name $httpProvider#useLegacyPromiseExtensions
19784    * @description
19785    *
19786    * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
19787    * This should be used to make sure that applications work without these methods.
19788    *
19789    * Defaults to true. If no value is specified, returns the current configured value.
19790    *
19791    * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
19792    *
19793    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
19794    *    otherwise, returns the current configured value.
19795    **/
19796   this.useLegacyPromiseExtensions = function(value) {
19797     if (isDefined(value)) {
19798       useLegacyPromise = !!value;
19799       return this;
19800     }
19801     return useLegacyPromise;
19802   };
19803
19804   /**
19805    * @ngdoc property
19806    * @name $httpProvider#interceptors
19807    * @description
19808    *
19809    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
19810    * pre-processing of request or postprocessing of responses.
19811    *
19812    * These service factories are ordered by request, i.e. they are applied in the same order as the
19813    * array, on request, but reverse order, on response.
19814    *
19815    * {@link ng.$http#interceptors Interceptors detailed info}
19816    **/
19817   var interceptorFactories = this.interceptors = [];
19818
19819   this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
19820       function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
19821
19822     var defaultCache = $cacheFactory('$http');
19823
19824     /**
19825      * Make sure that default param serializer is exposed as a function
19826      */
19827     defaults.paramSerializer = isString(defaults.paramSerializer) ?
19828       $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
19829
19830     /**
19831      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
19832      * The reversal is needed so that we can build up the interception chain around the
19833      * server request.
19834      */
19835     var reversedInterceptors = [];
19836
19837     forEach(interceptorFactories, function(interceptorFactory) {
19838       reversedInterceptors.unshift(isString(interceptorFactory)
19839           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
19840     });
19841
19842     /**
19843      * @ngdoc service
19844      * @kind function
19845      * @name $http
19846      * @requires ng.$httpBackend
19847      * @requires $cacheFactory
19848      * @requires $rootScope
19849      * @requires $q
19850      * @requires $injector
19851      *
19852      * @description
19853      * The `$http` service is a core Angular service that facilitates communication with the remote
19854      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
19855      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
19856      *
19857      * For unit testing applications that use `$http` service, see
19858      * {@link ngMock.$httpBackend $httpBackend mock}.
19859      *
19860      * For a higher level of abstraction, please check out the {@link ngResource.$resource
19861      * $resource} service.
19862      *
19863      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
19864      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
19865      * it is important to familiarize yourself with these APIs and the guarantees they provide.
19866      *
19867      *
19868      * ## General usage
19869      * The `$http` service is a function which takes a single argument â€” a {@link $http#usage configuration object} â€”
19870      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
19871      *
19872      * ```js
19873      *   // Simple GET request example:
19874      *   $http({
19875      *     method: 'GET',
19876      *     url: '/someUrl'
19877      *   }).then(function successCallback(response) {
19878      *       // this callback will be called asynchronously
19879      *       // when the response is available
19880      *     }, function errorCallback(response) {
19881      *       // called asynchronously if an error occurs
19882      *       // or server returns response with an error status.
19883      *     });
19884      * ```
19885      *
19886      * The response object has these properties:
19887      *
19888      *   - **data** â€“ `{string|Object}` â€“ The response body transformed with the transform
19889      *     functions.
19890      *   - **status** â€“ `{number}` â€“ HTTP status code of the response.
19891      *   - **headers** â€“ `{function([headerName])}` â€“ Header getter function.
19892      *   - **config** â€“ `{Object}` â€“ The configuration object that was used to generate the request.
19893      *   - **statusText** â€“ `{string}` â€“ HTTP status text of the response.
19894      *
19895      * A response status code between 200 and 299 is considered a success status and
19896      * will result in the success callback being called. Note that if the response is a redirect,
19897      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
19898      * called for such responses.
19899      *
19900      *
19901      * ## Shortcut methods
19902      *
19903      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
19904      * request data must be passed in for POST/PUT requests. An optional config can be passed as the
19905      * last argument.
19906      *
19907      * ```js
19908      *   $http.get('/someUrl', config).then(successCallback, errorCallback);
19909      *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
19910      * ```
19911      *
19912      * Complete list of shortcut methods:
19913      *
19914      * - {@link ng.$http#get $http.get}
19915      * - {@link ng.$http#head $http.head}
19916      * - {@link ng.$http#post $http.post}
19917      * - {@link ng.$http#put $http.put}
19918      * - {@link ng.$http#delete $http.delete}
19919      * - {@link ng.$http#jsonp $http.jsonp}
19920      * - {@link ng.$http#patch $http.patch}
19921      *
19922      *
19923      * ## Writing Unit Tests that use $http
19924      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
19925      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
19926      * request using trained responses.
19927      *
19928      * ```
19929      * $httpBackend.expectGET(...);
19930      * $http.get(...);
19931      * $httpBackend.flush();
19932      * ```
19933      *
19934      * ## Deprecation Notice
19935      * <div class="alert alert-danger">
19936      *   The `$http` legacy promise methods `success` and `error` have been deprecated.
19937      *   Use the standard `then` method instead.
19938      *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
19939      *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
19940      * </div>
19941      *
19942      * ## Setting HTTP Headers
19943      *
19944      * The $http service will automatically add certain HTTP headers to all requests. These defaults
19945      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
19946      * object, which currently contains this default configuration:
19947      *
19948      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
19949      *   - `Accept: application/json, text/plain, * / *`
19950      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
19951      *   - `Content-Type: application/json`
19952      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
19953      *   - `Content-Type: application/json`
19954      *
19955      * To add or overwrite these defaults, simply add or remove a property from these configuration
19956      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
19957      * with the lowercased HTTP method name as the key, e.g.
19958      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
19959      *
19960      * The defaults can also be set at runtime via the `$http.defaults` object in the same
19961      * fashion. For example:
19962      *
19963      * ```
19964      * module.run(function($http) {
19965      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
19966      * });
19967      * ```
19968      *
19969      * In addition, you can supply a `headers` property in the config object passed when
19970      * calling `$http(config)`, which overrides the defaults without changing them globally.
19971      *
19972      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
19973      * Use the `headers` property, setting the desired header to `undefined`. For example:
19974      *
19975      * ```js
19976      * var req = {
19977      *  method: 'POST',
19978      *  url: 'http://example.com',
19979      *  headers: {
19980      *    'Content-Type': undefined
19981      *  },
19982      *  data: { test: 'test' }
19983      * }
19984      *
19985      * $http(req).then(function(){...}, function(){...});
19986      * ```
19987      *
19988      * ## Transforming Requests and Responses
19989      *
19990      * Both requests and responses can be transformed using transformation functions: `transformRequest`
19991      * and `transformResponse`. These properties can be a single function that returns
19992      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
19993      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
19994      *
19995      * <div class="alert alert-warning">
19996      * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
19997      * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
19998      * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
19999      * function will be reflected on the scope and in any templates where the object is data-bound.
20000      * To prevent this, transform functions should have no side-effects.
20001      * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
20002      * </div>
20003      *
20004      * ### Default Transformations
20005      *
20006      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
20007      * `defaults.transformResponse` properties. If a request does not provide its own transformations
20008      * then these will be applied.
20009      *
20010      * You can augment or replace the default transformations by modifying these properties by adding to or
20011      * replacing the array.
20012      *
20013      * Angular provides the following default transformations:
20014      *
20015      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
20016      *
20017      * - If the `data` property of the request configuration object contains an object, serialize it
20018      *   into JSON format.
20019      *
20020      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
20021      *
20022      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
20023      *  - If JSON response is detected, deserialize it using a JSON parser.
20024      *
20025      *
20026      * ### Overriding the Default Transformations Per Request
20027      *
20028      * If you wish override the request/response transformations only for a single request then provide
20029      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
20030      * into `$http`.
20031      *
20032      * Note that if you provide these properties on the config object the default transformations will be
20033      * overwritten. If you wish to augment the default transformations then you must include them in your
20034      * local transformation array.
20035      *
20036      * The following code demonstrates adding a new response transformation to be run after the default response
20037      * transformations have been run.
20038      *
20039      * ```js
20040      * function appendTransform(defaults, transform) {
20041      *
20042      *   // We can't guarantee that the default transformation is an array
20043      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
20044      *
20045      *   // Append the new transformation to the defaults
20046      *   return defaults.concat(transform);
20047      * }
20048      *
20049      * $http({
20050      *   url: '...',
20051      *   method: 'GET',
20052      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
20053      *     return doTransform(value);
20054      *   })
20055      * });
20056      * ```
20057      *
20058      *
20059      * ## Caching
20060      *
20061      * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
20062      * set the config.cache value or the default cache value to TRUE or to a cache object (created
20063      * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
20064      * precedence over the default cache value.
20065      *
20066      * In order to:
20067      *   * cache all responses - set the default cache value to TRUE or to a cache object
20068      *   * cache a specific response - set config.cache value to TRUE or to a cache object
20069      *
20070      * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
20071      * then the default `$cacheFactory($http)` object is used.
20072      *
20073      * The default cache value can be set by updating the
20074      * {@link ng.$http#defaults `$http.defaults.cache`} property or the
20075      * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
20076      *
20077      * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
20078      * the relevant cache object. The next time the same request is made, the response is returned
20079      * from the cache without sending a request to the server.
20080      *
20081      * Take note that:
20082      *
20083      *   * Only GET and JSONP requests are cached.
20084      *   * The cache key is the request URL including search parameters; headers are not considered.
20085      *   * Cached responses are returned asynchronously, in the same way as responses from the server.
20086      *   * If multiple identical requests are made using the same cache, which is not yet populated,
20087      *     one request will be made to the server and remaining requests will return the same response.
20088      *   * A cache-control header on the response does not affect if or how responses are cached.
20089      *
20090      *
20091      * ## Interceptors
20092      *
20093      * Before you start creating interceptors, be sure to understand the
20094      * {@link ng.$q $q and deferred/promise APIs}.
20095      *
20096      * For purposes of global error handling, authentication, or any kind of synchronous or
20097      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
20098      * able to intercept requests before they are handed to the server and
20099      * responses before they are handed over to the application code that
20100      * initiated these requests. The interceptors leverage the {@link ng.$q
20101      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
20102      *
20103      * The interceptors are service factories that are registered with the `$httpProvider` by
20104      * adding them to the `$httpProvider.interceptors` array. The factory is called and
20105      * injected with dependencies (if specified) and returns the interceptor.
20106      *
20107      * There are two kinds of interceptors (and two kinds of rejection interceptors):
20108      *
20109      *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
20110      *     modify the `config` object or create a new one. The function needs to return the `config`
20111      *     object directly, or a promise containing the `config` or a new `config` object.
20112      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
20113      *     resolved with a rejection.
20114      *   * `response`: interceptors get called with http `response` object. The function is free to
20115      *     modify the `response` object or create a new one. The function needs to return the `response`
20116      *     object directly, or as a promise containing the `response` or a new `response` object.
20117      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
20118      *     resolved with a rejection.
20119      *
20120      *
20121      * ```js
20122      *   // register the interceptor as a service
20123      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
20124      *     return {
20125      *       // optional method
20126      *       'request': function(config) {
20127      *         // do something on success
20128      *         return config;
20129      *       },
20130      *
20131      *       // optional method
20132      *      'requestError': function(rejection) {
20133      *         // do something on error
20134      *         if (canRecover(rejection)) {
20135      *           return responseOrNewPromise
20136      *         }
20137      *         return $q.reject(rejection);
20138      *       },
20139      *
20140      *
20141      *
20142      *       // optional method
20143      *       'response': function(response) {
20144      *         // do something on success
20145      *         return response;
20146      *       },
20147      *
20148      *       // optional method
20149      *      'responseError': function(rejection) {
20150      *         // do something on error
20151      *         if (canRecover(rejection)) {
20152      *           return responseOrNewPromise
20153      *         }
20154      *         return $q.reject(rejection);
20155      *       }
20156      *     };
20157      *   });
20158      *
20159      *   $httpProvider.interceptors.push('myHttpInterceptor');
20160      *
20161      *
20162      *   // alternatively, register the interceptor via an anonymous factory
20163      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
20164      *     return {
20165      *      'request': function(config) {
20166      *          // same as above
20167      *       },
20168      *
20169      *       'response': function(response) {
20170      *          // same as above
20171      *       }
20172      *     };
20173      *   });
20174      * ```
20175      *
20176      * ## Security Considerations
20177      *
20178      * When designing web applications, consider security threats from:
20179      *
20180      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
20181      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
20182      *
20183      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
20184      * pre-configured with strategies that address these issues, but for this to work backend server
20185      * cooperation is required.
20186      *
20187      * ### JSON Vulnerability Protection
20188      *
20189      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
20190      * allows third party website to turn your JSON resource URL into
20191      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
20192      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
20193      * Angular will automatically strip the prefix before processing it as JSON.
20194      *
20195      * For example if your server needs to return:
20196      * ```js
20197      * ['one','two']
20198      * ```
20199      *
20200      * which is vulnerable to attack, your server can return:
20201      * ```js
20202      * )]}',
20203      * ['one','two']
20204      * ```
20205      *
20206      * Angular will strip the prefix, before processing the JSON.
20207      *
20208      *
20209      * ### Cross Site Request Forgery (XSRF) Protection
20210      *
20211      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
20212      * which the attacker can trick an authenticated user into unknowingly executing actions on your
20213      * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
20214      * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
20215      * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
20216      * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
20217      * The header will not be set for cross-domain requests.
20218      *
20219      * To take advantage of this, your server needs to set a token in a JavaScript readable session
20220      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
20221      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
20222      * that only JavaScript running on your domain could have sent the request. The token must be
20223      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
20224      * making up its own tokens). We recommend that the token is a digest of your site's
20225      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
20226      * for added security.
20227      *
20228      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
20229      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
20230      * or the per-request config object.
20231      *
20232      * In order to prevent collisions in environments where multiple Angular apps share the
20233      * same domain or subdomain, we recommend that each application uses unique cookie name.
20234      *
20235      * @param {object} config Object describing the request to be made and how it should be
20236      *    processed. The object has following properties:
20237      *
20238      *    - **method** â€“ `{string}` â€“ HTTP method (e.g. 'GET', 'POST', etc)
20239      *    - **url** â€“ `{string}` â€“ Absolute or relative URL of the resource that is being requested.
20240      *    - **params** â€“ `{Object.<string|Object>}` â€“ Map of strings or objects which will be serialized
20241      *      with the `paramSerializer` and appended as GET parameters.
20242      *    - **data** â€“ `{string|Object}` â€“ Data to be sent as the request message data.
20243      *    - **headers** â€“ `{Object}` â€“ Map of strings or functions which return strings representing
20244      *      HTTP headers to send to the server. If the return value of a function is null, the
20245      *      header will not be sent. Functions accept a config object as an argument.
20246      *    - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
20247      *      To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
20248      *      The handler will be called in the context of a `$apply` block.
20249      *    - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
20250      *      object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
20251      *      The handler will be called in the context of a `$apply` block.
20252      *    - **xsrfHeaderName** â€“ `{string}` â€“ Name of HTTP header to populate with the XSRF token.
20253      *    - **xsrfCookieName** â€“ `{string}` â€“ Name of cookie containing the XSRF token.
20254      *    - **transformRequest** â€“
20255      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` â€“
20256      *      transform function or an array of such functions. The transform function takes the http
20257      *      request body and headers and returns its transformed (typically serialized) version.
20258      *      See {@link ng.$http#overriding-the-default-transformations-per-request
20259      *      Overriding the Default Transformations}
20260      *    - **transformResponse** â€“
20261      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` â€“
20262      *      transform function or an array of such functions. The transform function takes the http
20263      *      response body, headers and status and returns its transformed (typically deserialized) version.
20264      *      See {@link ng.$http#overriding-the-default-transformations-per-request
20265      *      Overriding the Default Transformations}
20266      *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
20267      *      prepare the string representation of request parameters (specified as an object).
20268      *      If specified as string, it is interpreted as function registered with the
20269      *      {@link $injector $injector}, which means you can create your own serializer
20270      *      by registering it as a {@link auto.$provide#service service}.
20271      *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
20272      *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
20273      *    - **cache** â€“ `{boolean|Object}` â€“ A boolean value or object created with
20274      *      {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
20275      *      See {@link $http#caching $http Caching} for more information.
20276      *    - **timeout** â€“ `{number|Promise}` â€“ timeout in milliseconds, or {@link ng.$q promise}
20277      *      that should abort the request when resolved.
20278      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
20279      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
20280      *      for more information.
20281      *    - **responseType** - `{string}` - see
20282      *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
20283      *
20284      * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
20285      *                        when the request succeeds or fails.
20286      *
20287      *
20288      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
20289      *   requests. This is primarily meant to be used for debugging purposes.
20290      *
20291      *
20292      * @example
20293 <example module="httpExample">
20294 <file name="index.html">
20295   <div ng-controller="FetchController">
20296     <select ng-model="method" aria-label="Request method">
20297       <option>GET</option>
20298       <option>JSONP</option>
20299     </select>
20300     <input type="text" ng-model="url" size="80" aria-label="URL" />
20301     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
20302     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
20303     <button id="samplejsonpbtn"
20304       ng-click="updateModel('JSONP',
20305                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
20306       Sample JSONP
20307     </button>
20308     <button id="invalidjsonpbtn"
20309       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
20310         Invalid JSONP
20311       </button>
20312     <pre>http status code: {{status}}</pre>
20313     <pre>http response data: {{data}}</pre>
20314   </div>
20315 </file>
20316 <file name="script.js">
20317   angular.module('httpExample', [])
20318     .controller('FetchController', ['$scope', '$http', '$templateCache',
20319       function($scope, $http, $templateCache) {
20320         $scope.method = 'GET';
20321         $scope.url = 'http-hello.html';
20322
20323         $scope.fetch = function() {
20324           $scope.code = null;
20325           $scope.response = null;
20326
20327           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
20328             then(function(response) {
20329               $scope.status = response.status;
20330               $scope.data = response.data;
20331             }, function(response) {
20332               $scope.data = response.data || "Request failed";
20333               $scope.status = response.status;
20334           });
20335         };
20336
20337         $scope.updateModel = function(method, url) {
20338           $scope.method = method;
20339           $scope.url = url;
20340         };
20341       }]);
20342 </file>
20343 <file name="http-hello.html">
20344   Hello, $http!
20345 </file>
20346 <file name="protractor.js" type="protractor">
20347   var status = element(by.binding('status'));
20348   var data = element(by.binding('data'));
20349   var fetchBtn = element(by.id('fetchbtn'));
20350   var sampleGetBtn = element(by.id('samplegetbtn'));
20351   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
20352   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
20353
20354   it('should make an xhr GET request', function() {
20355     sampleGetBtn.click();
20356     fetchBtn.click();
20357     expect(status.getText()).toMatch('200');
20358     expect(data.getText()).toMatch(/Hello, \$http!/);
20359   });
20360
20361 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
20362 // it('should make a JSONP request to angularjs.org', function() {
20363 //   sampleJsonpBtn.click();
20364 //   fetchBtn.click();
20365 //   expect(status.getText()).toMatch('200');
20366 //   expect(data.getText()).toMatch(/Super Hero!/);
20367 // });
20368
20369   it('should make JSONP request to invalid URL and invoke the error handler',
20370       function() {
20371     invalidJsonpBtn.click();
20372     fetchBtn.click();
20373     expect(status.getText()).toMatch('0');
20374     expect(data.getText()).toMatch('Request failed');
20375   });
20376 </file>
20377 </example>
20378      */
20379     function $http(requestConfig) {
20380
20381       if (!isObject(requestConfig)) {
20382         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
20383       }
20384
20385       if (!isString(requestConfig.url)) {
20386         throw minErr('$http')('badreq', 'Http request configuration url must be a string.  Received: {0}', requestConfig.url);
20387       }
20388
20389       var config = extend({
20390         method: 'get',
20391         transformRequest: defaults.transformRequest,
20392         transformResponse: defaults.transformResponse,
20393         paramSerializer: defaults.paramSerializer
20394       }, requestConfig);
20395
20396       config.headers = mergeHeaders(requestConfig);
20397       config.method = uppercase(config.method);
20398       config.paramSerializer = isString(config.paramSerializer) ?
20399         $injector.get(config.paramSerializer) : config.paramSerializer;
20400
20401       var serverRequest = function(config) {
20402         var headers = config.headers;
20403         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
20404
20405         // strip content-type if data is undefined
20406         if (isUndefined(reqData)) {
20407           forEach(headers, function(value, header) {
20408             if (lowercase(header) === 'content-type') {
20409                 delete headers[header];
20410             }
20411           });
20412         }
20413
20414         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
20415           config.withCredentials = defaults.withCredentials;
20416         }
20417
20418         // send request
20419         return sendReq(config, reqData).then(transformResponse, transformResponse);
20420       };
20421
20422       var chain = [serverRequest, undefined];
20423       var promise = $q.when(config);
20424
20425       // apply interceptors
20426       forEach(reversedInterceptors, function(interceptor) {
20427         if (interceptor.request || interceptor.requestError) {
20428           chain.unshift(interceptor.request, interceptor.requestError);
20429         }
20430         if (interceptor.response || interceptor.responseError) {
20431           chain.push(interceptor.response, interceptor.responseError);
20432         }
20433       });
20434
20435       while (chain.length) {
20436         var thenFn = chain.shift();
20437         var rejectFn = chain.shift();
20438
20439         promise = promise.then(thenFn, rejectFn);
20440       }
20441
20442       if (useLegacyPromise) {
20443         promise.success = function(fn) {
20444           assertArgFn(fn, 'fn');
20445
20446           promise.then(function(response) {
20447             fn(response.data, response.status, response.headers, config);
20448           });
20449           return promise;
20450         };
20451
20452         promise.error = function(fn) {
20453           assertArgFn(fn, 'fn');
20454
20455           promise.then(null, function(response) {
20456             fn(response.data, response.status, response.headers, config);
20457           });
20458           return promise;
20459         };
20460       } else {
20461         promise.success = $httpMinErrLegacyFn('success');
20462         promise.error = $httpMinErrLegacyFn('error');
20463       }
20464
20465       return promise;
20466
20467       function transformResponse(response) {
20468         // make a copy since the response must be cacheable
20469         var resp = extend({}, response);
20470         resp.data = transformData(response.data, response.headers, response.status,
20471                                   config.transformResponse);
20472         return (isSuccess(response.status))
20473           ? resp
20474           : $q.reject(resp);
20475       }
20476
20477       function executeHeaderFns(headers, config) {
20478         var headerContent, processedHeaders = {};
20479
20480         forEach(headers, function(headerFn, header) {
20481           if (isFunction(headerFn)) {
20482             headerContent = headerFn(config);
20483             if (headerContent != null) {
20484               processedHeaders[header] = headerContent;
20485             }
20486           } else {
20487             processedHeaders[header] = headerFn;
20488           }
20489         });
20490
20491         return processedHeaders;
20492       }
20493
20494       function mergeHeaders(config) {
20495         var defHeaders = defaults.headers,
20496             reqHeaders = extend({}, config.headers),
20497             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
20498
20499         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
20500
20501         // using for-in instead of forEach to avoid unnecessary iteration after header has been found
20502         defaultHeadersIteration:
20503         for (defHeaderName in defHeaders) {
20504           lowercaseDefHeaderName = lowercase(defHeaderName);
20505
20506           for (reqHeaderName in reqHeaders) {
20507             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
20508               continue defaultHeadersIteration;
20509             }
20510           }
20511
20512           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
20513         }
20514
20515         // execute if header value is a function for merged headers
20516         return executeHeaderFns(reqHeaders, shallowCopy(config));
20517       }
20518     }
20519
20520     $http.pendingRequests = [];
20521
20522     /**
20523      * @ngdoc method
20524      * @name $http#get
20525      *
20526      * @description
20527      * Shortcut method to perform `GET` request.
20528      *
20529      * @param {string} url Relative or absolute URL specifying the destination of the request
20530      * @param {Object=} config Optional configuration object
20531      * @returns {HttpPromise} Future object
20532      */
20533
20534     /**
20535      * @ngdoc method
20536      * @name $http#delete
20537      *
20538      * @description
20539      * Shortcut method to perform `DELETE` request.
20540      *
20541      * @param {string} url Relative or absolute URL specifying the destination of the request
20542      * @param {Object=} config Optional configuration object
20543      * @returns {HttpPromise} Future object
20544      */
20545
20546     /**
20547      * @ngdoc method
20548      * @name $http#head
20549      *
20550      * @description
20551      * Shortcut method to perform `HEAD` request.
20552      *
20553      * @param {string} url Relative or absolute URL specifying the destination of the request
20554      * @param {Object=} config Optional configuration object
20555      * @returns {HttpPromise} Future object
20556      */
20557
20558     /**
20559      * @ngdoc method
20560      * @name $http#jsonp
20561      *
20562      * @description
20563      * Shortcut method to perform `JSONP` request.
20564      *
20565      * @param {string} url Relative or absolute URL specifying the destination of the request.
20566      *                     The name of the callback should be the string `JSON_CALLBACK`.
20567      * @param {Object=} config Optional configuration object
20568      * @returns {HttpPromise} Future object
20569      */
20570     createShortMethods('get', 'delete', 'head', 'jsonp');
20571
20572     /**
20573      * @ngdoc method
20574      * @name $http#post
20575      *
20576      * @description
20577      * Shortcut method to perform `POST` request.
20578      *
20579      * @param {string} url Relative or absolute URL specifying the destination of the request
20580      * @param {*} data Request content
20581      * @param {Object=} config Optional configuration object
20582      * @returns {HttpPromise} Future object
20583      */
20584
20585     /**
20586      * @ngdoc method
20587      * @name $http#put
20588      *
20589      * @description
20590      * Shortcut method to perform `PUT` request.
20591      *
20592      * @param {string} url Relative or absolute URL specifying the destination of the request
20593      * @param {*} data Request content
20594      * @param {Object=} config Optional configuration object
20595      * @returns {HttpPromise} Future object
20596      */
20597
20598      /**
20599       * @ngdoc method
20600       * @name $http#patch
20601       *
20602       * @description
20603       * Shortcut method to perform `PATCH` request.
20604       *
20605       * @param {string} url Relative or absolute URL specifying the destination of the request
20606       * @param {*} data Request content
20607       * @param {Object=} config Optional configuration object
20608       * @returns {HttpPromise} Future object
20609       */
20610     createShortMethodsWithData('post', 'put', 'patch');
20611
20612         /**
20613          * @ngdoc property
20614          * @name $http#defaults
20615          *
20616          * @description
20617          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
20618          * default headers, withCredentials as well as request and response transformations.
20619          *
20620          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
20621          */
20622     $http.defaults = defaults;
20623
20624
20625     return $http;
20626
20627
20628     function createShortMethods(names) {
20629       forEach(arguments, function(name) {
20630         $http[name] = function(url, config) {
20631           return $http(extend({}, config || {}, {
20632             method: name,
20633             url: url
20634           }));
20635         };
20636       });
20637     }
20638
20639
20640     function createShortMethodsWithData(name) {
20641       forEach(arguments, function(name) {
20642         $http[name] = function(url, data, config) {
20643           return $http(extend({}, config || {}, {
20644             method: name,
20645             url: url,
20646             data: data
20647           }));
20648         };
20649       });
20650     }
20651
20652
20653     /**
20654      * Makes the request.
20655      *
20656      * !!! ACCESSES CLOSURE VARS:
20657      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
20658      */
20659     function sendReq(config, reqData) {
20660       var deferred = $q.defer(),
20661           promise = deferred.promise,
20662           cache,
20663           cachedResp,
20664           reqHeaders = config.headers,
20665           url = buildUrl(config.url, config.paramSerializer(config.params));
20666
20667       $http.pendingRequests.push(config);
20668       promise.then(removePendingReq, removePendingReq);
20669
20670
20671       if ((config.cache || defaults.cache) && config.cache !== false &&
20672           (config.method === 'GET' || config.method === 'JSONP')) {
20673         cache = isObject(config.cache) ? config.cache
20674               : isObject(defaults.cache) ? defaults.cache
20675               : defaultCache;
20676       }
20677
20678       if (cache) {
20679         cachedResp = cache.get(url);
20680         if (isDefined(cachedResp)) {
20681           if (isPromiseLike(cachedResp)) {
20682             // cached request has already been sent, but there is no response yet
20683             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
20684           } else {
20685             // serving from cache
20686             if (isArray(cachedResp)) {
20687               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
20688             } else {
20689               resolvePromise(cachedResp, 200, {}, 'OK');
20690             }
20691           }
20692         } else {
20693           // put the promise for the non-transformed response into cache as a placeholder
20694           cache.put(url, promise);
20695         }
20696       }
20697
20698
20699       // if we won't have the response in cache, set the xsrf headers and
20700       // send the request to the backend
20701       if (isUndefined(cachedResp)) {
20702         var xsrfValue = urlIsSameOrigin(config.url)
20703             ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
20704             : undefined;
20705         if (xsrfValue) {
20706           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
20707         }
20708
20709         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
20710             config.withCredentials, config.responseType,
20711             createApplyHandlers(config.eventHandlers),
20712             createApplyHandlers(config.uploadEventHandlers));
20713       }
20714
20715       return promise;
20716
20717       function createApplyHandlers(eventHandlers) {
20718         if (eventHandlers) {
20719           var applyHandlers = {};
20720           forEach(eventHandlers, function(eventHandler, key) {
20721             applyHandlers[key] = function(event) {
20722               if (useApplyAsync) {
20723                 $rootScope.$applyAsync(callEventHandler);
20724               } else if ($rootScope.$$phase) {
20725                 callEventHandler();
20726               } else {
20727                 $rootScope.$apply(callEventHandler);
20728               }
20729
20730               function callEventHandler() {
20731                 eventHandler(event);
20732               }
20733             };
20734           });
20735           return applyHandlers;
20736         }
20737       }
20738
20739
20740       /**
20741        * Callback registered to $httpBackend():
20742        *  - caches the response if desired
20743        *  - resolves the raw $http promise
20744        *  - calls $apply
20745        */
20746       function done(status, response, headersString, statusText) {
20747         if (cache) {
20748           if (isSuccess(status)) {
20749             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
20750           } else {
20751             // remove promise from the cache
20752             cache.remove(url);
20753           }
20754         }
20755
20756         function resolveHttpPromise() {
20757           resolvePromise(response, status, headersString, statusText);
20758         }
20759
20760         if (useApplyAsync) {
20761           $rootScope.$applyAsync(resolveHttpPromise);
20762         } else {
20763           resolveHttpPromise();
20764           if (!$rootScope.$$phase) $rootScope.$apply();
20765         }
20766       }
20767
20768
20769       /**
20770        * Resolves the raw $http promise.
20771        */
20772       function resolvePromise(response, status, headers, statusText) {
20773         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
20774         status = status >= -1 ? status : 0;
20775
20776         (isSuccess(status) ? deferred.resolve : deferred.reject)({
20777           data: response,
20778           status: status,
20779           headers: headersGetter(headers),
20780           config: config,
20781           statusText: statusText
20782         });
20783       }
20784
20785       function resolvePromiseWithResult(result) {
20786         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
20787       }
20788
20789       function removePendingReq() {
20790         var idx = $http.pendingRequests.indexOf(config);
20791         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
20792       }
20793     }
20794
20795
20796     function buildUrl(url, serializedParams) {
20797       if (serializedParams.length > 0) {
20798         url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
20799       }
20800       return url;
20801     }
20802   }];
20803 }
20804
20805 /**
20806  * @ngdoc service
20807  * @name $xhrFactory
20808  *
20809  * @description
20810  * Factory function used to create XMLHttpRequest objects.
20811  *
20812  * Replace or decorate this service to create your own custom XMLHttpRequest objects.
20813  *
20814  * ```
20815  * angular.module('myApp', [])
20816  * .factory('$xhrFactory', function() {
20817  *   return function createXhr(method, url) {
20818  *     return new window.XMLHttpRequest({mozSystem: true});
20819  *   };
20820  * });
20821  * ```
20822  *
20823  * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
20824  * @param {string} url URL of the request.
20825  */
20826 function $xhrFactoryProvider() {
20827   this.$get = function() {
20828     return function createXhr() {
20829       return new window.XMLHttpRequest();
20830     };
20831   };
20832 }
20833
20834 /**
20835  * @ngdoc service
20836  * @name $httpBackend
20837  * @requires $window
20838  * @requires $document
20839  * @requires $xhrFactory
20840  *
20841  * @description
20842  * HTTP backend used by the {@link ng.$http service} that delegates to
20843  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
20844  *
20845  * You should never need to use this service directly, instead use the higher-level abstractions:
20846  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
20847  *
20848  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
20849  * $httpBackend} which can be trained with responses.
20850  */
20851 function $HttpBackendProvider() {
20852   this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
20853     return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
20854   }];
20855 }
20856
20857 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
20858   // TODO(vojta): fix the signature
20859   return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
20860     $browser.$$incOutstandingRequestCount();
20861     url = url || $browser.url();
20862
20863     if (lowercase(method) == 'jsonp') {
20864       var callbackId = '_' + (callbacks.counter++).toString(36);
20865       callbacks[callbackId] = function(data) {
20866         callbacks[callbackId].data = data;
20867         callbacks[callbackId].called = true;
20868       };
20869
20870       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
20871           callbackId, function(status, text) {
20872         completeRequest(callback, status, callbacks[callbackId].data, "", text);
20873         callbacks[callbackId] = noop;
20874       });
20875     } else {
20876
20877       var xhr = createXhr(method, url);
20878
20879       xhr.open(method, url, true);
20880       forEach(headers, function(value, key) {
20881         if (isDefined(value)) {
20882             xhr.setRequestHeader(key, value);
20883         }
20884       });
20885
20886       xhr.onload = function requestLoaded() {
20887         var statusText = xhr.statusText || '';
20888
20889         // responseText is the old-school way of retrieving response (supported by IE9)
20890         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
20891         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
20892
20893         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
20894         var status = xhr.status === 1223 ? 204 : xhr.status;
20895
20896         // fix status code when it is 0 (0 status is undocumented).
20897         // Occurs when accessing file resources or on Android 4.1 stock browser
20898         // while retrieving files from application cache.
20899         if (status === 0) {
20900           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
20901         }
20902
20903         completeRequest(callback,
20904             status,
20905             response,
20906             xhr.getAllResponseHeaders(),
20907             statusText);
20908       };
20909
20910       var requestError = function() {
20911         // The response is always empty
20912         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
20913         completeRequest(callback, -1, null, null, '');
20914       };
20915
20916       xhr.onerror = requestError;
20917       xhr.onabort = requestError;
20918
20919       forEach(eventHandlers, function(value, key) {
20920           xhr.addEventListener(key, value);
20921       });
20922
20923       forEach(uploadEventHandlers, function(value, key) {
20924         xhr.upload.addEventListener(key, value);
20925       });
20926
20927       if (withCredentials) {
20928         xhr.withCredentials = true;
20929       }
20930
20931       if (responseType) {
20932         try {
20933           xhr.responseType = responseType;
20934         } catch (e) {
20935           // WebKit added support for the json responseType value on 09/03/2013
20936           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
20937           // known to throw when setting the value "json" as the response type. Other older
20938           // browsers implementing the responseType
20939           //
20940           // The json response type can be ignored if not supported, because JSON payloads are
20941           // parsed on the client-side regardless.
20942           if (responseType !== 'json') {
20943             throw e;
20944           }
20945         }
20946       }
20947
20948       xhr.send(isUndefined(post) ? null : post);
20949     }
20950
20951     if (timeout > 0) {
20952       var timeoutId = $browserDefer(timeoutRequest, timeout);
20953     } else if (isPromiseLike(timeout)) {
20954       timeout.then(timeoutRequest);
20955     }
20956
20957
20958     function timeoutRequest() {
20959       jsonpDone && jsonpDone();
20960       xhr && xhr.abort();
20961     }
20962
20963     function completeRequest(callback, status, response, headersString, statusText) {
20964       // cancel timeout and subsequent timeout promise resolution
20965       if (isDefined(timeoutId)) {
20966         $browserDefer.cancel(timeoutId);
20967       }
20968       jsonpDone = xhr = null;
20969
20970       callback(status, response, headersString, statusText);
20971       $browser.$$completeOutstandingRequest(noop);
20972     }
20973   };
20974
20975   function jsonpReq(url, callbackId, done) {
20976     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
20977     // - fetches local scripts via XHR and evals them
20978     // - adds and immediately removes script elements from the document
20979     var script = rawDocument.createElement('script'), callback = null;
20980     script.type = "text/javascript";
20981     script.src = url;
20982     script.async = true;
20983
20984     callback = function(event) {
20985       removeEventListenerFn(script, "load", callback);
20986       removeEventListenerFn(script, "error", callback);
20987       rawDocument.body.removeChild(script);
20988       script = null;
20989       var status = -1;
20990       var text = "unknown";
20991
20992       if (event) {
20993         if (event.type === "load" && !callbacks[callbackId].called) {
20994           event = { type: "error" };
20995         }
20996         text = event.type;
20997         status = event.type === "error" ? 404 : 200;
20998       }
20999
21000       if (done) {
21001         done(status, text);
21002       }
21003     };
21004
21005     addEventListenerFn(script, "load", callback);
21006     addEventListenerFn(script, "error", callback);
21007     rawDocument.body.appendChild(script);
21008     return callback;
21009   }
21010 }
21011
21012 var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
21013 $interpolateMinErr.throwNoconcat = function(text) {
21014   throw $interpolateMinErr('noconcat',
21015       "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
21016       "interpolations that concatenate multiple expressions when a trusted value is " +
21017       "required.  See http://docs.angularjs.org/api/ng.$sce", text);
21018 };
21019
21020 $interpolateMinErr.interr = function(text, err) {
21021   return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
21022 };
21023
21024 /**
21025  * @ngdoc provider
21026  * @name $interpolateProvider
21027  *
21028  * @description
21029  *
21030  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
21031  *
21032  * <div class="alert alert-danger">
21033  * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
21034  * template within a Python Jinja template (or any other template language). Mixing templating
21035  * languages is **very dangerous**. The embedding template language will not safely escape Angular
21036  * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
21037  * security bugs!
21038  * </div>
21039  *
21040  * @example
21041 <example name="custom-interpolation-markup" module="customInterpolationApp">
21042 <file name="index.html">
21043 <script>
21044   var customInterpolationApp = angular.module('customInterpolationApp', []);
21045
21046   customInterpolationApp.config(function($interpolateProvider) {
21047     $interpolateProvider.startSymbol('//');
21048     $interpolateProvider.endSymbol('//');
21049   });
21050
21051
21052   customInterpolationApp.controller('DemoController', function() {
21053       this.label = "This binding is brought you by // interpolation symbols.";
21054   });
21055 </script>
21056 <div ng-controller="DemoController as demo">
21057     //demo.label//
21058 </div>
21059 </file>
21060 <file name="protractor.js" type="protractor">
21061   it('should interpolate binding with custom symbols', function() {
21062     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
21063   });
21064 </file>
21065 </example>
21066  */
21067 function $InterpolateProvider() {
21068   var startSymbol = '{{';
21069   var endSymbol = '}}';
21070
21071   /**
21072    * @ngdoc method
21073    * @name $interpolateProvider#startSymbol
21074    * @description
21075    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
21076    *
21077    * @param {string=} value new value to set the starting symbol to.
21078    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
21079    */
21080   this.startSymbol = function(value) {
21081     if (value) {
21082       startSymbol = value;
21083       return this;
21084     } else {
21085       return startSymbol;
21086     }
21087   };
21088
21089   /**
21090    * @ngdoc method
21091    * @name $interpolateProvider#endSymbol
21092    * @description
21093    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
21094    *
21095    * @param {string=} value new value to set the ending symbol to.
21096    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
21097    */
21098   this.endSymbol = function(value) {
21099     if (value) {
21100       endSymbol = value;
21101       return this;
21102     } else {
21103       return endSymbol;
21104     }
21105   };
21106
21107
21108   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
21109     var startSymbolLength = startSymbol.length,
21110         endSymbolLength = endSymbol.length,
21111         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
21112         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
21113
21114     function escape(ch) {
21115       return '\\\\\\' + ch;
21116     }
21117
21118     function unescapeText(text) {
21119       return text.replace(escapedStartRegexp, startSymbol).
21120         replace(escapedEndRegexp, endSymbol);
21121     }
21122
21123     function stringify(value) {
21124       if (value == null) { // null || undefined
21125         return '';
21126       }
21127       switch (typeof value) {
21128         case 'string':
21129           break;
21130         case 'number':
21131           value = '' + value;
21132           break;
21133         default:
21134           value = toJson(value);
21135       }
21136
21137       return value;
21138     }
21139
21140     //TODO: this is the same as the constantWatchDelegate in parse.js
21141     function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
21142       var unwatch;
21143       return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
21144         unwatch();
21145         return constantInterp(scope);
21146       }, listener, objectEquality);
21147     }
21148
21149     /**
21150      * @ngdoc service
21151      * @name $interpolate
21152      * @kind function
21153      *
21154      * @requires $parse
21155      * @requires $sce
21156      *
21157      * @description
21158      *
21159      * Compiles a string with markup into an interpolation function. This service is used by the
21160      * HTML {@link ng.$compile $compile} service for data binding. See
21161      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
21162      * interpolation markup.
21163      *
21164      *
21165      * ```js
21166      *   var $interpolate = ...; // injected
21167      *   var exp = $interpolate('Hello {{name | uppercase}}!');
21168      *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
21169      * ```
21170      *
21171      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
21172      * `true`, the interpolation function will return `undefined` unless all embedded expressions
21173      * evaluate to a value other than `undefined`.
21174      *
21175      * ```js
21176      *   var $interpolate = ...; // injected
21177      *   var context = {greeting: 'Hello', name: undefined };
21178      *
21179      *   // default "forgiving" mode
21180      *   var exp = $interpolate('{{greeting}} {{name}}!');
21181      *   expect(exp(context)).toEqual('Hello !');
21182      *
21183      *   // "allOrNothing" mode
21184      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
21185      *   expect(exp(context)).toBeUndefined();
21186      *   context.name = 'Angular';
21187      *   expect(exp(context)).toEqual('Hello Angular!');
21188      * ```
21189      *
21190      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
21191      *
21192      * ####Escaped Interpolation
21193      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
21194      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
21195      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
21196      * or binding.
21197      *
21198      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
21199      * degree, while also enabling code examples to work without relying on the
21200      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
21201      *
21202      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
21203      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
21204      * interpolation start/end markers with their escaped counterparts.**
21205      *
21206      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
21207      * output when the $interpolate service processes the text. So, for HTML elements interpolated
21208      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
21209      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
21210      * this is typically useful only when user-data is used in rendering a template from the server, or
21211      * when otherwise untrusted data is used by a directive.
21212      *
21213      * <example>
21214      *  <file name="index.html">
21215      *    <div ng-init="username='A user'">
21216      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
21217      *        </p>
21218      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
21219      *        application, but fails to accomplish their task, because the server has correctly
21220      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
21221      *        characters.</p>
21222      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
21223      *        from the database by an administrator.</p>
21224      *    </div>
21225      *  </file>
21226      * </example>
21227      *
21228      * @param {string} text The text with markup to interpolate.
21229      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
21230      *    embedded expression in order to return an interpolation function. Strings with no
21231      *    embedded expression will return null for the interpolation function.
21232      * @param {string=} trustedContext when provided, the returned function passes the interpolated
21233      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
21234      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
21235      *    provides Strict Contextual Escaping for details.
21236      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
21237      *    unless all embedded expressions evaluate to a value other than `undefined`.
21238      * @returns {function(context)} an interpolation function which is used to compute the
21239      *    interpolated string. The function has these parameters:
21240      *
21241      * - `context`: evaluation context for all expressions embedded in the interpolated text
21242      */
21243     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
21244       // Provide a quick exit and simplified result function for text with no interpolation
21245       if (!text.length || text.indexOf(startSymbol) === -1) {
21246         var constantInterp;
21247         if (!mustHaveExpression) {
21248           var unescapedText = unescapeText(text);
21249           constantInterp = valueFn(unescapedText);
21250           constantInterp.exp = text;
21251           constantInterp.expressions = [];
21252           constantInterp.$$watchDelegate = constantWatchDelegate;
21253         }
21254         return constantInterp;
21255       }
21256
21257       allOrNothing = !!allOrNothing;
21258       var startIndex,
21259           endIndex,
21260           index = 0,
21261           expressions = [],
21262           parseFns = [],
21263           textLength = text.length,
21264           exp,
21265           concat = [],
21266           expressionPositions = [];
21267
21268       while (index < textLength) {
21269         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
21270              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
21271           if (index !== startIndex) {
21272             concat.push(unescapeText(text.substring(index, startIndex)));
21273           }
21274           exp = text.substring(startIndex + startSymbolLength, endIndex);
21275           expressions.push(exp);
21276           parseFns.push($parse(exp, parseStringifyInterceptor));
21277           index = endIndex + endSymbolLength;
21278           expressionPositions.push(concat.length);
21279           concat.push('');
21280         } else {
21281           // we did not find an interpolation, so we have to add the remainder to the separators array
21282           if (index !== textLength) {
21283             concat.push(unescapeText(text.substring(index)));
21284           }
21285           break;
21286         }
21287       }
21288
21289       // Concatenating expressions makes it hard to reason about whether some combination of
21290       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
21291       // single expression be used for iframe[src], object[src], etc., we ensure that the value
21292       // that's used is assigned or constructed by some JS code somewhere that is more testable or
21293       // make it obvious that you bound the value to some user controlled value.  This helps reduce
21294       // the load when auditing for XSS issues.
21295       if (trustedContext && concat.length > 1) {
21296           $interpolateMinErr.throwNoconcat(text);
21297       }
21298
21299       if (!mustHaveExpression || expressions.length) {
21300         var compute = function(values) {
21301           for (var i = 0, ii = expressions.length; i < ii; i++) {
21302             if (allOrNothing && isUndefined(values[i])) return;
21303             concat[expressionPositions[i]] = values[i];
21304           }
21305           return concat.join('');
21306         };
21307
21308         var getValue = function(value) {
21309           return trustedContext ?
21310             $sce.getTrusted(trustedContext, value) :
21311             $sce.valueOf(value);
21312         };
21313
21314         return extend(function interpolationFn(context) {
21315             var i = 0;
21316             var ii = expressions.length;
21317             var values = new Array(ii);
21318
21319             try {
21320               for (; i < ii; i++) {
21321                 values[i] = parseFns[i](context);
21322               }
21323
21324               return compute(values);
21325             } catch (err) {
21326               $exceptionHandler($interpolateMinErr.interr(text, err));
21327             }
21328
21329           }, {
21330           // all of these properties are undocumented for now
21331           exp: text, //just for compatibility with regular watchers created via $watch
21332           expressions: expressions,
21333           $$watchDelegate: function(scope, listener) {
21334             var lastValue;
21335             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
21336               var currValue = compute(values);
21337               if (isFunction(listener)) {
21338                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
21339               }
21340               lastValue = currValue;
21341             });
21342           }
21343         });
21344       }
21345
21346       function parseStringifyInterceptor(value) {
21347         try {
21348           value = getValue(value);
21349           return allOrNothing && !isDefined(value) ? value : stringify(value);
21350         } catch (err) {
21351           $exceptionHandler($interpolateMinErr.interr(text, err));
21352         }
21353       }
21354     }
21355
21356
21357     /**
21358      * @ngdoc method
21359      * @name $interpolate#startSymbol
21360      * @description
21361      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
21362      *
21363      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
21364      * the symbol.
21365      *
21366      * @returns {string} start symbol.
21367      */
21368     $interpolate.startSymbol = function() {
21369       return startSymbol;
21370     };
21371
21372
21373     /**
21374      * @ngdoc method
21375      * @name $interpolate#endSymbol
21376      * @description
21377      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
21378      *
21379      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
21380      * the symbol.
21381      *
21382      * @returns {string} end symbol.
21383      */
21384     $interpolate.endSymbol = function() {
21385       return endSymbol;
21386     };
21387
21388     return $interpolate;
21389   }];
21390 }
21391
21392 function $IntervalProvider() {
21393   this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
21394        function($rootScope,   $window,   $q,   $$q,   $browser) {
21395     var intervals = {};
21396
21397
21398      /**
21399       * @ngdoc service
21400       * @name $interval
21401       *
21402       * @description
21403       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
21404       * milliseconds.
21405       *
21406       * The return value of registering an interval function is a promise. This promise will be
21407       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
21408       * run indefinitely if `count` is not defined. The value of the notification will be the
21409       * number of iterations that have run.
21410       * To cancel an interval, call `$interval.cancel(promise)`.
21411       *
21412       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
21413       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
21414       * time.
21415       *
21416       * <div class="alert alert-warning">
21417       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
21418       * with them.  In particular they are not automatically destroyed when a controller's scope or a
21419       * directive's element are destroyed.
21420       * You should take this into consideration and make sure to always cancel the interval at the
21421       * appropriate moment.  See the example below for more details on how and when to do this.
21422       * </div>
21423       *
21424       * @param {function()} fn A function that should be called repeatedly.
21425       * @param {number} delay Number of milliseconds between each function call.
21426       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
21427       *   indefinitely.
21428       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
21429       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
21430       * @param {...*=} Pass additional parameters to the executed function.
21431       * @returns {promise} A promise which will be notified on each iteration.
21432       *
21433       * @example
21434       * <example module="intervalExample">
21435       * <file name="index.html">
21436       *   <script>
21437       *     angular.module('intervalExample', [])
21438       *       .controller('ExampleController', ['$scope', '$interval',
21439       *         function($scope, $interval) {
21440       *           $scope.format = 'M/d/yy h:mm:ss a';
21441       *           $scope.blood_1 = 100;
21442       *           $scope.blood_2 = 120;
21443       *
21444       *           var stop;
21445       *           $scope.fight = function() {
21446       *             // Don't start a new fight if we are already fighting
21447       *             if ( angular.isDefined(stop) ) return;
21448       *
21449       *             stop = $interval(function() {
21450       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
21451       *                 $scope.blood_1 = $scope.blood_1 - 3;
21452       *                 $scope.blood_2 = $scope.blood_2 - 4;
21453       *               } else {
21454       *                 $scope.stopFight();
21455       *               }
21456       *             }, 100);
21457       *           };
21458       *
21459       *           $scope.stopFight = function() {
21460       *             if (angular.isDefined(stop)) {
21461       *               $interval.cancel(stop);
21462       *               stop = undefined;
21463       *             }
21464       *           };
21465       *
21466       *           $scope.resetFight = function() {
21467       *             $scope.blood_1 = 100;
21468       *             $scope.blood_2 = 120;
21469       *           };
21470       *
21471       *           $scope.$on('$destroy', function() {
21472       *             // Make sure that the interval is destroyed too
21473       *             $scope.stopFight();
21474       *           });
21475       *         }])
21476       *       // Register the 'myCurrentTime' directive factory method.
21477       *       // We inject $interval and dateFilter service since the factory method is DI.
21478       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
21479       *         function($interval, dateFilter) {
21480       *           // return the directive link function. (compile function not needed)
21481       *           return function(scope, element, attrs) {
21482       *             var format,  // date format
21483       *                 stopTime; // so that we can cancel the time updates
21484       *
21485       *             // used to update the UI
21486       *             function updateTime() {
21487       *               element.text(dateFilter(new Date(), format));
21488       *             }
21489       *
21490       *             // watch the expression, and update the UI on change.
21491       *             scope.$watch(attrs.myCurrentTime, function(value) {
21492       *               format = value;
21493       *               updateTime();
21494       *             });
21495       *
21496       *             stopTime = $interval(updateTime, 1000);
21497       *
21498       *             // listen on DOM destroy (removal) event, and cancel the next UI update
21499       *             // to prevent updating time after the DOM element was removed.
21500       *             element.on('$destroy', function() {
21501       *               $interval.cancel(stopTime);
21502       *             });
21503       *           }
21504       *         }]);
21505       *   </script>
21506       *
21507       *   <div>
21508       *     <div ng-controller="ExampleController">
21509       *       <label>Date format: <input ng-model="format"></label> <hr/>
21510       *       Current time is: <span my-current-time="format"></span>
21511       *       <hr/>
21512       *       Blood 1 : <font color='red'>{{blood_1}}</font>
21513       *       Blood 2 : <font color='red'>{{blood_2}}</font>
21514       *       <button type="button" data-ng-click="fight()">Fight</button>
21515       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
21516       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
21517       *     </div>
21518       *   </div>
21519       *
21520       * </file>
21521       * </example>
21522       */
21523     function interval(fn, delay, count, invokeApply) {
21524       var hasParams = arguments.length > 4,
21525           args = hasParams ? sliceArgs(arguments, 4) : [],
21526           setInterval = $window.setInterval,
21527           clearInterval = $window.clearInterval,
21528           iteration = 0,
21529           skipApply = (isDefined(invokeApply) && !invokeApply),
21530           deferred = (skipApply ? $$q : $q).defer(),
21531           promise = deferred.promise;
21532
21533       count = isDefined(count) ? count : 0;
21534
21535       promise.$$intervalId = setInterval(function tick() {
21536         if (skipApply) {
21537           $browser.defer(callback);
21538         } else {
21539           $rootScope.$evalAsync(callback);
21540         }
21541         deferred.notify(iteration++);
21542
21543         if (count > 0 && iteration >= count) {
21544           deferred.resolve(iteration);
21545           clearInterval(promise.$$intervalId);
21546           delete intervals[promise.$$intervalId];
21547         }
21548
21549         if (!skipApply) $rootScope.$apply();
21550
21551       }, delay);
21552
21553       intervals[promise.$$intervalId] = deferred;
21554
21555       return promise;
21556
21557       function callback() {
21558         if (!hasParams) {
21559           fn(iteration);
21560         } else {
21561           fn.apply(null, args);
21562         }
21563       }
21564     }
21565
21566
21567      /**
21568       * @ngdoc method
21569       * @name $interval#cancel
21570       *
21571       * @description
21572       * Cancels a task associated with the `promise`.
21573       *
21574       * @param {Promise=} promise returned by the `$interval` function.
21575       * @returns {boolean} Returns `true` if the task was successfully canceled.
21576       */
21577     interval.cancel = function(promise) {
21578       if (promise && promise.$$intervalId in intervals) {
21579         intervals[promise.$$intervalId].reject('canceled');
21580         $window.clearInterval(promise.$$intervalId);
21581         delete intervals[promise.$$intervalId];
21582         return true;
21583       }
21584       return false;
21585     };
21586
21587     return interval;
21588   }];
21589 }
21590
21591 /**
21592  * @ngdoc service
21593  * @name $locale
21594  *
21595  * @description
21596  * $locale service provides localization rules for various Angular components. As of right now the
21597  * only public api is:
21598  *
21599  * * `id` â€“ `{string}` â€“ locale id formatted as `languageId-countryId` (e.g. `en-us`)
21600  */
21601
21602 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
21603     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
21604 var $locationMinErr = minErr('$location');
21605
21606
21607 /**
21608  * Encode path using encodeUriSegment, ignoring forward slashes
21609  *
21610  * @param {string} path Path to encode
21611  * @returns {string}
21612  */
21613 function encodePath(path) {
21614   var segments = path.split('/'),
21615       i = segments.length;
21616
21617   while (i--) {
21618     segments[i] = encodeUriSegment(segments[i]);
21619   }
21620
21621   return segments.join('/');
21622 }
21623
21624 function parseAbsoluteUrl(absoluteUrl, locationObj) {
21625   var parsedUrl = urlResolve(absoluteUrl);
21626
21627   locationObj.$$protocol = parsedUrl.protocol;
21628   locationObj.$$host = parsedUrl.hostname;
21629   locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
21630 }
21631
21632
21633 function parseAppUrl(relativeUrl, locationObj) {
21634   var prefixed = (relativeUrl.charAt(0) !== '/');
21635   if (prefixed) {
21636     relativeUrl = '/' + relativeUrl;
21637   }
21638   var match = urlResolve(relativeUrl);
21639   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
21640       match.pathname.substring(1) : match.pathname);
21641   locationObj.$$search = parseKeyValue(match.search);
21642   locationObj.$$hash = decodeURIComponent(match.hash);
21643
21644   // make sure path starts with '/';
21645   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
21646     locationObj.$$path = '/' + locationObj.$$path;
21647   }
21648 }
21649
21650
21651 /**
21652  *
21653  * @param {string} begin
21654  * @param {string} whole
21655  * @returns {string} returns text from whole after begin or undefined if it does not begin with
21656  *                   expected string.
21657  */
21658 function beginsWith(begin, whole) {
21659   if (whole.indexOf(begin) === 0) {
21660     return whole.substr(begin.length);
21661   }
21662 }
21663
21664
21665 function stripHash(url) {
21666   var index = url.indexOf('#');
21667   return index == -1 ? url : url.substr(0, index);
21668 }
21669
21670 function trimEmptyHash(url) {
21671   return url.replace(/(#.+)|#$/, '$1');
21672 }
21673
21674
21675 function stripFile(url) {
21676   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
21677 }
21678
21679 /* return the server only (scheme://host:port) */
21680 function serverBase(url) {
21681   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
21682 }
21683
21684
21685 /**
21686  * LocationHtml5Url represents an url
21687  * This object is exposed as $location service when HTML5 mode is enabled and supported
21688  *
21689  * @constructor
21690  * @param {string} appBase application base URL
21691  * @param {string} appBaseNoFile application base URL stripped of any filename
21692  * @param {string} basePrefix url path prefix
21693  */
21694 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
21695   this.$$html5 = true;
21696   basePrefix = basePrefix || '';
21697   parseAbsoluteUrl(appBase, this);
21698
21699
21700   /**
21701    * Parse given html5 (regular) url string into properties
21702    * @param {string} url HTML5 url
21703    * @private
21704    */
21705   this.$$parse = function(url) {
21706     var pathUrl = beginsWith(appBaseNoFile, url);
21707     if (!isString(pathUrl)) {
21708       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
21709           appBaseNoFile);
21710     }
21711
21712     parseAppUrl(pathUrl, this);
21713
21714     if (!this.$$path) {
21715       this.$$path = '/';
21716     }
21717
21718     this.$$compose();
21719   };
21720
21721   /**
21722    * Compose url and update `absUrl` property
21723    * @private
21724    */
21725   this.$$compose = function() {
21726     var search = toKeyValue(this.$$search),
21727         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21728
21729     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21730     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
21731   };
21732
21733   this.$$parseLinkUrl = function(url, relHref) {
21734     if (relHref && relHref[0] === '#') {
21735       // special case for links to hash fragments:
21736       // keep the old url and only replace the hash fragment
21737       this.hash(relHref.slice(1));
21738       return true;
21739     }
21740     var appUrl, prevAppUrl;
21741     var rewrittenUrl;
21742
21743     if (isDefined(appUrl = beginsWith(appBase, url))) {
21744       prevAppUrl = appUrl;
21745       if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
21746         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
21747       } else {
21748         rewrittenUrl = appBase + prevAppUrl;
21749       }
21750     } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
21751       rewrittenUrl = appBaseNoFile + appUrl;
21752     } else if (appBaseNoFile == url + '/') {
21753       rewrittenUrl = appBaseNoFile;
21754     }
21755     if (rewrittenUrl) {
21756       this.$$parse(rewrittenUrl);
21757     }
21758     return !!rewrittenUrl;
21759   };
21760 }
21761
21762
21763 /**
21764  * LocationHashbangUrl represents url
21765  * This object is exposed as $location service when developer doesn't opt into html5 mode.
21766  * It also serves as the base class for html5 mode fallback on legacy browsers.
21767  *
21768  * @constructor
21769  * @param {string} appBase application base URL
21770  * @param {string} appBaseNoFile application base URL stripped of any filename
21771  * @param {string} hashPrefix hashbang prefix
21772  */
21773 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
21774
21775   parseAbsoluteUrl(appBase, this);
21776
21777
21778   /**
21779    * Parse given hashbang url into properties
21780    * @param {string} url Hashbang url
21781    * @private
21782    */
21783   this.$$parse = function(url) {
21784     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
21785     var withoutHashUrl;
21786
21787     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
21788
21789       // The rest of the url starts with a hash so we have
21790       // got either a hashbang path or a plain hash fragment
21791       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
21792       if (isUndefined(withoutHashUrl)) {
21793         // There was no hashbang prefix so we just have a hash fragment
21794         withoutHashUrl = withoutBaseUrl;
21795       }
21796
21797     } else {
21798       // There was no hashbang path nor hash fragment:
21799       // If we are in HTML5 mode we use what is left as the path;
21800       // Otherwise we ignore what is left
21801       if (this.$$html5) {
21802         withoutHashUrl = withoutBaseUrl;
21803       } else {
21804         withoutHashUrl = '';
21805         if (isUndefined(withoutBaseUrl)) {
21806           appBase = url;
21807           this.replace();
21808         }
21809       }
21810     }
21811
21812     parseAppUrl(withoutHashUrl, this);
21813
21814     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
21815
21816     this.$$compose();
21817
21818     /*
21819      * In Windows, on an anchor node on documents loaded from
21820      * the filesystem, the browser will return a pathname
21821      * prefixed with the drive name ('/C:/path') when a
21822      * pathname without a drive is set:
21823      *  * a.setAttribute('href', '/foo')
21824      *   * a.pathname === '/C:/foo' //true
21825      *
21826      * Inside of Angular, we're always using pathnames that
21827      * do not include drive names for routing.
21828      */
21829     function removeWindowsDriveName(path, url, base) {
21830       /*
21831       Matches paths for file protocol on windows,
21832       such as /C:/foo/bar, and captures only /foo/bar.
21833       */
21834       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
21835
21836       var firstPathSegmentMatch;
21837
21838       //Get the relative path from the input URL.
21839       if (url.indexOf(base) === 0) {
21840         url = url.replace(base, '');
21841       }
21842
21843       // The input URL intentionally contains a first path segment that ends with a colon.
21844       if (windowsFilePathExp.exec(url)) {
21845         return path;
21846       }
21847
21848       firstPathSegmentMatch = windowsFilePathExp.exec(path);
21849       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
21850     }
21851   };
21852
21853   /**
21854    * Compose hashbang url and update `absUrl` property
21855    * @private
21856    */
21857   this.$$compose = function() {
21858     var search = toKeyValue(this.$$search),
21859         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21860
21861     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21862     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
21863   };
21864
21865   this.$$parseLinkUrl = function(url, relHref) {
21866     if (stripHash(appBase) == stripHash(url)) {
21867       this.$$parse(url);
21868       return true;
21869     }
21870     return false;
21871   };
21872 }
21873
21874
21875 /**
21876  * LocationHashbangUrl represents url
21877  * This object is exposed as $location service when html5 history api is enabled but the browser
21878  * does not support it.
21879  *
21880  * @constructor
21881  * @param {string} appBase application base URL
21882  * @param {string} appBaseNoFile application base URL stripped of any filename
21883  * @param {string} hashPrefix hashbang prefix
21884  */
21885 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
21886   this.$$html5 = true;
21887   LocationHashbangUrl.apply(this, arguments);
21888
21889   this.$$parseLinkUrl = function(url, relHref) {
21890     if (relHref && relHref[0] === '#') {
21891       // special case for links to hash fragments:
21892       // keep the old url and only replace the hash fragment
21893       this.hash(relHref.slice(1));
21894       return true;
21895     }
21896
21897     var rewrittenUrl;
21898     var appUrl;
21899
21900     if (appBase == stripHash(url)) {
21901       rewrittenUrl = url;
21902     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
21903       rewrittenUrl = appBase + hashPrefix + appUrl;
21904     } else if (appBaseNoFile === url + '/') {
21905       rewrittenUrl = appBaseNoFile;
21906     }
21907     if (rewrittenUrl) {
21908       this.$$parse(rewrittenUrl);
21909     }
21910     return !!rewrittenUrl;
21911   };
21912
21913   this.$$compose = function() {
21914     var search = toKeyValue(this.$$search),
21915         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21916
21917     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21918     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
21919     this.$$absUrl = appBase + hashPrefix + this.$$url;
21920   };
21921
21922 }
21923
21924
21925 var locationPrototype = {
21926
21927   /**
21928    * Are we in html5 mode?
21929    * @private
21930    */
21931   $$html5: false,
21932
21933   /**
21934    * Has any change been replacing?
21935    * @private
21936    */
21937   $$replace: false,
21938
21939   /**
21940    * @ngdoc method
21941    * @name $location#absUrl
21942    *
21943    * @description
21944    * This method is getter only.
21945    *
21946    * Return full url representation with all segments encoded according to rules specified in
21947    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
21948    *
21949    *
21950    * ```js
21951    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21952    * var absUrl = $location.absUrl();
21953    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
21954    * ```
21955    *
21956    * @return {string} full url
21957    */
21958   absUrl: locationGetter('$$absUrl'),
21959
21960   /**
21961    * @ngdoc method
21962    * @name $location#url
21963    *
21964    * @description
21965    * This method is getter / setter.
21966    *
21967    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
21968    *
21969    * Change path, search and hash, when called with parameter and return `$location`.
21970    *
21971    *
21972    * ```js
21973    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21974    * var url = $location.url();
21975    * // => "/some/path?foo=bar&baz=xoxo"
21976    * ```
21977    *
21978    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
21979    * @return {string} url
21980    */
21981   url: function(url) {
21982     if (isUndefined(url)) {
21983       return this.$$url;
21984     }
21985
21986     var match = PATH_MATCH.exec(url);
21987     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
21988     if (match[2] || match[1] || url === '') this.search(match[3] || '');
21989     this.hash(match[5] || '');
21990
21991     return this;
21992   },
21993
21994   /**
21995    * @ngdoc method
21996    * @name $location#protocol
21997    *
21998    * @description
21999    * This method is getter only.
22000    *
22001    * Return protocol of current url.
22002    *
22003    *
22004    * ```js
22005    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
22006    * var protocol = $location.protocol();
22007    * // => "http"
22008    * ```
22009    *
22010    * @return {string} protocol of current url
22011    */
22012   protocol: locationGetter('$$protocol'),
22013
22014   /**
22015    * @ngdoc method
22016    * @name $location#host
22017    *
22018    * @description
22019    * This method is getter only.
22020    *
22021    * Return host of current url.
22022    *
22023    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
22024    *
22025    *
22026    * ```js
22027    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
22028    * var host = $location.host();
22029    * // => "example.com"
22030    *
22031    * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
22032    * host = $location.host();
22033    * // => "example.com"
22034    * host = location.host;
22035    * // => "example.com:8080"
22036    * ```
22037    *
22038    * @return {string} host of current url.
22039    */
22040   host: locationGetter('$$host'),
22041
22042   /**
22043    * @ngdoc method
22044    * @name $location#port
22045    *
22046    * @description
22047    * This method is getter only.
22048    *
22049    * Return port of current url.
22050    *
22051    *
22052    * ```js
22053    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
22054    * var port = $location.port();
22055    * // => 80
22056    * ```
22057    *
22058    * @return {Number} port
22059    */
22060   port: locationGetter('$$port'),
22061
22062   /**
22063    * @ngdoc method
22064    * @name $location#path
22065    *
22066    * @description
22067    * This method is getter / setter.
22068    *
22069    * Return path of current url when called without any parameter.
22070    *
22071    * Change path when called with parameter and return `$location`.
22072    *
22073    * Note: Path should always begin with forward slash (/), this method will add the forward slash
22074    * if it is missing.
22075    *
22076    *
22077    * ```js
22078    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
22079    * var path = $location.path();
22080    * // => "/some/path"
22081    * ```
22082    *
22083    * @param {(string|number)=} path New path
22084    * @return {string} path
22085    */
22086   path: locationGetterSetter('$$path', function(path) {
22087     path = path !== null ? path.toString() : '';
22088     return path.charAt(0) == '/' ? path : '/' + path;
22089   }),
22090
22091   /**
22092    * @ngdoc method
22093    * @name $location#search
22094    *
22095    * @description
22096    * This method is getter / setter.
22097    *
22098    * Return search part (as object) of current url when called without any parameter.
22099    *
22100    * Change search part when called with parameter and return `$location`.
22101    *
22102    *
22103    * ```js
22104    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
22105    * var searchObject = $location.search();
22106    * // => {foo: 'bar', baz: 'xoxo'}
22107    *
22108    * // set foo to 'yipee'
22109    * $location.search('foo', 'yipee');
22110    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
22111    * ```
22112    *
22113    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
22114    * hash object.
22115    *
22116    * When called with a single argument the method acts as a setter, setting the `search` component
22117    * of `$location` to the specified value.
22118    *
22119    * If the argument is a hash object containing an array of values, these values will be encoded
22120    * as duplicate search parameters in the url.
22121    *
22122    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
22123    * will override only a single search property.
22124    *
22125    * If `paramValue` is an array, it will override the property of the `search` component of
22126    * `$location` specified via the first argument.
22127    *
22128    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
22129    *
22130    * If `paramValue` is `true`, the property specified via the first argument will be added with no
22131    * value nor trailing equal sign.
22132    *
22133    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
22134    * one or more arguments returns `$location` object itself.
22135    */
22136   search: function(search, paramValue) {
22137     switch (arguments.length) {
22138       case 0:
22139         return this.$$search;
22140       case 1:
22141         if (isString(search) || isNumber(search)) {
22142           search = search.toString();
22143           this.$$search = parseKeyValue(search);
22144         } else if (isObject(search)) {
22145           search = copy(search, {});
22146           // remove object undefined or null properties
22147           forEach(search, function(value, key) {
22148             if (value == null) delete search[key];
22149           });
22150
22151           this.$$search = search;
22152         } else {
22153           throw $locationMinErr('isrcharg',
22154               'The first argument of the `$location#search()` call must be a string or an object.');
22155         }
22156         break;
22157       default:
22158         if (isUndefined(paramValue) || paramValue === null) {
22159           delete this.$$search[search];
22160         } else {
22161           this.$$search[search] = paramValue;
22162         }
22163     }
22164
22165     this.$$compose();
22166     return this;
22167   },
22168
22169   /**
22170    * @ngdoc method
22171    * @name $location#hash
22172    *
22173    * @description
22174    * This method is getter / setter.
22175    *
22176    * Returns the hash fragment when called without any parameters.
22177    *
22178    * Changes the hash fragment when called with a parameter and returns `$location`.
22179    *
22180    *
22181    * ```js
22182    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
22183    * var hash = $location.hash();
22184    * // => "hashValue"
22185    * ```
22186    *
22187    * @param {(string|number)=} hash New hash fragment
22188    * @return {string} hash
22189    */
22190   hash: locationGetterSetter('$$hash', function(hash) {
22191     return hash !== null ? hash.toString() : '';
22192   }),
22193
22194   /**
22195    * @ngdoc method
22196    * @name $location#replace
22197    *
22198    * @description
22199    * If called, all changes to $location during the current `$digest` will replace the current history
22200    * record, instead of adding a new one.
22201    */
22202   replace: function() {
22203     this.$$replace = true;
22204     return this;
22205   }
22206 };
22207
22208 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
22209   Location.prototype = Object.create(locationPrototype);
22210
22211   /**
22212    * @ngdoc method
22213    * @name $location#state
22214    *
22215    * @description
22216    * This method is getter / setter.
22217    *
22218    * Return the history state object when called without any parameter.
22219    *
22220    * Change the history state object when called with one parameter and return `$location`.
22221    * The state object is later passed to `pushState` or `replaceState`.
22222    *
22223    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
22224    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
22225    * older browsers (like IE9 or Android < 4.0), don't use this method.
22226    *
22227    * @param {object=} state State object for pushState or replaceState
22228    * @return {object} state
22229    */
22230   Location.prototype.state = function(state) {
22231     if (!arguments.length) {
22232       return this.$$state;
22233     }
22234
22235     if (Location !== LocationHtml5Url || !this.$$html5) {
22236       throw $locationMinErr('nostate', 'History API state support is available only ' +
22237         'in HTML5 mode and only in browsers supporting HTML5 History API');
22238     }
22239     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
22240     // but we're changing the $$state reference to $browser.state() during the $digest
22241     // so the modification window is narrow.
22242     this.$$state = isUndefined(state) ? null : state;
22243
22244     return this;
22245   };
22246 });
22247
22248
22249 function locationGetter(property) {
22250   return function() {
22251     return this[property];
22252   };
22253 }
22254
22255
22256 function locationGetterSetter(property, preprocess) {
22257   return function(value) {
22258     if (isUndefined(value)) {
22259       return this[property];
22260     }
22261
22262     this[property] = preprocess(value);
22263     this.$$compose();
22264
22265     return this;
22266   };
22267 }
22268
22269
22270 /**
22271  * @ngdoc service
22272  * @name $location
22273  *
22274  * @requires $rootElement
22275  *
22276  * @description
22277  * The $location service parses the URL in the browser address bar (based on the
22278  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
22279  * available to your application. Changes to the URL in the address bar are reflected into
22280  * $location service and changes to $location are reflected into the browser address bar.
22281  *
22282  * **The $location service:**
22283  *
22284  * - Exposes the current URL in the browser address bar, so you can
22285  *   - Watch and observe the URL.
22286  *   - Change the URL.
22287  * - Synchronizes the URL with the browser when the user
22288  *   - Changes the address bar.
22289  *   - Clicks the back or forward button (or clicks a History link).
22290  *   - Clicks on a link.
22291  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
22292  *
22293  * For more information see {@link guide/$location Developer Guide: Using $location}
22294  */
22295
22296 /**
22297  * @ngdoc provider
22298  * @name $locationProvider
22299  * @description
22300  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
22301  */
22302 function $LocationProvider() {
22303   var hashPrefix = '',
22304       html5Mode = {
22305         enabled: false,
22306         requireBase: true,
22307         rewriteLinks: true
22308       };
22309
22310   /**
22311    * @ngdoc method
22312    * @name $locationProvider#hashPrefix
22313    * @description
22314    * @param {string=} prefix Prefix for hash part (containing path and search)
22315    * @returns {*} current value if used as getter or itself (chaining) if used as setter
22316    */
22317   this.hashPrefix = function(prefix) {
22318     if (isDefined(prefix)) {
22319       hashPrefix = prefix;
22320       return this;
22321     } else {
22322       return hashPrefix;
22323     }
22324   };
22325
22326   /**
22327    * @ngdoc method
22328    * @name $locationProvider#html5Mode
22329    * @description
22330    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
22331    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
22332    *   properties:
22333    *   - **enabled** â€“ `{boolean}` â€“ (default: false) If true, will rely on `history.pushState` to
22334    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
22335    *     support `pushState`.
22336    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
22337    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
22338    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
22339    *     See the {@link guide/$location $location guide for more information}
22340    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
22341    *     enables/disables url rewriting for relative links.
22342    *
22343    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
22344    */
22345   this.html5Mode = function(mode) {
22346     if (isBoolean(mode)) {
22347       html5Mode.enabled = mode;
22348       return this;
22349     } else if (isObject(mode)) {
22350
22351       if (isBoolean(mode.enabled)) {
22352         html5Mode.enabled = mode.enabled;
22353       }
22354
22355       if (isBoolean(mode.requireBase)) {
22356         html5Mode.requireBase = mode.requireBase;
22357       }
22358
22359       if (isBoolean(mode.rewriteLinks)) {
22360         html5Mode.rewriteLinks = mode.rewriteLinks;
22361       }
22362
22363       return this;
22364     } else {
22365       return html5Mode;
22366     }
22367   };
22368
22369   /**
22370    * @ngdoc event
22371    * @name $location#$locationChangeStart
22372    * @eventType broadcast on root scope
22373    * @description
22374    * Broadcasted before a URL will change.
22375    *
22376    * This change can be prevented by calling
22377    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
22378    * details about event object. Upon successful change
22379    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
22380    *
22381    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
22382    * the browser supports the HTML5 History API.
22383    *
22384    * @param {Object} angularEvent Synthetic event object.
22385    * @param {string} newUrl New URL
22386    * @param {string=} oldUrl URL that was before it was changed.
22387    * @param {string=} newState New history state object
22388    * @param {string=} oldState History state object that was before it was changed.
22389    */
22390
22391   /**
22392    * @ngdoc event
22393    * @name $location#$locationChangeSuccess
22394    * @eventType broadcast on root scope
22395    * @description
22396    * Broadcasted after a URL was changed.
22397    *
22398    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
22399    * the browser supports the HTML5 History API.
22400    *
22401    * @param {Object} angularEvent Synthetic event object.
22402    * @param {string} newUrl New URL
22403    * @param {string=} oldUrl URL that was before it was changed.
22404    * @param {string=} newState New history state object
22405    * @param {string=} oldState History state object that was before it was changed.
22406    */
22407
22408   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
22409       function($rootScope, $browser, $sniffer, $rootElement, $window) {
22410     var $location,
22411         LocationMode,
22412         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
22413         initialUrl = $browser.url(),
22414         appBase;
22415
22416     if (html5Mode.enabled) {
22417       if (!baseHref && html5Mode.requireBase) {
22418         throw $locationMinErr('nobase',
22419           "$location in HTML5 mode requires a <base> tag to be present!");
22420       }
22421       appBase = serverBase(initialUrl) + (baseHref || '/');
22422       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
22423     } else {
22424       appBase = stripHash(initialUrl);
22425       LocationMode = LocationHashbangUrl;
22426     }
22427     var appBaseNoFile = stripFile(appBase);
22428
22429     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
22430     $location.$$parseLinkUrl(initialUrl, initialUrl);
22431
22432     $location.$$state = $browser.state();
22433
22434     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
22435
22436     function setBrowserUrlWithFallback(url, replace, state) {
22437       var oldUrl = $location.url();
22438       var oldState = $location.$$state;
22439       try {
22440         $browser.url(url, replace, state);
22441
22442         // Make sure $location.state() returns referentially identical (not just deeply equal)
22443         // state object; this makes possible quick checking if the state changed in the digest
22444         // loop. Checking deep equality would be too expensive.
22445         $location.$$state = $browser.state();
22446       } catch (e) {
22447         // Restore old values if pushState fails
22448         $location.url(oldUrl);
22449         $location.$$state = oldState;
22450
22451         throw e;
22452       }
22453     }
22454
22455     $rootElement.on('click', function(event) {
22456       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
22457       // currently we open nice url link and redirect then
22458
22459       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
22460
22461       var elm = jqLite(event.target);
22462
22463       // traverse the DOM up to find first A tag
22464       while (nodeName_(elm[0]) !== 'a') {
22465         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
22466         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
22467       }
22468
22469       var absHref = elm.prop('href');
22470       // get the actual href attribute - see
22471       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
22472       var relHref = elm.attr('href') || elm.attr('xlink:href');
22473
22474       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
22475         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
22476         // an animation.
22477         absHref = urlResolve(absHref.animVal).href;
22478       }
22479
22480       // Ignore when url is started with javascript: or mailto:
22481       if (IGNORE_URI_REGEXP.test(absHref)) return;
22482
22483       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
22484         if ($location.$$parseLinkUrl(absHref, relHref)) {
22485           // We do a preventDefault for all urls that are part of the angular application,
22486           // in html5mode and also without, so that we are able to abort navigation without
22487           // getting double entries in the location history.
22488           event.preventDefault();
22489           // update location manually
22490           if ($location.absUrl() != $browser.url()) {
22491             $rootScope.$apply();
22492             // hack to work around FF6 bug 684208 when scenario runner clicks on links
22493             $window.angular['ff-684208-preventDefault'] = true;
22494           }
22495         }
22496       }
22497     });
22498
22499
22500     // rewrite hashbang url <> html5 url
22501     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
22502       $browser.url($location.absUrl(), true);
22503     }
22504
22505     var initializing = true;
22506
22507     // update $location when $browser url changes
22508     $browser.onUrlChange(function(newUrl, newState) {
22509
22510       if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
22511         // If we are navigating outside of the app then force a reload
22512         $window.location.href = newUrl;
22513         return;
22514       }
22515
22516       $rootScope.$evalAsync(function() {
22517         var oldUrl = $location.absUrl();
22518         var oldState = $location.$$state;
22519         var defaultPrevented;
22520         newUrl = trimEmptyHash(newUrl);
22521         $location.$$parse(newUrl);
22522         $location.$$state = newState;
22523
22524         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
22525             newState, oldState).defaultPrevented;
22526
22527         // if the location was changed by a `$locationChangeStart` handler then stop
22528         // processing this location change
22529         if ($location.absUrl() !== newUrl) return;
22530
22531         if (defaultPrevented) {
22532           $location.$$parse(oldUrl);
22533           $location.$$state = oldState;
22534           setBrowserUrlWithFallback(oldUrl, false, oldState);
22535         } else {
22536           initializing = false;
22537           afterLocationChange(oldUrl, oldState);
22538         }
22539       });
22540       if (!$rootScope.$$phase) $rootScope.$digest();
22541     });
22542
22543     // update browser
22544     $rootScope.$watch(function $locationWatch() {
22545       var oldUrl = trimEmptyHash($browser.url());
22546       var newUrl = trimEmptyHash($location.absUrl());
22547       var oldState = $browser.state();
22548       var currentReplace = $location.$$replace;
22549       var urlOrStateChanged = oldUrl !== newUrl ||
22550         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
22551
22552       if (initializing || urlOrStateChanged) {
22553         initializing = false;
22554
22555         $rootScope.$evalAsync(function() {
22556           var newUrl = $location.absUrl();
22557           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
22558               $location.$$state, oldState).defaultPrevented;
22559
22560           // if the location was changed by a `$locationChangeStart` handler then stop
22561           // processing this location change
22562           if ($location.absUrl() !== newUrl) return;
22563
22564           if (defaultPrevented) {
22565             $location.$$parse(oldUrl);
22566             $location.$$state = oldState;
22567           } else {
22568             if (urlOrStateChanged) {
22569               setBrowserUrlWithFallback(newUrl, currentReplace,
22570                                         oldState === $location.$$state ? null : $location.$$state);
22571             }
22572             afterLocationChange(oldUrl, oldState);
22573           }
22574         });
22575       }
22576
22577       $location.$$replace = false;
22578
22579       // we don't need to return anything because $evalAsync will make the digest loop dirty when
22580       // there is a change
22581     });
22582
22583     return $location;
22584
22585     function afterLocationChange(oldUrl, oldState) {
22586       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
22587         $location.$$state, oldState);
22588     }
22589 }];
22590 }
22591
22592 /**
22593  * @ngdoc service
22594  * @name $log
22595  * @requires $window
22596  *
22597  * @description
22598  * Simple service for logging. Default implementation safely writes the message
22599  * into the browser's console (if present).
22600  *
22601  * The main purpose of this service is to simplify debugging and troubleshooting.
22602  *
22603  * The default is to log `debug` messages. You can use
22604  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
22605  *
22606  * @example
22607    <example module="logExample">
22608      <file name="script.js">
22609        angular.module('logExample', [])
22610          .controller('LogController', ['$scope', '$log', function($scope, $log) {
22611            $scope.$log = $log;
22612            $scope.message = 'Hello World!';
22613          }]);
22614      </file>
22615      <file name="index.html">
22616        <div ng-controller="LogController">
22617          <p>Reload this page with open console, enter text and hit the log button...</p>
22618          <label>Message:
22619          <input type="text" ng-model="message" /></label>
22620          <button ng-click="$log.log(message)">log</button>
22621          <button ng-click="$log.warn(message)">warn</button>
22622          <button ng-click="$log.info(message)">info</button>
22623          <button ng-click="$log.error(message)">error</button>
22624          <button ng-click="$log.debug(message)">debug</button>
22625        </div>
22626      </file>
22627    </example>
22628  */
22629
22630 /**
22631  * @ngdoc provider
22632  * @name $logProvider
22633  * @description
22634  * Use the `$logProvider` to configure how the application logs messages
22635  */
22636 function $LogProvider() {
22637   var debug = true,
22638       self = this;
22639
22640   /**
22641    * @ngdoc method
22642    * @name $logProvider#debugEnabled
22643    * @description
22644    * @param {boolean=} flag enable or disable debug level messages
22645    * @returns {*} current value if used as getter or itself (chaining) if used as setter
22646    */
22647   this.debugEnabled = function(flag) {
22648     if (isDefined(flag)) {
22649       debug = flag;
22650     return this;
22651     } else {
22652       return debug;
22653     }
22654   };
22655
22656   this.$get = ['$window', function($window) {
22657     return {
22658       /**
22659        * @ngdoc method
22660        * @name $log#log
22661        *
22662        * @description
22663        * Write a log message
22664        */
22665       log: consoleLog('log'),
22666
22667       /**
22668        * @ngdoc method
22669        * @name $log#info
22670        *
22671        * @description
22672        * Write an information message
22673        */
22674       info: consoleLog('info'),
22675
22676       /**
22677        * @ngdoc method
22678        * @name $log#warn
22679        *
22680        * @description
22681        * Write a warning message
22682        */
22683       warn: consoleLog('warn'),
22684
22685       /**
22686        * @ngdoc method
22687        * @name $log#error
22688        *
22689        * @description
22690        * Write an error message
22691        */
22692       error: consoleLog('error'),
22693
22694       /**
22695        * @ngdoc method
22696        * @name $log#debug
22697        *
22698        * @description
22699        * Write a debug message
22700        */
22701       debug: (function() {
22702         var fn = consoleLog('debug');
22703
22704         return function() {
22705           if (debug) {
22706             fn.apply(self, arguments);
22707           }
22708         };
22709       }())
22710     };
22711
22712     function formatError(arg) {
22713       if (arg instanceof Error) {
22714         if (arg.stack) {
22715           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
22716               ? 'Error: ' + arg.message + '\n' + arg.stack
22717               : arg.stack;
22718         } else if (arg.sourceURL) {
22719           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
22720         }
22721       }
22722       return arg;
22723     }
22724
22725     function consoleLog(type) {
22726       var console = $window.console || {},
22727           logFn = console[type] || console.log || noop,
22728           hasApply = false;
22729
22730       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
22731       // The reason behind this is that console.log has type "object" in IE8...
22732       try {
22733         hasApply = !!logFn.apply;
22734       } catch (e) {}
22735
22736       if (hasApply) {
22737         return function() {
22738           var args = [];
22739           forEach(arguments, function(arg) {
22740             args.push(formatError(arg));
22741           });
22742           return logFn.apply(console, args);
22743         };
22744       }
22745
22746       // we are IE which either doesn't have window.console => this is noop and we do nothing,
22747       // or we are IE where console.log doesn't have apply so we log at least first 2 args
22748       return function(arg1, arg2) {
22749         logFn(arg1, arg2 == null ? '' : arg2);
22750       };
22751     }
22752   }];
22753 }
22754
22755 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22756  *     Any commits to this file should be reviewed with security in mind.  *
22757  *   Changes to this file can potentially create security vulnerabilities. *
22758  *          An approval from 2 Core members with history of modifying      *
22759  *                         this file is required.                          *
22760  *                                                                         *
22761  *  Does the change somehow allow for arbitrary javascript to be executed? *
22762  *    Or allows for someone to change the prototype of built-in objects?   *
22763  *     Or gives undesired access to variables likes document or window?    *
22764  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22765
22766 var $parseMinErr = minErr('$parse');
22767
22768 // Sandboxing Angular Expressions
22769 // ------------------------------
22770 // Angular expressions are generally considered safe because these expressions only have direct
22771 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
22772 // obtaining a reference to native JS functions such as the Function constructor.
22773 //
22774 // As an example, consider the following Angular expression:
22775 //
22776 //   {}.toString.constructor('alert("evil JS code")')
22777 //
22778 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
22779 // against the expression language, but not to prevent exploits that were enabled by exposing
22780 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
22781 // practice and therefore we are not even trying to protect against interaction with an object
22782 // explicitly exposed in this way.
22783 //
22784 // In general, it is not possible to access a Window object from an angular expression unless a
22785 // window or some DOM object that has a reference to window is published onto a Scope.
22786 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
22787 // native objects.
22788 //
22789 // See https://docs.angularjs.org/guide/security
22790
22791
22792 function ensureSafeMemberName(name, fullExpression) {
22793   if (name === "__defineGetter__" || name === "__defineSetter__"
22794       || name === "__lookupGetter__" || name === "__lookupSetter__"
22795       || name === "__proto__") {
22796     throw $parseMinErr('isecfld',
22797         'Attempting to access a disallowed field in Angular expressions! '
22798         + 'Expression: {0}', fullExpression);
22799   }
22800   return name;
22801 }
22802
22803 function getStringValue(name) {
22804   // Property names must be strings. This means that non-string objects cannot be used
22805   // as keys in an object. Any non-string object, including a number, is typecasted
22806   // into a string via the toString method.
22807   // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
22808   //
22809   // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
22810   // to a string. It's not always possible. If `name` is an object and its `toString` method is
22811   // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
22812   //
22813   // TypeError: Cannot convert object to primitive value
22814   //
22815   // For performance reasons, we don't catch this error here and allow it to propagate up the call
22816   // stack. Note that you'll get the same error in JavaScript if you try to access a property using
22817   // such a 'broken' object as a key.
22818   return name + '';
22819 }
22820
22821 function ensureSafeObject(obj, fullExpression) {
22822   // nifty check if obj is Function that is fast and works across iframes and other contexts
22823   if (obj) {
22824     if (obj.constructor === obj) {
22825       throw $parseMinErr('isecfn',
22826           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
22827           fullExpression);
22828     } else if (// isWindow(obj)
22829         obj.window === obj) {
22830       throw $parseMinErr('isecwindow',
22831           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
22832           fullExpression);
22833     } else if (// isElement(obj)
22834         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
22835       throw $parseMinErr('isecdom',
22836           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
22837           fullExpression);
22838     } else if (// block Object so that we can't get hold of dangerous Object.* methods
22839         obj === Object) {
22840       throw $parseMinErr('isecobj',
22841           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
22842           fullExpression);
22843     }
22844   }
22845   return obj;
22846 }
22847
22848 var CALL = Function.prototype.call;
22849 var APPLY = Function.prototype.apply;
22850 var BIND = Function.prototype.bind;
22851
22852 function ensureSafeFunction(obj, fullExpression) {
22853   if (obj) {
22854     if (obj.constructor === obj) {
22855       throw $parseMinErr('isecfn',
22856         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
22857         fullExpression);
22858     } else if (obj === CALL || obj === APPLY || obj === BIND) {
22859       throw $parseMinErr('isecff',
22860         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
22861         fullExpression);
22862     }
22863   }
22864 }
22865
22866 function ensureSafeAssignContext(obj, fullExpression) {
22867   if (obj) {
22868     if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
22869         obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
22870       throw $parseMinErr('isecaf',
22871         'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
22872     }
22873   }
22874 }
22875
22876 var OPERATORS = createMap();
22877 forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
22878 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
22879
22880
22881 /////////////////////////////////////////
22882
22883
22884 /**
22885  * @constructor
22886  */
22887 var Lexer = function(options) {
22888   this.options = options;
22889 };
22890
22891 Lexer.prototype = {
22892   constructor: Lexer,
22893
22894   lex: function(text) {
22895     this.text = text;
22896     this.index = 0;
22897     this.tokens = [];
22898
22899     while (this.index < this.text.length) {
22900       var ch = this.text.charAt(this.index);
22901       if (ch === '"' || ch === "'") {
22902         this.readString(ch);
22903       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
22904         this.readNumber();
22905       } else if (this.isIdentifierStart(this.peekMultichar())) {
22906         this.readIdent();
22907       } else if (this.is(ch, '(){}[].,;:?')) {
22908         this.tokens.push({index: this.index, text: ch});
22909         this.index++;
22910       } else if (this.isWhitespace(ch)) {
22911         this.index++;
22912       } else {
22913         var ch2 = ch + this.peek();
22914         var ch3 = ch2 + this.peek(2);
22915         var op1 = OPERATORS[ch];
22916         var op2 = OPERATORS[ch2];
22917         var op3 = OPERATORS[ch3];
22918         if (op1 || op2 || op3) {
22919           var token = op3 ? ch3 : (op2 ? ch2 : ch);
22920           this.tokens.push({index: this.index, text: token, operator: true});
22921           this.index += token.length;
22922         } else {
22923           this.throwError('Unexpected next character ', this.index, this.index + 1);
22924         }
22925       }
22926     }
22927     return this.tokens;
22928   },
22929
22930   is: function(ch, chars) {
22931     return chars.indexOf(ch) !== -1;
22932   },
22933
22934   peek: function(i) {
22935     var num = i || 1;
22936     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
22937   },
22938
22939   isNumber: function(ch) {
22940     return ('0' <= ch && ch <= '9') && typeof ch === "string";
22941   },
22942
22943   isWhitespace: function(ch) {
22944     // IE treats non-breaking space as \u00A0
22945     return (ch === ' ' || ch === '\r' || ch === '\t' ||
22946             ch === '\n' || ch === '\v' || ch === '\u00A0');
22947   },
22948
22949   isIdentifierStart: function(ch) {
22950     return this.options.isIdentifierStart ?
22951         this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
22952         this.isValidIdentifierStart(ch);
22953   },
22954
22955   isValidIdentifierStart: function(ch) {
22956     return ('a' <= ch && ch <= 'z' ||
22957             'A' <= ch && ch <= 'Z' ||
22958             '_' === ch || ch === '$');
22959   },
22960
22961   isIdentifierContinue: function(ch) {
22962     return this.options.isIdentifierContinue ?
22963         this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
22964         this.isValidIdentifierContinue(ch);
22965   },
22966
22967   isValidIdentifierContinue: function(ch, cp) {
22968     return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
22969   },
22970
22971   codePointAt: function(ch) {
22972     if (ch.length === 1) return ch.charCodeAt(0);
22973     /*jshint bitwise: false*/
22974     return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
22975     /*jshint bitwise: true*/
22976   },
22977
22978   peekMultichar: function() {
22979     var ch = this.text.charAt(this.index);
22980     var peek = this.peek();
22981     if (!peek) {
22982       return ch;
22983     }
22984     var cp1 = ch.charCodeAt(0);
22985     var cp2 = peek.charCodeAt(0);
22986     if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
22987       return ch + peek;
22988     }
22989     return ch;
22990   },
22991
22992   isExpOperator: function(ch) {
22993     return (ch === '-' || ch === '+' || this.isNumber(ch));
22994   },
22995
22996   throwError: function(error, start, end) {
22997     end = end || this.index;
22998     var colStr = (isDefined(start)
22999             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
23000             : ' ' + end);
23001     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
23002         error, colStr, this.text);
23003   },
23004
23005   readNumber: function() {
23006     var number = '';
23007     var start = this.index;
23008     while (this.index < this.text.length) {
23009       var ch = lowercase(this.text.charAt(this.index));
23010       if (ch == '.' || this.isNumber(ch)) {
23011         number += ch;
23012       } else {
23013         var peekCh = this.peek();
23014         if (ch == 'e' && this.isExpOperator(peekCh)) {
23015           number += ch;
23016         } else if (this.isExpOperator(ch) &&
23017             peekCh && this.isNumber(peekCh) &&
23018             number.charAt(number.length - 1) == 'e') {
23019           number += ch;
23020         } else if (this.isExpOperator(ch) &&
23021             (!peekCh || !this.isNumber(peekCh)) &&
23022             number.charAt(number.length - 1) == 'e') {
23023           this.throwError('Invalid exponent');
23024         } else {
23025           break;
23026         }
23027       }
23028       this.index++;
23029     }
23030     this.tokens.push({
23031       index: start,
23032       text: number,
23033       constant: true,
23034       value: Number(number)
23035     });
23036   },
23037
23038   readIdent: function() {
23039     var start = this.index;
23040     this.index += this.peekMultichar().length;
23041     while (this.index < this.text.length) {
23042       var ch = this.peekMultichar();
23043       if (!this.isIdentifierContinue(ch)) {
23044         break;
23045       }
23046       this.index += ch.length;
23047     }
23048     this.tokens.push({
23049       index: start,
23050       text: this.text.slice(start, this.index),
23051       identifier: true
23052     });
23053   },
23054
23055   readString: function(quote) {
23056     var start = this.index;
23057     this.index++;
23058     var string = '';
23059     var rawString = quote;
23060     var escape = false;
23061     while (this.index < this.text.length) {
23062       var ch = this.text.charAt(this.index);
23063       rawString += ch;
23064       if (escape) {
23065         if (ch === 'u') {
23066           var hex = this.text.substring(this.index + 1, this.index + 5);
23067           if (!hex.match(/[\da-f]{4}/i)) {
23068             this.throwError('Invalid unicode escape [\\u' + hex + ']');
23069           }
23070           this.index += 4;
23071           string += String.fromCharCode(parseInt(hex, 16));
23072         } else {
23073           var rep = ESCAPE[ch];
23074           string = string + (rep || ch);
23075         }
23076         escape = false;
23077       } else if (ch === '\\') {
23078         escape = true;
23079       } else if (ch === quote) {
23080         this.index++;
23081         this.tokens.push({
23082           index: start,
23083           text: rawString,
23084           constant: true,
23085           value: string
23086         });
23087         return;
23088       } else {
23089         string += ch;
23090       }
23091       this.index++;
23092     }
23093     this.throwError('Unterminated quote', start);
23094   }
23095 };
23096
23097 var AST = function(lexer, options) {
23098   this.lexer = lexer;
23099   this.options = options;
23100 };
23101
23102 AST.Program = 'Program';
23103 AST.ExpressionStatement = 'ExpressionStatement';
23104 AST.AssignmentExpression = 'AssignmentExpression';
23105 AST.ConditionalExpression = 'ConditionalExpression';
23106 AST.LogicalExpression = 'LogicalExpression';
23107 AST.BinaryExpression = 'BinaryExpression';
23108 AST.UnaryExpression = 'UnaryExpression';
23109 AST.CallExpression = 'CallExpression';
23110 AST.MemberExpression = 'MemberExpression';
23111 AST.Identifier = 'Identifier';
23112 AST.Literal = 'Literal';
23113 AST.ArrayExpression = 'ArrayExpression';
23114 AST.Property = 'Property';
23115 AST.ObjectExpression = 'ObjectExpression';
23116 AST.ThisExpression = 'ThisExpression';
23117 AST.LocalsExpression = 'LocalsExpression';
23118
23119 // Internal use only
23120 AST.NGValueParameter = 'NGValueParameter';
23121
23122 AST.prototype = {
23123   ast: function(text) {
23124     this.text = text;
23125     this.tokens = this.lexer.lex(text);
23126
23127     var value = this.program();
23128
23129     if (this.tokens.length !== 0) {
23130       this.throwError('is an unexpected token', this.tokens[0]);
23131     }
23132
23133     return value;
23134   },
23135
23136   program: function() {
23137     var body = [];
23138     while (true) {
23139       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
23140         body.push(this.expressionStatement());
23141       if (!this.expect(';')) {
23142         return { type: AST.Program, body: body};
23143       }
23144     }
23145   },
23146
23147   expressionStatement: function() {
23148     return { type: AST.ExpressionStatement, expression: this.filterChain() };
23149   },
23150
23151   filterChain: function() {
23152     var left = this.expression();
23153     var token;
23154     while ((token = this.expect('|'))) {
23155       left = this.filter(left);
23156     }
23157     return left;
23158   },
23159
23160   expression: function() {
23161     return this.assignment();
23162   },
23163
23164   assignment: function() {
23165     var result = this.ternary();
23166     if (this.expect('=')) {
23167       result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
23168     }
23169     return result;
23170   },
23171
23172   ternary: function() {
23173     var test = this.logicalOR();
23174     var alternate;
23175     var consequent;
23176     if (this.expect('?')) {
23177       alternate = this.expression();
23178       if (this.consume(':')) {
23179         consequent = this.expression();
23180         return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
23181       }
23182     }
23183     return test;
23184   },
23185
23186   logicalOR: function() {
23187     var left = this.logicalAND();
23188     while (this.expect('||')) {
23189       left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
23190     }
23191     return left;
23192   },
23193
23194   logicalAND: function() {
23195     var left = this.equality();
23196     while (this.expect('&&')) {
23197       left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
23198     }
23199     return left;
23200   },
23201
23202   equality: function() {
23203     var left = this.relational();
23204     var token;
23205     while ((token = this.expect('==','!=','===','!=='))) {
23206       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
23207     }
23208     return left;
23209   },
23210
23211   relational: function() {
23212     var left = this.additive();
23213     var token;
23214     while ((token = this.expect('<', '>', '<=', '>='))) {
23215       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
23216     }
23217     return left;
23218   },
23219
23220   additive: function() {
23221     var left = this.multiplicative();
23222     var token;
23223     while ((token = this.expect('+','-'))) {
23224       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
23225     }
23226     return left;
23227   },
23228
23229   multiplicative: function() {
23230     var left = this.unary();
23231     var token;
23232     while ((token = this.expect('*','/','%'))) {
23233       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
23234     }
23235     return left;
23236   },
23237
23238   unary: function() {
23239     var token;
23240     if ((token = this.expect('+', '-', '!'))) {
23241       return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
23242     } else {
23243       return this.primary();
23244     }
23245   },
23246
23247   primary: function() {
23248     var primary;
23249     if (this.expect('(')) {
23250       primary = this.filterChain();
23251       this.consume(')');
23252     } else if (this.expect('[')) {
23253       primary = this.arrayDeclaration();
23254     } else if (this.expect('{')) {
23255       primary = this.object();
23256     } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
23257       primary = copy(this.selfReferential[this.consume().text]);
23258     } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
23259       primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
23260     } else if (this.peek().identifier) {
23261       primary = this.identifier();
23262     } else if (this.peek().constant) {
23263       primary = this.constant();
23264     } else {
23265       this.throwError('not a primary expression', this.peek());
23266     }
23267
23268     var next;
23269     while ((next = this.expect('(', '[', '.'))) {
23270       if (next.text === '(') {
23271         primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
23272         this.consume(')');
23273       } else if (next.text === '[') {
23274         primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
23275         this.consume(']');
23276       } else if (next.text === '.') {
23277         primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
23278       } else {
23279         this.throwError('IMPOSSIBLE');
23280       }
23281     }
23282     return primary;
23283   },
23284
23285   filter: function(baseExpression) {
23286     var args = [baseExpression];
23287     var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
23288
23289     while (this.expect(':')) {
23290       args.push(this.expression());
23291     }
23292
23293     return result;
23294   },
23295
23296   parseArguments: function() {
23297     var args = [];
23298     if (this.peekToken().text !== ')') {
23299       do {
23300         args.push(this.expression());
23301       } while (this.expect(','));
23302     }
23303     return args;
23304   },
23305
23306   identifier: function() {
23307     var token = this.consume();
23308     if (!token.identifier) {
23309       this.throwError('is not a valid identifier', token);
23310     }
23311     return { type: AST.Identifier, name: token.text };
23312   },
23313
23314   constant: function() {
23315     // TODO check that it is a constant
23316     return { type: AST.Literal, value: this.consume().value };
23317   },
23318
23319   arrayDeclaration: function() {
23320     var elements = [];
23321     if (this.peekToken().text !== ']') {
23322       do {
23323         if (this.peek(']')) {
23324           // Support trailing commas per ES5.1.
23325           break;
23326         }
23327         elements.push(this.expression());
23328       } while (this.expect(','));
23329     }
23330     this.consume(']');
23331
23332     return { type: AST.ArrayExpression, elements: elements };
23333   },
23334
23335   object: function() {
23336     var properties = [], property;
23337     if (this.peekToken().text !== '}') {
23338       do {
23339         if (this.peek('}')) {
23340           // Support trailing commas per ES5.1.
23341           break;
23342         }
23343         property = {type: AST.Property, kind: 'init'};
23344         if (this.peek().constant) {
23345           property.key = this.constant();
23346         } else if (this.peek().identifier) {
23347           property.key = this.identifier();
23348         } else {
23349           this.throwError("invalid key", this.peek());
23350         }
23351         this.consume(':');
23352         property.value = this.expression();
23353         properties.push(property);
23354       } while (this.expect(','));
23355     }
23356     this.consume('}');
23357
23358     return {type: AST.ObjectExpression, properties: properties };
23359   },
23360
23361   throwError: function(msg, token) {
23362     throw $parseMinErr('syntax',
23363         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
23364           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
23365   },
23366
23367   consume: function(e1) {
23368     if (this.tokens.length === 0) {
23369       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
23370     }
23371
23372     var token = this.expect(e1);
23373     if (!token) {
23374       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
23375     }
23376     return token;
23377   },
23378
23379   peekToken: function() {
23380     if (this.tokens.length === 0) {
23381       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
23382     }
23383     return this.tokens[0];
23384   },
23385
23386   peek: function(e1, e2, e3, e4) {
23387     return this.peekAhead(0, e1, e2, e3, e4);
23388   },
23389
23390   peekAhead: function(i, e1, e2, e3, e4) {
23391     if (this.tokens.length > i) {
23392       var token = this.tokens[i];
23393       var t = token.text;
23394       if (t === e1 || t === e2 || t === e3 || t === e4 ||
23395           (!e1 && !e2 && !e3 && !e4)) {
23396         return token;
23397       }
23398     }
23399     return false;
23400   },
23401
23402   expect: function(e1, e2, e3, e4) {
23403     var token = this.peek(e1, e2, e3, e4);
23404     if (token) {
23405       this.tokens.shift();
23406       return token;
23407     }
23408     return false;
23409   },
23410
23411   selfReferential: {
23412     'this': {type: AST.ThisExpression },
23413     '$locals': {type: AST.LocalsExpression }
23414   }
23415 };
23416
23417 function ifDefined(v, d) {
23418   return typeof v !== 'undefined' ? v : d;
23419 }
23420
23421 function plusFn(l, r) {
23422   if (typeof l === 'undefined') return r;
23423   if (typeof r === 'undefined') return l;
23424   return l + r;
23425 }
23426
23427 function isStateless($filter, filterName) {
23428   var fn = $filter(filterName);
23429   return !fn.$stateful;
23430 }
23431
23432 function findConstantAndWatchExpressions(ast, $filter) {
23433   var allConstants;
23434   var argsToWatch;
23435   switch (ast.type) {
23436   case AST.Program:
23437     allConstants = true;
23438     forEach(ast.body, function(expr) {
23439       findConstantAndWatchExpressions(expr.expression, $filter);
23440       allConstants = allConstants && expr.expression.constant;
23441     });
23442     ast.constant = allConstants;
23443     break;
23444   case AST.Literal:
23445     ast.constant = true;
23446     ast.toWatch = [];
23447     break;
23448   case AST.UnaryExpression:
23449     findConstantAndWatchExpressions(ast.argument, $filter);
23450     ast.constant = ast.argument.constant;
23451     ast.toWatch = ast.argument.toWatch;
23452     break;
23453   case AST.BinaryExpression:
23454     findConstantAndWatchExpressions(ast.left, $filter);
23455     findConstantAndWatchExpressions(ast.right, $filter);
23456     ast.constant = ast.left.constant && ast.right.constant;
23457     ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
23458     break;
23459   case AST.LogicalExpression:
23460     findConstantAndWatchExpressions(ast.left, $filter);
23461     findConstantAndWatchExpressions(ast.right, $filter);
23462     ast.constant = ast.left.constant && ast.right.constant;
23463     ast.toWatch = ast.constant ? [] : [ast];
23464     break;
23465   case AST.ConditionalExpression:
23466     findConstantAndWatchExpressions(ast.test, $filter);
23467     findConstantAndWatchExpressions(ast.alternate, $filter);
23468     findConstantAndWatchExpressions(ast.consequent, $filter);
23469     ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
23470     ast.toWatch = ast.constant ? [] : [ast];
23471     break;
23472   case AST.Identifier:
23473     ast.constant = false;
23474     ast.toWatch = [ast];
23475     break;
23476   case AST.MemberExpression:
23477     findConstantAndWatchExpressions(ast.object, $filter);
23478     if (ast.computed) {
23479       findConstantAndWatchExpressions(ast.property, $filter);
23480     }
23481     ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
23482     ast.toWatch = [ast];
23483     break;
23484   case AST.CallExpression:
23485     allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
23486     argsToWatch = [];
23487     forEach(ast.arguments, function(expr) {
23488       findConstantAndWatchExpressions(expr, $filter);
23489       allConstants = allConstants && expr.constant;
23490       if (!expr.constant) {
23491         argsToWatch.push.apply(argsToWatch, expr.toWatch);
23492       }
23493     });
23494     ast.constant = allConstants;
23495     ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
23496     break;
23497   case AST.AssignmentExpression:
23498     findConstantAndWatchExpressions(ast.left, $filter);
23499     findConstantAndWatchExpressions(ast.right, $filter);
23500     ast.constant = ast.left.constant && ast.right.constant;
23501     ast.toWatch = [ast];
23502     break;
23503   case AST.ArrayExpression:
23504     allConstants = true;
23505     argsToWatch = [];
23506     forEach(ast.elements, function(expr) {
23507       findConstantAndWatchExpressions(expr, $filter);
23508       allConstants = allConstants && expr.constant;
23509       if (!expr.constant) {
23510         argsToWatch.push.apply(argsToWatch, expr.toWatch);
23511       }
23512     });
23513     ast.constant = allConstants;
23514     ast.toWatch = argsToWatch;
23515     break;
23516   case AST.ObjectExpression:
23517     allConstants = true;
23518     argsToWatch = [];
23519     forEach(ast.properties, function(property) {
23520       findConstantAndWatchExpressions(property.value, $filter);
23521       allConstants = allConstants && property.value.constant;
23522       if (!property.value.constant) {
23523         argsToWatch.push.apply(argsToWatch, property.value.toWatch);
23524       }
23525     });
23526     ast.constant = allConstants;
23527     ast.toWatch = argsToWatch;
23528     break;
23529   case AST.ThisExpression:
23530     ast.constant = false;
23531     ast.toWatch = [];
23532     break;
23533   case AST.LocalsExpression:
23534     ast.constant = false;
23535     ast.toWatch = [];
23536     break;
23537   }
23538 }
23539
23540 function getInputs(body) {
23541   if (body.length != 1) return;
23542   var lastExpression = body[0].expression;
23543   var candidate = lastExpression.toWatch;
23544   if (candidate.length !== 1) return candidate;
23545   return candidate[0] !== lastExpression ? candidate : undefined;
23546 }
23547
23548 function isAssignable(ast) {
23549   return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
23550 }
23551
23552 function assignableAST(ast) {
23553   if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
23554     return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
23555   }
23556 }
23557
23558 function isLiteral(ast) {
23559   return ast.body.length === 0 ||
23560       ast.body.length === 1 && (
23561       ast.body[0].expression.type === AST.Literal ||
23562       ast.body[0].expression.type === AST.ArrayExpression ||
23563       ast.body[0].expression.type === AST.ObjectExpression);
23564 }
23565
23566 function isConstant(ast) {
23567   return ast.constant;
23568 }
23569
23570 function ASTCompiler(astBuilder, $filter) {
23571   this.astBuilder = astBuilder;
23572   this.$filter = $filter;
23573 }
23574
23575 ASTCompiler.prototype = {
23576   compile: function(expression, expensiveChecks) {
23577     var self = this;
23578     var ast = this.astBuilder.ast(expression);
23579     this.state = {
23580       nextId: 0,
23581       filters: {},
23582       expensiveChecks: expensiveChecks,
23583       fn: {vars: [], body: [], own: {}},
23584       assign: {vars: [], body: [], own: {}},
23585       inputs: []
23586     };
23587     findConstantAndWatchExpressions(ast, self.$filter);
23588     var extra = '';
23589     var assignable;
23590     this.stage = 'assign';
23591     if ((assignable = assignableAST(ast))) {
23592       this.state.computing = 'assign';
23593       var result = this.nextId();
23594       this.recurse(assignable, result);
23595       this.return_(result);
23596       extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
23597     }
23598     var toWatch = getInputs(ast.body);
23599     self.stage = 'inputs';
23600     forEach(toWatch, function(watch, key) {
23601       var fnKey = 'fn' + key;
23602       self.state[fnKey] = {vars: [], body: [], own: {}};
23603       self.state.computing = fnKey;
23604       var intoId = self.nextId();
23605       self.recurse(watch, intoId);
23606       self.return_(intoId);
23607       self.state.inputs.push(fnKey);
23608       watch.watchId = key;
23609     });
23610     this.state.computing = 'fn';
23611     this.stage = 'main';
23612     this.recurse(ast);
23613     var fnString =
23614       // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
23615       // This is a workaround for this until we do a better job at only removing the prefix only when we should.
23616       '"' + this.USE + ' ' + this.STRICT + '";\n' +
23617       this.filterPrefix() +
23618       'var fn=' + this.generateFunction('fn', 's,l,a,i') +
23619       extra +
23620       this.watchFns() +
23621       'return fn;';
23622
23623     /* jshint -W054 */
23624     var fn = (new Function('$filter',
23625         'ensureSafeMemberName',
23626         'ensureSafeObject',
23627         'ensureSafeFunction',
23628         'getStringValue',
23629         'ensureSafeAssignContext',
23630         'ifDefined',
23631         'plus',
23632         'text',
23633         fnString))(
23634           this.$filter,
23635           ensureSafeMemberName,
23636           ensureSafeObject,
23637           ensureSafeFunction,
23638           getStringValue,
23639           ensureSafeAssignContext,
23640           ifDefined,
23641           plusFn,
23642           expression);
23643     /* jshint +W054 */
23644     this.state = this.stage = undefined;
23645     fn.literal = isLiteral(ast);
23646     fn.constant = isConstant(ast);
23647     return fn;
23648   },
23649
23650   USE: 'use',
23651
23652   STRICT: 'strict',
23653
23654   watchFns: function() {
23655     var result = [];
23656     var fns = this.state.inputs;
23657     var self = this;
23658     forEach(fns, function(name) {
23659       result.push('var ' + name + '=' + self.generateFunction(name, 's'));
23660     });
23661     if (fns.length) {
23662       result.push('fn.inputs=[' + fns.join(',') + '];');
23663     }
23664     return result.join('');
23665   },
23666
23667   generateFunction: function(name, params) {
23668     return 'function(' + params + '){' +
23669         this.varsPrefix(name) +
23670         this.body(name) +
23671         '};';
23672   },
23673
23674   filterPrefix: function() {
23675     var parts = [];
23676     var self = this;
23677     forEach(this.state.filters, function(id, filter) {
23678       parts.push(id + '=$filter(' + self.escape(filter) + ')');
23679     });
23680     if (parts.length) return 'var ' + parts.join(',') + ';';
23681     return '';
23682   },
23683
23684   varsPrefix: function(section) {
23685     return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
23686   },
23687
23688   body: function(section) {
23689     return this.state[section].body.join('');
23690   },
23691
23692   recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
23693     var left, right, self = this, args, expression;
23694     recursionFn = recursionFn || noop;
23695     if (!skipWatchIdCheck && isDefined(ast.watchId)) {
23696       intoId = intoId || this.nextId();
23697       this.if_('i',
23698         this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
23699         this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
23700       );
23701       return;
23702     }
23703     switch (ast.type) {
23704     case AST.Program:
23705       forEach(ast.body, function(expression, pos) {
23706         self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
23707         if (pos !== ast.body.length - 1) {
23708           self.current().body.push(right, ';');
23709         } else {
23710           self.return_(right);
23711         }
23712       });
23713       break;
23714     case AST.Literal:
23715       expression = this.escape(ast.value);
23716       this.assign(intoId, expression);
23717       recursionFn(expression);
23718       break;
23719     case AST.UnaryExpression:
23720       this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
23721       expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
23722       this.assign(intoId, expression);
23723       recursionFn(expression);
23724       break;
23725     case AST.BinaryExpression:
23726       this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
23727       this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
23728       if (ast.operator === '+') {
23729         expression = this.plus(left, right);
23730       } else if (ast.operator === '-') {
23731         expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
23732       } else {
23733         expression = '(' + left + ')' + ast.operator + '(' + right + ')';
23734       }
23735       this.assign(intoId, expression);
23736       recursionFn(expression);
23737       break;
23738     case AST.LogicalExpression:
23739       intoId = intoId || this.nextId();
23740       self.recurse(ast.left, intoId);
23741       self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
23742       recursionFn(intoId);
23743       break;
23744     case AST.ConditionalExpression:
23745       intoId = intoId || this.nextId();
23746       self.recurse(ast.test, intoId);
23747       self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
23748       recursionFn(intoId);
23749       break;
23750     case AST.Identifier:
23751       intoId = intoId || this.nextId();
23752       if (nameId) {
23753         nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
23754         nameId.computed = false;
23755         nameId.name = ast.name;
23756       }
23757       ensureSafeMemberName(ast.name);
23758       self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
23759         function() {
23760           self.if_(self.stage === 'inputs' || 's', function() {
23761             if (create && create !== 1) {
23762               self.if_(
23763                 self.not(self.nonComputedMember('s', ast.name)),
23764                 self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
23765             }
23766             self.assign(intoId, self.nonComputedMember('s', ast.name));
23767           });
23768         }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
23769         );
23770       if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
23771         self.addEnsureSafeObject(intoId);
23772       }
23773       recursionFn(intoId);
23774       break;
23775     case AST.MemberExpression:
23776       left = nameId && (nameId.context = this.nextId()) || this.nextId();
23777       intoId = intoId || this.nextId();
23778       self.recurse(ast.object, left, undefined, function() {
23779         self.if_(self.notNull(left), function() {
23780           if (create && create !== 1) {
23781             self.addEnsureSafeAssignContext(left);
23782           }
23783           if (ast.computed) {
23784             right = self.nextId();
23785             self.recurse(ast.property, right);
23786             self.getStringValue(right);
23787             self.addEnsureSafeMemberName(right);
23788             if (create && create !== 1) {
23789               self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
23790             }
23791             expression = self.ensureSafeObject(self.computedMember(left, right));
23792             self.assign(intoId, expression);
23793             if (nameId) {
23794               nameId.computed = true;
23795               nameId.name = right;
23796             }
23797           } else {
23798             ensureSafeMemberName(ast.property.name);
23799             if (create && create !== 1) {
23800               self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
23801             }
23802             expression = self.nonComputedMember(left, ast.property.name);
23803             if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
23804               expression = self.ensureSafeObject(expression);
23805             }
23806             self.assign(intoId, expression);
23807             if (nameId) {
23808               nameId.computed = false;
23809               nameId.name = ast.property.name;
23810             }
23811           }
23812         }, function() {
23813           self.assign(intoId, 'undefined');
23814         });
23815         recursionFn(intoId);
23816       }, !!create);
23817       break;
23818     case AST.CallExpression:
23819       intoId = intoId || this.nextId();
23820       if (ast.filter) {
23821         right = self.filter(ast.callee.name);
23822         args = [];
23823         forEach(ast.arguments, function(expr) {
23824           var argument = self.nextId();
23825           self.recurse(expr, argument);
23826           args.push(argument);
23827         });
23828         expression = right + '(' + args.join(',') + ')';
23829         self.assign(intoId, expression);
23830         recursionFn(intoId);
23831       } else {
23832         right = self.nextId();
23833         left = {};
23834         args = [];
23835         self.recurse(ast.callee, right, left, function() {
23836           self.if_(self.notNull(right), function() {
23837             self.addEnsureSafeFunction(right);
23838             forEach(ast.arguments, function(expr) {
23839               self.recurse(expr, self.nextId(), undefined, function(argument) {
23840                 args.push(self.ensureSafeObject(argument));
23841               });
23842             });
23843             if (left.name) {
23844               if (!self.state.expensiveChecks) {
23845                 self.addEnsureSafeObject(left.context);
23846               }
23847               expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
23848             } else {
23849               expression = right + '(' + args.join(',') + ')';
23850             }
23851             expression = self.ensureSafeObject(expression);
23852             self.assign(intoId, expression);
23853           }, function() {
23854             self.assign(intoId, 'undefined');
23855           });
23856           recursionFn(intoId);
23857         });
23858       }
23859       break;
23860     case AST.AssignmentExpression:
23861       right = this.nextId();
23862       left = {};
23863       if (!isAssignable(ast.left)) {
23864         throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
23865       }
23866       this.recurse(ast.left, undefined, left, function() {
23867         self.if_(self.notNull(left.context), function() {
23868           self.recurse(ast.right, right);
23869           self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
23870           self.addEnsureSafeAssignContext(left.context);
23871           expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
23872           self.assign(intoId, expression);
23873           recursionFn(intoId || expression);
23874         });
23875       }, 1);
23876       break;
23877     case AST.ArrayExpression:
23878       args = [];
23879       forEach(ast.elements, function(expr) {
23880         self.recurse(expr, self.nextId(), undefined, function(argument) {
23881           args.push(argument);
23882         });
23883       });
23884       expression = '[' + args.join(',') + ']';
23885       this.assign(intoId, expression);
23886       recursionFn(expression);
23887       break;
23888     case AST.ObjectExpression:
23889       args = [];
23890       forEach(ast.properties, function(property) {
23891         self.recurse(property.value, self.nextId(), undefined, function(expr) {
23892           args.push(self.escape(
23893               property.key.type === AST.Identifier ? property.key.name :
23894                 ('' + property.key.value)) +
23895               ':' + expr);
23896         });
23897       });
23898       expression = '{' + args.join(',') + '}';
23899       this.assign(intoId, expression);
23900       recursionFn(expression);
23901       break;
23902     case AST.ThisExpression:
23903       this.assign(intoId, 's');
23904       recursionFn('s');
23905       break;
23906     case AST.LocalsExpression:
23907       this.assign(intoId, 'l');
23908       recursionFn('l');
23909       break;
23910     case AST.NGValueParameter:
23911       this.assign(intoId, 'v');
23912       recursionFn('v');
23913       break;
23914     }
23915   },
23916
23917   getHasOwnProperty: function(element, property) {
23918     var key = element + '.' + property;
23919     var own = this.current().own;
23920     if (!own.hasOwnProperty(key)) {
23921       own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
23922     }
23923     return own[key];
23924   },
23925
23926   assign: function(id, value) {
23927     if (!id) return;
23928     this.current().body.push(id, '=', value, ';');
23929     return id;
23930   },
23931
23932   filter: function(filterName) {
23933     if (!this.state.filters.hasOwnProperty(filterName)) {
23934       this.state.filters[filterName] = this.nextId(true);
23935     }
23936     return this.state.filters[filterName];
23937   },
23938
23939   ifDefined: function(id, defaultValue) {
23940     return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
23941   },
23942
23943   plus: function(left, right) {
23944     return 'plus(' + left + ',' + right + ')';
23945   },
23946
23947   return_: function(id) {
23948     this.current().body.push('return ', id, ';');
23949   },
23950
23951   if_: function(test, alternate, consequent) {
23952     if (test === true) {
23953       alternate();
23954     } else {
23955       var body = this.current().body;
23956       body.push('if(', test, '){');
23957       alternate();
23958       body.push('}');
23959       if (consequent) {
23960         body.push('else{');
23961         consequent();
23962         body.push('}');
23963       }
23964     }
23965   },
23966
23967   not: function(expression) {
23968     return '!(' + expression + ')';
23969   },
23970
23971   notNull: function(expression) {
23972     return expression + '!=null';
23973   },
23974
23975   nonComputedMember: function(left, right) {
23976     var SAFE_IDENTIFIER = /[$_a-zA-Z][$_a-zA-Z0-9]*/;
23977     var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
23978     if (SAFE_IDENTIFIER.test(right)) {
23979       return left + '.' + right;
23980     } else {
23981       return left  + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
23982     }
23983   },
23984
23985   computedMember: function(left, right) {
23986     return left + '[' + right + ']';
23987   },
23988
23989   member: function(left, right, computed) {
23990     if (computed) return this.computedMember(left, right);
23991     return this.nonComputedMember(left, right);
23992   },
23993
23994   addEnsureSafeObject: function(item) {
23995     this.current().body.push(this.ensureSafeObject(item), ';');
23996   },
23997
23998   addEnsureSafeMemberName: function(item) {
23999     this.current().body.push(this.ensureSafeMemberName(item), ';');
24000   },
24001
24002   addEnsureSafeFunction: function(item) {
24003     this.current().body.push(this.ensureSafeFunction(item), ';');
24004   },
24005
24006   addEnsureSafeAssignContext: function(item) {
24007     this.current().body.push(this.ensureSafeAssignContext(item), ';');
24008   },
24009
24010   ensureSafeObject: function(item) {
24011     return 'ensureSafeObject(' + item + ',text)';
24012   },
24013
24014   ensureSafeMemberName: function(item) {
24015     return 'ensureSafeMemberName(' + item + ',text)';
24016   },
24017
24018   ensureSafeFunction: function(item) {
24019     return 'ensureSafeFunction(' + item + ',text)';
24020   },
24021
24022   getStringValue: function(item) {
24023     this.assign(item, 'getStringValue(' + item + ')');
24024   },
24025
24026   ensureSafeAssignContext: function(item) {
24027     return 'ensureSafeAssignContext(' + item + ',text)';
24028   },
24029
24030   lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
24031     var self = this;
24032     return function() {
24033       self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
24034     };
24035   },
24036
24037   lazyAssign: function(id, value) {
24038     var self = this;
24039     return function() {
24040       self.assign(id, value);
24041     };
24042   },
24043
24044   stringEscapeRegex: /[^ a-zA-Z0-9]/g,
24045
24046   stringEscapeFn: function(c) {
24047     return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
24048   },
24049
24050   escape: function(value) {
24051     if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
24052     if (isNumber(value)) return value.toString();
24053     if (value === true) return 'true';
24054     if (value === false) return 'false';
24055     if (value === null) return 'null';
24056     if (typeof value === 'undefined') return 'undefined';
24057
24058     throw $parseMinErr('esc', 'IMPOSSIBLE');
24059   },
24060
24061   nextId: function(skip, init) {
24062     var id = 'v' + (this.state.nextId++);
24063     if (!skip) {
24064       this.current().vars.push(id + (init ? '=' + init : ''));
24065     }
24066     return id;
24067   },
24068
24069   current: function() {
24070     return this.state[this.state.computing];
24071   }
24072 };
24073
24074
24075 function ASTInterpreter(astBuilder, $filter) {
24076   this.astBuilder = astBuilder;
24077   this.$filter = $filter;
24078 }
24079
24080 ASTInterpreter.prototype = {
24081   compile: function(expression, expensiveChecks) {
24082     var self = this;
24083     var ast = this.astBuilder.ast(expression);
24084     this.expression = expression;
24085     this.expensiveChecks = expensiveChecks;
24086     findConstantAndWatchExpressions(ast, self.$filter);
24087     var assignable;
24088     var assign;
24089     if ((assignable = assignableAST(ast))) {
24090       assign = this.recurse(assignable);
24091     }
24092     var toWatch = getInputs(ast.body);
24093     var inputs;
24094     if (toWatch) {
24095       inputs = [];
24096       forEach(toWatch, function(watch, key) {
24097         var input = self.recurse(watch);
24098         watch.input = input;
24099         inputs.push(input);
24100         watch.watchId = key;
24101       });
24102     }
24103     var expressions = [];
24104     forEach(ast.body, function(expression) {
24105       expressions.push(self.recurse(expression.expression));
24106     });
24107     var fn = ast.body.length === 0 ? noop :
24108              ast.body.length === 1 ? expressions[0] :
24109              function(scope, locals) {
24110                var lastValue;
24111                forEach(expressions, function(exp) {
24112                  lastValue = exp(scope, locals);
24113                });
24114                return lastValue;
24115              };
24116     if (assign) {
24117       fn.assign = function(scope, value, locals) {
24118         return assign(scope, locals, value);
24119       };
24120     }
24121     if (inputs) {
24122       fn.inputs = inputs;
24123     }
24124     fn.literal = isLiteral(ast);
24125     fn.constant = isConstant(ast);
24126     return fn;
24127   },
24128
24129   recurse: function(ast, context, create) {
24130     var left, right, self = this, args, expression;
24131     if (ast.input) {
24132       return this.inputs(ast.input, ast.watchId);
24133     }
24134     switch (ast.type) {
24135     case AST.Literal:
24136       return this.value(ast.value, context);
24137     case AST.UnaryExpression:
24138       right = this.recurse(ast.argument);
24139       return this['unary' + ast.operator](right, context);
24140     case AST.BinaryExpression:
24141       left = this.recurse(ast.left);
24142       right = this.recurse(ast.right);
24143       return this['binary' + ast.operator](left, right, context);
24144     case AST.LogicalExpression:
24145       left = this.recurse(ast.left);
24146       right = this.recurse(ast.right);
24147       return this['binary' + ast.operator](left, right, context);
24148     case AST.ConditionalExpression:
24149       return this['ternary?:'](
24150         this.recurse(ast.test),
24151         this.recurse(ast.alternate),
24152         this.recurse(ast.consequent),
24153         context
24154       );
24155     case AST.Identifier:
24156       ensureSafeMemberName(ast.name, self.expression);
24157       return self.identifier(ast.name,
24158                              self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
24159                              context, create, self.expression);
24160     case AST.MemberExpression:
24161       left = this.recurse(ast.object, false, !!create);
24162       if (!ast.computed) {
24163         ensureSafeMemberName(ast.property.name, self.expression);
24164         right = ast.property.name;
24165       }
24166       if (ast.computed) right = this.recurse(ast.property);
24167       return ast.computed ?
24168         this.computedMember(left, right, context, create, self.expression) :
24169         this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
24170     case AST.CallExpression:
24171       args = [];
24172       forEach(ast.arguments, function(expr) {
24173         args.push(self.recurse(expr));
24174       });
24175       if (ast.filter) right = this.$filter(ast.callee.name);
24176       if (!ast.filter) right = this.recurse(ast.callee, true);
24177       return ast.filter ?
24178         function(scope, locals, assign, inputs) {
24179           var values = [];
24180           for (var i = 0; i < args.length; ++i) {
24181             values.push(args[i](scope, locals, assign, inputs));
24182           }
24183           var value = right.apply(undefined, values, inputs);
24184           return context ? {context: undefined, name: undefined, value: value} : value;
24185         } :
24186         function(scope, locals, assign, inputs) {
24187           var rhs = right(scope, locals, assign, inputs);
24188           var value;
24189           if (rhs.value != null) {
24190             ensureSafeObject(rhs.context, self.expression);
24191             ensureSafeFunction(rhs.value, self.expression);
24192             var values = [];
24193             for (var i = 0; i < args.length; ++i) {
24194               values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
24195             }
24196             value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
24197           }
24198           return context ? {value: value} : value;
24199         };
24200     case AST.AssignmentExpression:
24201       left = this.recurse(ast.left, true, 1);
24202       right = this.recurse(ast.right);
24203       return function(scope, locals, assign, inputs) {
24204         var lhs = left(scope, locals, assign, inputs);
24205         var rhs = right(scope, locals, assign, inputs);
24206         ensureSafeObject(lhs.value, self.expression);
24207         ensureSafeAssignContext(lhs.context);
24208         lhs.context[lhs.name] = rhs;
24209         return context ? {value: rhs} : rhs;
24210       };
24211     case AST.ArrayExpression:
24212       args = [];
24213       forEach(ast.elements, function(expr) {
24214         args.push(self.recurse(expr));
24215       });
24216       return function(scope, locals, assign, inputs) {
24217         var value = [];
24218         for (var i = 0; i < args.length; ++i) {
24219           value.push(args[i](scope, locals, assign, inputs));
24220         }
24221         return context ? {value: value} : value;
24222       };
24223     case AST.ObjectExpression:
24224       args = [];
24225       forEach(ast.properties, function(property) {
24226         args.push({key: property.key.type === AST.Identifier ?
24227                         property.key.name :
24228                         ('' + property.key.value),
24229                    value: self.recurse(property.value)
24230         });
24231       });
24232       return function(scope, locals, assign, inputs) {
24233         var value = {};
24234         for (var i = 0; i < args.length; ++i) {
24235           value[args[i].key] = args[i].value(scope, locals, assign, inputs);
24236         }
24237         return context ? {value: value} : value;
24238       };
24239     case AST.ThisExpression:
24240       return function(scope) {
24241         return context ? {value: scope} : scope;
24242       };
24243     case AST.LocalsExpression:
24244       return function(scope, locals) {
24245         return context ? {value: locals} : locals;
24246       };
24247     case AST.NGValueParameter:
24248       return function(scope, locals, assign) {
24249         return context ? {value: assign} : assign;
24250       };
24251     }
24252   },
24253
24254   'unary+': function(argument, context) {
24255     return function(scope, locals, assign, inputs) {
24256       var arg = argument(scope, locals, assign, inputs);
24257       if (isDefined(arg)) {
24258         arg = +arg;
24259       } else {
24260         arg = 0;
24261       }
24262       return context ? {value: arg} : arg;
24263     };
24264   },
24265   'unary-': function(argument, context) {
24266     return function(scope, locals, assign, inputs) {
24267       var arg = argument(scope, locals, assign, inputs);
24268       if (isDefined(arg)) {
24269         arg = -arg;
24270       } else {
24271         arg = 0;
24272       }
24273       return context ? {value: arg} : arg;
24274     };
24275   },
24276   'unary!': function(argument, context) {
24277     return function(scope, locals, assign, inputs) {
24278       var arg = !argument(scope, locals, assign, inputs);
24279       return context ? {value: arg} : arg;
24280     };
24281   },
24282   'binary+': function(left, right, context) {
24283     return function(scope, locals, assign, inputs) {
24284       var lhs = left(scope, locals, assign, inputs);
24285       var rhs = right(scope, locals, assign, inputs);
24286       var arg = plusFn(lhs, rhs);
24287       return context ? {value: arg} : arg;
24288     };
24289   },
24290   'binary-': function(left, right, context) {
24291     return function(scope, locals, assign, inputs) {
24292       var lhs = left(scope, locals, assign, inputs);
24293       var rhs = right(scope, locals, assign, inputs);
24294       var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
24295       return context ? {value: arg} : arg;
24296     };
24297   },
24298   'binary*': function(left, right, context) {
24299     return function(scope, locals, assign, inputs) {
24300       var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
24301       return context ? {value: arg} : arg;
24302     };
24303   },
24304   'binary/': function(left, right, context) {
24305     return function(scope, locals, assign, inputs) {
24306       var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
24307       return context ? {value: arg} : arg;
24308     };
24309   },
24310   'binary%': function(left, right, context) {
24311     return function(scope, locals, assign, inputs) {
24312       var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
24313       return context ? {value: arg} : arg;
24314     };
24315   },
24316   'binary===': function(left, right, context) {
24317     return function(scope, locals, assign, inputs) {
24318       var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
24319       return context ? {value: arg} : arg;
24320     };
24321   },
24322   'binary!==': function(left, right, context) {
24323     return function(scope, locals, assign, inputs) {
24324       var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
24325       return context ? {value: arg} : arg;
24326     };
24327   },
24328   'binary==': function(left, right, context) {
24329     return function(scope, locals, assign, inputs) {
24330       var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
24331       return context ? {value: arg} : arg;
24332     };
24333   },
24334   'binary!=': function(left, right, context) {
24335     return function(scope, locals, assign, inputs) {
24336       var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
24337       return context ? {value: arg} : arg;
24338     };
24339   },
24340   'binary<': function(left, right, context) {
24341     return function(scope, locals, assign, inputs) {
24342       var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
24343       return context ? {value: arg} : arg;
24344     };
24345   },
24346   'binary>': function(left, right, context) {
24347     return function(scope, locals, assign, inputs) {
24348       var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
24349       return context ? {value: arg} : arg;
24350     };
24351   },
24352   'binary<=': function(left, right, context) {
24353     return function(scope, locals, assign, inputs) {
24354       var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
24355       return context ? {value: arg} : arg;
24356     };
24357   },
24358   'binary>=': function(left, right, context) {
24359     return function(scope, locals, assign, inputs) {
24360       var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
24361       return context ? {value: arg} : arg;
24362     };
24363   },
24364   'binary&&': function(left, right, context) {
24365     return function(scope, locals, assign, inputs) {
24366       var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
24367       return context ? {value: arg} : arg;
24368     };
24369   },
24370   'binary||': function(left, right, context) {
24371     return function(scope, locals, assign, inputs) {
24372       var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
24373       return context ? {value: arg} : arg;
24374     };
24375   },
24376   'ternary?:': function(test, alternate, consequent, context) {
24377     return function(scope, locals, assign, inputs) {
24378       var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
24379       return context ? {value: arg} : arg;
24380     };
24381   },
24382   value: function(value, context) {
24383     return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
24384   },
24385   identifier: function(name, expensiveChecks, context, create, expression) {
24386     return function(scope, locals, assign, inputs) {
24387       var base = locals && (name in locals) ? locals : scope;
24388       if (create && create !== 1 && base && !(base[name])) {
24389         base[name] = {};
24390       }
24391       var value = base ? base[name] : undefined;
24392       if (expensiveChecks) {
24393         ensureSafeObject(value, expression);
24394       }
24395       if (context) {
24396         return {context: base, name: name, value: value};
24397       } else {
24398         return value;
24399       }
24400     };
24401   },
24402   computedMember: function(left, right, context, create, expression) {
24403     return function(scope, locals, assign, inputs) {
24404       var lhs = left(scope, locals, assign, inputs);
24405       var rhs;
24406       var value;
24407       if (lhs != null) {
24408         rhs = right(scope, locals, assign, inputs);
24409         rhs = getStringValue(rhs);
24410         ensureSafeMemberName(rhs, expression);
24411         if (create && create !== 1) {
24412           ensureSafeAssignContext(lhs);
24413           if (lhs && !(lhs[rhs])) {
24414             lhs[rhs] = {};
24415           }
24416         }
24417         value = lhs[rhs];
24418         ensureSafeObject(value, expression);
24419       }
24420       if (context) {
24421         return {context: lhs, name: rhs, value: value};
24422       } else {
24423         return value;
24424       }
24425     };
24426   },
24427   nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
24428     return function(scope, locals, assign, inputs) {
24429       var lhs = left(scope, locals, assign, inputs);
24430       if (create && create !== 1) {
24431         ensureSafeAssignContext(lhs);
24432         if (lhs && !(lhs[right])) {
24433           lhs[right] = {};
24434         }
24435       }
24436       var value = lhs != null ? lhs[right] : undefined;
24437       if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
24438         ensureSafeObject(value, expression);
24439       }
24440       if (context) {
24441         return {context: lhs, name: right, value: value};
24442       } else {
24443         return value;
24444       }
24445     };
24446   },
24447   inputs: function(input, watchId) {
24448     return function(scope, value, locals, inputs) {
24449       if (inputs) return inputs[watchId];
24450       return input(scope, value, locals);
24451     };
24452   }
24453 };
24454
24455 /**
24456  * @constructor
24457  */
24458 var Parser = function(lexer, $filter, options) {
24459   this.lexer = lexer;
24460   this.$filter = $filter;
24461   this.options = options;
24462   this.ast = new AST(lexer, options);
24463   this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
24464                                    new ASTCompiler(this.ast, $filter);
24465 };
24466
24467 Parser.prototype = {
24468   constructor: Parser,
24469
24470   parse: function(text) {
24471     return this.astCompiler.compile(text, this.options.expensiveChecks);
24472   }
24473 };
24474
24475 function isPossiblyDangerousMemberName(name) {
24476   return name == 'constructor';
24477 }
24478
24479 var objectValueOf = Object.prototype.valueOf;
24480
24481 function getValueOf(value) {
24482   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
24483 }
24484
24485 ///////////////////////////////////
24486
24487 /**
24488  * @ngdoc service
24489  * @name $parse
24490  * @kind function
24491  *
24492  * @description
24493  *
24494  * Converts Angular {@link guide/expression expression} into a function.
24495  *
24496  * ```js
24497  *   var getter = $parse('user.name');
24498  *   var setter = getter.assign;
24499  *   var context = {user:{name:'angular'}};
24500  *   var locals = {user:{name:'local'}};
24501  *
24502  *   expect(getter(context)).toEqual('angular');
24503  *   setter(context, 'newValue');
24504  *   expect(context.user.name).toEqual('newValue');
24505  *   expect(getter(context, locals)).toEqual('local');
24506  * ```
24507  *
24508  *
24509  * @param {string} expression String expression to compile.
24510  * @returns {function(context, locals)} a function which represents the compiled expression:
24511  *
24512  *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
24513  *      are evaluated against (typically a scope object).
24514  *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
24515  *      `context`.
24516  *
24517  *    The returned function also has the following properties:
24518  *      * `literal` â€“ `{boolean}` â€“ whether the expression's top-level node is a JavaScript
24519  *        literal.
24520  *      * `constant` â€“ `{boolean}` â€“ whether the expression is made entirely of JavaScript
24521  *        constant literals.
24522  *      * `assign` â€“ `{?function(context, value)}` â€“ if the expression is assignable, this will be
24523  *        set to a function to change its value on the given context.
24524  *
24525  */
24526
24527
24528 /**
24529  * @ngdoc provider
24530  * @name $parseProvider
24531  *
24532  * @description
24533  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
24534  *  service.
24535  */
24536 function $ParseProvider() {
24537   var cacheDefault = createMap();
24538   var cacheExpensive = createMap();
24539   var literals = {
24540     'true': true,
24541     'false': false,
24542     'null': null,
24543     'undefined': undefined
24544   };
24545   var identStart, identContinue;
24546
24547   /**
24548    * @ngdoc method
24549    * @name $parseProvider#addLiteral
24550    * @description
24551    *
24552    * Configure $parse service to add literal values that will be present as literal at expressions.
24553    *
24554    * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
24555    * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
24556    *
24557    **/
24558   this.addLiteral = function(literalName, literalValue) {
24559     literals[literalName] = literalValue;
24560   };
24561
24562  /**
24563   * @ngdoc method
24564   * @name $parseProvider#setIdentifierFns
24565   * @description
24566   *
24567   * Allows defining the set of characters that are allowed in Angular expressions. The function
24568   * `identifierStart` will get called to know if a given character is a valid character to be the
24569   * first character for an identifier. The function `identifierContinue` will get called to know if
24570   * a given character is a valid character to be a follow-up identifier character. The functions
24571   * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
24572   * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
24573   * mind that the `string` parameter can be two characters long depending on the character
24574   * representation. It is expected for the function to return `true` or `false`, whether that
24575   * character is allowed or not.
24576   *
24577   * Since this function will be called extensivelly, keep the implementation of these functions fast,
24578   * as the performance of these functions have a direct impact on the expressions parsing speed.
24579   *
24580   * @param {function=} identifierStart The function that will decide whether the given character is
24581   *   a valid identifier start character.
24582   * @param {function=} identifierContinue The function that will decide whether the given character is
24583   *   a valid identifier continue character.
24584   */
24585   this.setIdentifierFns = function(identifierStart, identifierContinue) {
24586     identStart = identifierStart;
24587     identContinue = identifierContinue;
24588     return this;
24589   };
24590
24591   this.$get = ['$filter', function($filter) {
24592     var noUnsafeEval = csp().noUnsafeEval;
24593     var $parseOptions = {
24594           csp: noUnsafeEval,
24595           expensiveChecks: false,
24596           literals: copy(literals),
24597           isIdentifierStart: isFunction(identStart) && identStart,
24598           isIdentifierContinue: isFunction(identContinue) && identContinue
24599         },
24600         $parseOptionsExpensive = {
24601           csp: noUnsafeEval,
24602           expensiveChecks: true,
24603           literals: copy(literals),
24604           isIdentifierStart: isFunction(identStart) && identStart,
24605           isIdentifierContinue: isFunction(identContinue) && identContinue
24606         };
24607     var runningChecksEnabled = false;
24608
24609     $parse.$$runningExpensiveChecks = function() {
24610       return runningChecksEnabled;
24611     };
24612
24613     return $parse;
24614
24615     function $parse(exp, interceptorFn, expensiveChecks) {
24616       var parsedExpression, oneTime, cacheKey;
24617
24618       expensiveChecks = expensiveChecks || runningChecksEnabled;
24619
24620       switch (typeof exp) {
24621         case 'string':
24622           exp = exp.trim();
24623           cacheKey = exp;
24624
24625           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
24626           parsedExpression = cache[cacheKey];
24627
24628           if (!parsedExpression) {
24629             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
24630               oneTime = true;
24631               exp = exp.substring(2);
24632             }
24633             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
24634             var lexer = new Lexer(parseOptions);
24635             var parser = new Parser(lexer, $filter, parseOptions);
24636             parsedExpression = parser.parse(exp);
24637             if (parsedExpression.constant) {
24638               parsedExpression.$$watchDelegate = constantWatchDelegate;
24639             } else if (oneTime) {
24640               parsedExpression.$$watchDelegate = parsedExpression.literal ?
24641                   oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
24642             } else if (parsedExpression.inputs) {
24643               parsedExpression.$$watchDelegate = inputsWatchDelegate;
24644             }
24645             if (expensiveChecks) {
24646               parsedExpression = expensiveChecksInterceptor(parsedExpression);
24647             }
24648             cache[cacheKey] = parsedExpression;
24649           }
24650           return addInterceptor(parsedExpression, interceptorFn);
24651
24652         case 'function':
24653           return addInterceptor(exp, interceptorFn);
24654
24655         default:
24656           return addInterceptor(noop, interceptorFn);
24657       }
24658     }
24659
24660     function expensiveChecksInterceptor(fn) {
24661       if (!fn) return fn;
24662       expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
24663       expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
24664       expensiveCheckFn.constant = fn.constant;
24665       expensiveCheckFn.literal = fn.literal;
24666       for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
24667         fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
24668       }
24669       expensiveCheckFn.inputs = fn.inputs;
24670
24671       return expensiveCheckFn;
24672
24673       function expensiveCheckFn(scope, locals, assign, inputs) {
24674         var expensiveCheckOldValue = runningChecksEnabled;
24675         runningChecksEnabled = true;
24676         try {
24677           return fn(scope, locals, assign, inputs);
24678         } finally {
24679           runningChecksEnabled = expensiveCheckOldValue;
24680         }
24681       }
24682     }
24683
24684     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
24685
24686       if (newValue == null || oldValueOfValue == null) { // null/undefined
24687         return newValue === oldValueOfValue;
24688       }
24689
24690       if (typeof newValue === 'object') {
24691
24692         // attempt to convert the value to a primitive type
24693         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
24694         //             be cheaply dirty-checked
24695         newValue = getValueOf(newValue);
24696
24697         if (typeof newValue === 'object') {
24698           // objects/arrays are not supported - deep-watching them would be too expensive
24699           return false;
24700         }
24701
24702         // fall-through to the primitive equality check
24703       }
24704
24705       //Primitive or NaN
24706       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
24707     }
24708
24709     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
24710       var inputExpressions = parsedExpression.inputs;
24711       var lastResult;
24712
24713       if (inputExpressions.length === 1) {
24714         var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
24715         inputExpressions = inputExpressions[0];
24716         return scope.$watch(function expressionInputWatch(scope) {
24717           var newInputValue = inputExpressions(scope);
24718           if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
24719             lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
24720             oldInputValueOf = newInputValue && getValueOf(newInputValue);
24721           }
24722           return lastResult;
24723         }, listener, objectEquality, prettyPrintExpression);
24724       }
24725
24726       var oldInputValueOfValues = [];
24727       var oldInputValues = [];
24728       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
24729         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
24730         oldInputValues[i] = null;
24731       }
24732
24733       return scope.$watch(function expressionInputsWatch(scope) {
24734         var changed = false;
24735
24736         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
24737           var newInputValue = inputExpressions[i](scope);
24738           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
24739             oldInputValues[i] = newInputValue;
24740             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
24741           }
24742         }
24743
24744         if (changed) {
24745           lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
24746         }
24747
24748         return lastResult;
24749       }, listener, objectEquality, prettyPrintExpression);
24750     }
24751
24752     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24753       var unwatch, lastValue;
24754       return unwatch = scope.$watch(function oneTimeWatch(scope) {
24755         return parsedExpression(scope);
24756       }, function oneTimeListener(value, old, scope) {
24757         lastValue = value;
24758         if (isFunction(listener)) {
24759           listener.apply(this, arguments);
24760         }
24761         if (isDefined(value)) {
24762           scope.$$postDigest(function() {
24763             if (isDefined(lastValue)) {
24764               unwatch();
24765             }
24766           });
24767         }
24768       }, objectEquality);
24769     }
24770
24771     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24772       var unwatch, lastValue;
24773       return unwatch = scope.$watch(function oneTimeWatch(scope) {
24774         return parsedExpression(scope);
24775       }, function oneTimeListener(value, old, scope) {
24776         lastValue = value;
24777         if (isFunction(listener)) {
24778           listener.call(this, value, old, scope);
24779         }
24780         if (isAllDefined(value)) {
24781           scope.$$postDigest(function() {
24782             if (isAllDefined(lastValue)) unwatch();
24783           });
24784         }
24785       }, objectEquality);
24786
24787       function isAllDefined(value) {
24788         var allDefined = true;
24789         forEach(value, function(val) {
24790           if (!isDefined(val)) allDefined = false;
24791         });
24792         return allDefined;
24793       }
24794     }
24795
24796     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24797       var unwatch;
24798       return unwatch = scope.$watch(function constantWatch(scope) {
24799         unwatch();
24800         return parsedExpression(scope);
24801       }, listener, objectEquality);
24802     }
24803
24804     function addInterceptor(parsedExpression, interceptorFn) {
24805       if (!interceptorFn) return parsedExpression;
24806       var watchDelegate = parsedExpression.$$watchDelegate;
24807       var useInputs = false;
24808
24809       var regularWatch =
24810           watchDelegate !== oneTimeLiteralWatchDelegate &&
24811           watchDelegate !== oneTimeWatchDelegate;
24812
24813       var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
24814         var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
24815         return interceptorFn(value, scope, locals);
24816       } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
24817         var value = parsedExpression(scope, locals, assign, inputs);
24818         var result = interceptorFn(value, scope, locals);
24819         // we only return the interceptor's result if the
24820         // initial value is defined (for bind-once)
24821         return isDefined(value) ? result : value;
24822       };
24823
24824       // Propagate $$watchDelegates other then inputsWatchDelegate
24825       if (parsedExpression.$$watchDelegate &&
24826           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
24827         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
24828       } else if (!interceptorFn.$stateful) {
24829         // If there is an interceptor, but no watchDelegate then treat the interceptor like
24830         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
24831         fn.$$watchDelegate = inputsWatchDelegate;
24832         useInputs = !parsedExpression.inputs;
24833         fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
24834       }
24835
24836       return fn;
24837     }
24838   }];
24839 }
24840
24841 /**
24842  * @ngdoc service
24843  * @name $q
24844  * @requires $rootScope
24845  *
24846  * @description
24847  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
24848  * when they are done processing.
24849  *
24850  * This is an implementation of promises/deferred objects inspired by
24851  * [Kris Kowal's Q](https://github.com/kriskowal/q).
24852  *
24853  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
24854  * implementations, and the other which resembles ES6 (ES2015) promises to some degree.
24855  *
24856  * # $q constructor
24857  *
24858  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
24859  * function as the first argument. This is similar to the native Promise implementation from ES6,
24860  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
24861  *
24862  * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
24863  * available yet.
24864  *
24865  * It can be used like so:
24866  *
24867  * ```js
24868  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
24869  *   // are available in the current lexical scope (they could have been injected or passed in).
24870  *
24871  *   function asyncGreet(name) {
24872  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
24873  *     return $q(function(resolve, reject) {
24874  *       setTimeout(function() {
24875  *         if (okToGreet(name)) {
24876  *           resolve('Hello, ' + name + '!');
24877  *         } else {
24878  *           reject('Greeting ' + name + ' is not allowed.');
24879  *         }
24880  *       }, 1000);
24881  *     });
24882  *   }
24883  *
24884  *   var promise = asyncGreet('Robin Hood');
24885  *   promise.then(function(greeting) {
24886  *     alert('Success: ' + greeting);
24887  *   }, function(reason) {
24888  *     alert('Failed: ' + reason);
24889  *   });
24890  * ```
24891  *
24892  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
24893  *
24894  * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
24895  *
24896  * However, the more traditional CommonJS-style usage is still available, and documented below.
24897  *
24898  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
24899  * interface for interacting with an object that represents the result of an action that is
24900  * performed asynchronously, and may or may not be finished at any given point in time.
24901  *
24902  * From the perspective of dealing with error handling, deferred and promise APIs are to
24903  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
24904  *
24905  * ```js
24906  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
24907  *   // are available in the current lexical scope (they could have been injected or passed in).
24908  *
24909  *   function asyncGreet(name) {
24910  *     var deferred = $q.defer();
24911  *
24912  *     setTimeout(function() {
24913  *       deferred.notify('About to greet ' + name + '.');
24914  *
24915  *       if (okToGreet(name)) {
24916  *         deferred.resolve('Hello, ' + name + '!');
24917  *       } else {
24918  *         deferred.reject('Greeting ' + name + ' is not allowed.');
24919  *       }
24920  *     }, 1000);
24921  *
24922  *     return deferred.promise;
24923  *   }
24924  *
24925  *   var promise = asyncGreet('Robin Hood');
24926  *   promise.then(function(greeting) {
24927  *     alert('Success: ' + greeting);
24928  *   }, function(reason) {
24929  *     alert('Failed: ' + reason);
24930  *   }, function(update) {
24931  *     alert('Got notification: ' + update);
24932  *   });
24933  * ```
24934  *
24935  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
24936  * comes in the way of guarantees that promise and deferred APIs make, see
24937  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
24938  *
24939  * Additionally the promise api allows for composition that is very hard to do with the
24940  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
24941  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
24942  * section on serial or parallel joining of promises.
24943  *
24944  * # The Deferred API
24945  *
24946  * A new instance of deferred is constructed by calling `$q.defer()`.
24947  *
24948  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
24949  * that can be used for signaling the successful or unsuccessful completion, as well as the status
24950  * of the task.
24951  *
24952  * **Methods**
24953  *
24954  * - `resolve(value)` â€“ resolves the derived promise with the `value`. If the value is a rejection
24955  *   constructed via `$q.reject`, the promise will be rejected instead.
24956  * - `reject(reason)` â€“ rejects the derived promise with the `reason`. This is equivalent to
24957  *   resolving it with a rejection constructed via `$q.reject`.
24958  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
24959  *   multiple times before the promise is either resolved or rejected.
24960  *
24961  * **Properties**
24962  *
24963  * - promise â€“ `{Promise}` â€“ promise object associated with this deferred.
24964  *
24965  *
24966  * # The Promise API
24967  *
24968  * A new promise instance is created when a deferred instance is created and can be retrieved by
24969  * calling `deferred.promise`.
24970  *
24971  * The purpose of the promise object is to allow for interested parties to get access to the result
24972  * of the deferred task when it completes.
24973  *
24974  * **Methods**
24975  *
24976  * - `then(successCallback, errorCallback, notifyCallback)` â€“ regardless of when the promise was or
24977  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
24978  *   as soon as the result is available. The callbacks are called with a single argument: the result
24979  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
24980  *   provide a progress indication, before the promise is resolved or rejected.
24981  *
24982  *   This method *returns a new promise* which is resolved or rejected via the return value of the
24983  *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
24984  *   with the value which is resolved in that promise using
24985  *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
24986  *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
24987  *   resolved or rejected from the notifyCallback method.
24988  *
24989  * - `catch(errorCallback)` â€“ shorthand for `promise.then(null, errorCallback)`
24990  *
24991  * - `finally(callback, notifyCallback)` â€“ allows you to observe either the fulfillment or rejection of a promise,
24992  *   but to do so without modifying the final value. This is useful to release resources or do some
24993  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
24994  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
24995  *   more information.
24996  *
24997  * # Chaining promises
24998  *
24999  * Because calling the `then` method of a promise returns a new derived promise, it is easily
25000  * possible to create a chain of promises:
25001  *
25002  * ```js
25003  *   promiseB = promiseA.then(function(result) {
25004  *     return result + 1;
25005  *   });
25006  *
25007  *   // promiseB will be resolved immediately after promiseA is resolved and its value
25008  *   // will be the result of promiseA incremented by 1
25009  * ```
25010  *
25011  * It is possible to create chains of any length and since a promise can be resolved with another
25012  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
25013  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
25014  * $http's response interceptors.
25015  *
25016  *
25017  * # Differences between Kris Kowal's Q and $q
25018  *
25019  *  There are two main differences:
25020  *
25021  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
25022  *   mechanism in angular, which means faster propagation of resolution or rejection into your
25023  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
25024  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
25025  *   all the important functionality needed for common async tasks.
25026  *
25027  * # Testing
25028  *
25029  *  ```js
25030  *    it('should simulate promise', inject(function($q, $rootScope) {
25031  *      var deferred = $q.defer();
25032  *      var promise = deferred.promise;
25033  *      var resolvedValue;
25034  *
25035  *      promise.then(function(value) { resolvedValue = value; });
25036  *      expect(resolvedValue).toBeUndefined();
25037  *
25038  *      // Simulate resolving of promise
25039  *      deferred.resolve(123);
25040  *      // Note that the 'then' function does not get called synchronously.
25041  *      // This is because we want the promise API to always be async, whether or not
25042  *      // it got called synchronously or asynchronously.
25043  *      expect(resolvedValue).toBeUndefined();
25044  *
25045  *      // Propagate promise resolution to 'then' functions using $apply().
25046  *      $rootScope.$apply();
25047  *      expect(resolvedValue).toEqual(123);
25048  *    }));
25049  *  ```
25050  *
25051  * @param {function(function, function)} resolver Function which is responsible for resolving or
25052  *   rejecting the newly created promise. The first parameter is a function which resolves the
25053  *   promise, the second parameter is a function which rejects the promise.
25054  *
25055  * @returns {Promise} The newly created promise.
25056  */
25057 function $QProvider() {
25058
25059   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
25060     return qFactory(function(callback) {
25061       $rootScope.$evalAsync(callback);
25062     }, $exceptionHandler);
25063   }];
25064 }
25065
25066 function $$QProvider() {
25067   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
25068     return qFactory(function(callback) {
25069       $browser.defer(callback);
25070     }, $exceptionHandler);
25071   }];
25072 }
25073
25074 /**
25075  * Constructs a promise manager.
25076  *
25077  * @param {function(function)} nextTick Function for executing functions in the next turn.
25078  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
25079  *     debugging purposes.
25080  * @returns {object} Promise manager.
25081  */
25082 function qFactory(nextTick, exceptionHandler) {
25083   var $qMinErr = minErr('$q', TypeError);
25084
25085   /**
25086    * @ngdoc method
25087    * @name ng.$q#defer
25088    * @kind function
25089    *
25090    * @description
25091    * Creates a `Deferred` object which represents a task which will finish in the future.
25092    *
25093    * @returns {Deferred} Returns a new instance of deferred.
25094    */
25095   var defer = function() {
25096     var d = new Deferred();
25097     //Necessary to support unbound execution :/
25098     d.resolve = simpleBind(d, d.resolve);
25099     d.reject = simpleBind(d, d.reject);
25100     d.notify = simpleBind(d, d.notify);
25101     return d;
25102   };
25103
25104   function Promise() {
25105     this.$$state = { status: 0 };
25106   }
25107
25108   extend(Promise.prototype, {
25109     then: function(onFulfilled, onRejected, progressBack) {
25110       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
25111         return this;
25112       }
25113       var result = new Deferred();
25114
25115       this.$$state.pending = this.$$state.pending || [];
25116       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
25117       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
25118
25119       return result.promise;
25120     },
25121
25122     "catch": function(callback) {
25123       return this.then(null, callback);
25124     },
25125
25126     "finally": function(callback, progressBack) {
25127       return this.then(function(value) {
25128         return handleCallback(value, true, callback);
25129       }, function(error) {
25130         return handleCallback(error, false, callback);
25131       }, progressBack);
25132     }
25133   });
25134
25135   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
25136   function simpleBind(context, fn) {
25137     return function(value) {
25138       fn.call(context, value);
25139     };
25140   }
25141
25142   function processQueue(state) {
25143     var fn, deferred, pending;
25144
25145     pending = state.pending;
25146     state.processScheduled = false;
25147     state.pending = undefined;
25148     for (var i = 0, ii = pending.length; i < ii; ++i) {
25149       deferred = pending[i][0];
25150       fn = pending[i][state.status];
25151       try {
25152         if (isFunction(fn)) {
25153           deferred.resolve(fn(state.value));
25154         } else if (state.status === 1) {
25155           deferred.resolve(state.value);
25156         } else {
25157           deferred.reject(state.value);
25158         }
25159       } catch (e) {
25160         deferred.reject(e);
25161         exceptionHandler(e);
25162       }
25163     }
25164   }
25165
25166   function scheduleProcessQueue(state) {
25167     if (state.processScheduled || !state.pending) return;
25168     state.processScheduled = true;
25169     nextTick(function() { processQueue(state); });
25170   }
25171
25172   function Deferred() {
25173     this.promise = new Promise();
25174   }
25175
25176   extend(Deferred.prototype, {
25177     resolve: function(val) {
25178       if (this.promise.$$state.status) return;
25179       if (val === this.promise) {
25180         this.$$reject($qMinErr(
25181           'qcycle',
25182           "Expected promise to be resolved with value other than itself '{0}'",
25183           val));
25184       } else {
25185         this.$$resolve(val);
25186       }
25187
25188     },
25189
25190     $$resolve: function(val) {
25191       var then;
25192       var that = this;
25193       var done = false;
25194       try {
25195         if ((isObject(val) || isFunction(val))) then = val && val.then;
25196         if (isFunction(then)) {
25197           this.promise.$$state.status = -1;
25198           then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
25199         } else {
25200           this.promise.$$state.value = val;
25201           this.promise.$$state.status = 1;
25202           scheduleProcessQueue(this.promise.$$state);
25203         }
25204       } catch (e) {
25205         rejectPromise(e);
25206         exceptionHandler(e);
25207       }
25208
25209       function resolvePromise(val) {
25210         if (done) return;
25211         done = true;
25212         that.$$resolve(val);
25213       }
25214       function rejectPromise(val) {
25215         if (done) return;
25216         done = true;
25217         that.$$reject(val);
25218       }
25219     },
25220
25221     reject: function(reason) {
25222       if (this.promise.$$state.status) return;
25223       this.$$reject(reason);
25224     },
25225
25226     $$reject: function(reason) {
25227       this.promise.$$state.value = reason;
25228       this.promise.$$state.status = 2;
25229       scheduleProcessQueue(this.promise.$$state);
25230     },
25231
25232     notify: function(progress) {
25233       var callbacks = this.promise.$$state.pending;
25234
25235       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
25236         nextTick(function() {
25237           var callback, result;
25238           for (var i = 0, ii = callbacks.length; i < ii; i++) {
25239             result = callbacks[i][0];
25240             callback = callbacks[i][3];
25241             try {
25242               result.notify(isFunction(callback) ? callback(progress) : progress);
25243             } catch (e) {
25244               exceptionHandler(e);
25245             }
25246           }
25247         });
25248       }
25249     }
25250   });
25251
25252   /**
25253    * @ngdoc method
25254    * @name $q#reject
25255    * @kind function
25256    *
25257    * @description
25258    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
25259    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
25260    * a promise chain, you don't need to worry about it.
25261    *
25262    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
25263    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
25264    * a promise error callback and you want to forward the error to the promise derived from the
25265    * current promise, you have to "rethrow" the error by returning a rejection constructed via
25266    * `reject`.
25267    *
25268    * ```js
25269    *   promiseB = promiseA.then(function(result) {
25270    *     // success: do something and resolve promiseB
25271    *     //          with the old or a new result
25272    *     return result;
25273    *   }, function(reason) {
25274    *     // error: handle the error if possible and
25275    *     //        resolve promiseB with newPromiseOrValue,
25276    *     //        otherwise forward the rejection to promiseB
25277    *     if (canHandle(reason)) {
25278    *      // handle the error and recover
25279    *      return newPromiseOrValue;
25280    *     }
25281    *     return $q.reject(reason);
25282    *   });
25283    * ```
25284    *
25285    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
25286    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
25287    */
25288   var reject = function(reason) {
25289     var result = new Deferred();
25290     result.reject(reason);
25291     return result.promise;
25292   };
25293
25294   var makePromise = function makePromise(value, resolved) {
25295     var result = new Deferred();
25296     if (resolved) {
25297       result.resolve(value);
25298     } else {
25299       result.reject(value);
25300     }
25301     return result.promise;
25302   };
25303
25304   var handleCallback = function handleCallback(value, isResolved, callback) {
25305     var callbackOutput = null;
25306     try {
25307       if (isFunction(callback)) callbackOutput = callback();
25308     } catch (e) {
25309       return makePromise(e, false);
25310     }
25311     if (isPromiseLike(callbackOutput)) {
25312       return callbackOutput.then(function() {
25313         return makePromise(value, isResolved);
25314       }, function(error) {
25315         return makePromise(error, false);
25316       });
25317     } else {
25318       return makePromise(value, isResolved);
25319     }
25320   };
25321
25322   /**
25323    * @ngdoc method
25324    * @name $q#when
25325    * @kind function
25326    *
25327    * @description
25328    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
25329    * This is useful when you are dealing with an object that might or might not be a promise, or if
25330    * the promise comes from a source that can't be trusted.
25331    *
25332    * @param {*} value Value or a promise
25333    * @param {Function=} successCallback
25334    * @param {Function=} errorCallback
25335    * @param {Function=} progressCallback
25336    * @returns {Promise} Returns a promise of the passed value or promise
25337    */
25338
25339
25340   var when = function(value, callback, errback, progressBack) {
25341     var result = new Deferred();
25342     result.resolve(value);
25343     return result.promise.then(callback, errback, progressBack);
25344   };
25345
25346   /**
25347    * @ngdoc method
25348    * @name $q#resolve
25349    * @kind function
25350    *
25351    * @description
25352    * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
25353    *
25354    * @param {*} value Value or a promise
25355    * @param {Function=} successCallback
25356    * @param {Function=} errorCallback
25357    * @param {Function=} progressCallback
25358    * @returns {Promise} Returns a promise of the passed value or promise
25359    */
25360   var resolve = when;
25361
25362   /**
25363    * @ngdoc method
25364    * @name $q#all
25365    * @kind function
25366    *
25367    * @description
25368    * Combines multiple promises into a single promise that is resolved when all of the input
25369    * promises are resolved.
25370    *
25371    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
25372    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
25373    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
25374    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
25375    *   with the same rejection value.
25376    */
25377
25378   function all(promises) {
25379     var deferred = new Deferred(),
25380         counter = 0,
25381         results = isArray(promises) ? [] : {};
25382
25383     forEach(promises, function(promise, key) {
25384       counter++;
25385       when(promise).then(function(value) {
25386         if (results.hasOwnProperty(key)) return;
25387         results[key] = value;
25388         if (!(--counter)) deferred.resolve(results);
25389       }, function(reason) {
25390         if (results.hasOwnProperty(key)) return;
25391         deferred.reject(reason);
25392       });
25393     });
25394
25395     if (counter === 0) {
25396       deferred.resolve(results);
25397     }
25398
25399     return deferred.promise;
25400   }
25401
25402   var $Q = function Q(resolver) {
25403     if (!isFunction(resolver)) {
25404       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
25405     }
25406
25407     var deferred = new Deferred();
25408
25409     function resolveFn(value) {
25410       deferred.resolve(value);
25411     }
25412
25413     function rejectFn(reason) {
25414       deferred.reject(reason);
25415     }
25416
25417     resolver(resolveFn, rejectFn);
25418
25419     return deferred.promise;
25420   };
25421
25422   // Let's make the instanceof operator work for promises, so that
25423   // `new $q(fn) instanceof $q` would evaluate to true.
25424   $Q.prototype = Promise.prototype;
25425
25426   $Q.defer = defer;
25427   $Q.reject = reject;
25428   $Q.when = when;
25429   $Q.resolve = resolve;
25430   $Q.all = all;
25431
25432   return $Q;
25433 }
25434
25435 function $$RAFProvider() { //rAF
25436   this.$get = ['$window', '$timeout', function($window, $timeout) {
25437     var requestAnimationFrame = $window.requestAnimationFrame ||
25438                                 $window.webkitRequestAnimationFrame;
25439
25440     var cancelAnimationFrame = $window.cancelAnimationFrame ||
25441                                $window.webkitCancelAnimationFrame ||
25442                                $window.webkitCancelRequestAnimationFrame;
25443
25444     var rafSupported = !!requestAnimationFrame;
25445     var raf = rafSupported
25446       ? function(fn) {
25447           var id = requestAnimationFrame(fn);
25448           return function() {
25449             cancelAnimationFrame(id);
25450           };
25451         }
25452       : function(fn) {
25453           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
25454           return function() {
25455             $timeout.cancel(timer);
25456           };
25457         };
25458
25459     raf.supported = rafSupported;
25460
25461     return raf;
25462   }];
25463 }
25464
25465 /**
25466  * DESIGN NOTES
25467  *
25468  * The design decisions behind the scope are heavily favored for speed and memory consumption.
25469  *
25470  * The typical use of scope is to watch the expressions, which most of the time return the same
25471  * value as last time so we optimize the operation.
25472  *
25473  * Closures construction is expensive in terms of speed as well as memory:
25474  *   - No closures, instead use prototypical inheritance for API
25475  *   - Internal state needs to be stored on scope directly, which means that private state is
25476  *     exposed as $$____ properties
25477  *
25478  * Loop operations are optimized by using while(count--) { ... }
25479  *   - This means that in order to keep the same order of execution as addition we have to add
25480  *     items to the array at the beginning (unshift) instead of at the end (push)
25481  *
25482  * Child scopes are created and removed often
25483  *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
25484  *
25485  * There are fewer watches than observers. This is why you don't want the observer to be implemented
25486  * in the same way as watch. Watch requires return of the initialization function which is expensive
25487  * to construct.
25488  */
25489
25490
25491 /**
25492  * @ngdoc provider
25493  * @name $rootScopeProvider
25494  * @description
25495  *
25496  * Provider for the $rootScope service.
25497  */
25498
25499 /**
25500  * @ngdoc method
25501  * @name $rootScopeProvider#digestTtl
25502  * @description
25503  *
25504  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
25505  * assuming that the model is unstable.
25506  *
25507  * The current default is 10 iterations.
25508  *
25509  * In complex applications it's possible that the dependencies between `$watch`s will result in
25510  * several digest iterations. However if an application needs more than the default 10 digest
25511  * iterations for its model to stabilize then you should investigate what is causing the model to
25512  * continuously change during the digest.
25513  *
25514  * Increasing the TTL could have performance implications, so you should not change it without
25515  * proper justification.
25516  *
25517  * @param {number} limit The number of digest iterations.
25518  */
25519
25520
25521 /**
25522  * @ngdoc service
25523  * @name $rootScope
25524  * @description
25525  *
25526  * Every application has a single root {@link ng.$rootScope.Scope scope}.
25527  * All other scopes are descendant scopes of the root scope. Scopes provide separation
25528  * between the model and the view, via a mechanism for watching the model for changes.
25529  * They also provide event emission/broadcast and subscription facility. See the
25530  * {@link guide/scope developer guide on scopes}.
25531  */
25532 function $RootScopeProvider() {
25533   var TTL = 10;
25534   var $rootScopeMinErr = minErr('$rootScope');
25535   var lastDirtyWatch = null;
25536   var applyAsyncId = null;
25537
25538   this.digestTtl = function(value) {
25539     if (arguments.length) {
25540       TTL = value;
25541     }
25542     return TTL;
25543   };
25544
25545   function createChildScopeClass(parent) {
25546     function ChildScope() {
25547       this.$$watchers = this.$$nextSibling =
25548           this.$$childHead = this.$$childTail = null;
25549       this.$$listeners = {};
25550       this.$$listenerCount = {};
25551       this.$$watchersCount = 0;
25552       this.$id = nextUid();
25553       this.$$ChildScope = null;
25554     }
25555     ChildScope.prototype = parent;
25556     return ChildScope;
25557   }
25558
25559   this.$get = ['$exceptionHandler', '$parse', '$browser',
25560       function($exceptionHandler, $parse, $browser) {
25561
25562     function destroyChildScope($event) {
25563         $event.currentScope.$$destroyed = true;
25564     }
25565
25566     function cleanUpScope($scope) {
25567
25568       if (msie === 9) {
25569         // There is a memory leak in IE9 if all child scopes are not disconnected
25570         // completely when a scope is destroyed. So this code will recurse up through
25571         // all this scopes children
25572         //
25573         // See issue https://github.com/angular/angular.js/issues/10706
25574         $scope.$$childHead && cleanUpScope($scope.$$childHead);
25575         $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
25576       }
25577
25578       // The code below works around IE9 and V8's memory leaks
25579       //
25580       // See:
25581       // - https://code.google.com/p/v8/issues/detail?id=2073#c26
25582       // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
25583       // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
25584
25585       $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
25586           $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
25587     }
25588
25589     /**
25590      * @ngdoc type
25591      * @name $rootScope.Scope
25592      *
25593      * @description
25594      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
25595      * {@link auto.$injector $injector}. Child scopes are created using the
25596      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
25597      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
25598      * an in-depth introduction and usage examples.
25599      *
25600      *
25601      * # Inheritance
25602      * A scope can inherit from a parent scope, as in this example:
25603      * ```js
25604          var parent = $rootScope;
25605          var child = parent.$new();
25606
25607          parent.salutation = "Hello";
25608          expect(child.salutation).toEqual('Hello');
25609
25610          child.salutation = "Welcome";
25611          expect(child.salutation).toEqual('Welcome');
25612          expect(parent.salutation).toEqual('Hello');
25613      * ```
25614      *
25615      * When interacting with `Scope` in tests, additional helper methods are available on the
25616      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
25617      * details.
25618      *
25619      *
25620      * @param {Object.<string, function()>=} providers Map of service factory which need to be
25621      *                                       provided for the current scope. Defaults to {@link ng}.
25622      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
25623      *                              append/override services provided by `providers`. This is handy
25624      *                              when unit-testing and having the need to override a default
25625      *                              service.
25626      * @returns {Object} Newly created scope.
25627      *
25628      */
25629     function Scope() {
25630       this.$id = nextUid();
25631       this.$$phase = this.$parent = this.$$watchers =
25632                      this.$$nextSibling = this.$$prevSibling =
25633                      this.$$childHead = this.$$childTail = null;
25634       this.$root = this;
25635       this.$$destroyed = false;
25636       this.$$listeners = {};
25637       this.$$listenerCount = {};
25638       this.$$watchersCount = 0;
25639       this.$$isolateBindings = null;
25640     }
25641
25642     /**
25643      * @ngdoc property
25644      * @name $rootScope.Scope#$id
25645      *
25646      * @description
25647      * Unique scope ID (monotonically increasing) useful for debugging.
25648      */
25649
25650      /**
25651       * @ngdoc property
25652       * @name $rootScope.Scope#$parent
25653       *
25654       * @description
25655       * Reference to the parent scope.
25656       */
25657
25658       /**
25659        * @ngdoc property
25660        * @name $rootScope.Scope#$root
25661        *
25662        * @description
25663        * Reference to the root scope.
25664        */
25665
25666     Scope.prototype = {
25667       constructor: Scope,
25668       /**
25669        * @ngdoc method
25670        * @name $rootScope.Scope#$new
25671        * @kind function
25672        *
25673        * @description
25674        * Creates a new child {@link ng.$rootScope.Scope scope}.
25675        *
25676        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
25677        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
25678        *
25679        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
25680        * desired for the scope and its child scopes to be permanently detached from the parent and
25681        * thus stop participating in model change detection and listener notification by invoking.
25682        *
25683        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
25684        *         parent scope. The scope is isolated, as it can not see parent scope properties.
25685        *         When creating widgets, it is useful for the widget to not accidentally read parent
25686        *         state.
25687        *
25688        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
25689        *                              of the newly created scope. Defaults to `this` scope if not provided.
25690        *                              This is used when creating a transclude scope to correctly place it
25691        *                              in the scope hierarchy while maintaining the correct prototypical
25692        *                              inheritance.
25693        *
25694        * @returns {Object} The newly created child scope.
25695        *
25696        */
25697       $new: function(isolate, parent) {
25698         var child;
25699
25700         parent = parent || this;
25701
25702         if (isolate) {
25703           child = new Scope();
25704           child.$root = this.$root;
25705         } else {
25706           // Only create a child scope class if somebody asks for one,
25707           // but cache it to allow the VM to optimize lookups.
25708           if (!this.$$ChildScope) {
25709             this.$$ChildScope = createChildScopeClass(this);
25710           }
25711           child = new this.$$ChildScope();
25712         }
25713         child.$parent = parent;
25714         child.$$prevSibling = parent.$$childTail;
25715         if (parent.$$childHead) {
25716           parent.$$childTail.$$nextSibling = child;
25717           parent.$$childTail = child;
25718         } else {
25719           parent.$$childHead = parent.$$childTail = child;
25720         }
25721
25722         // When the new scope is not isolated or we inherit from `this`, and
25723         // the parent scope is destroyed, the property `$$destroyed` is inherited
25724         // prototypically. In all other cases, this property needs to be set
25725         // when the parent scope is destroyed.
25726         // The listener needs to be added after the parent is set
25727         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
25728
25729         return child;
25730       },
25731
25732       /**
25733        * @ngdoc method
25734        * @name $rootScope.Scope#$watch
25735        * @kind function
25736        *
25737        * @description
25738        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
25739        *
25740        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
25741        *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
25742        *   its value when executed multiple times with the same input because it may be executed multiple
25743        *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
25744        *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
25745        * - The `listener` is called only when the value from the current `watchExpression` and the
25746        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
25747        *   see below). Inequality is determined according to reference inequality,
25748        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
25749        *    via the `!==` Javascript operator, unless `objectEquality == true`
25750        *   (see next point)
25751        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
25752        *   according to the {@link angular.equals} function. To save the value of the object for
25753        *   later comparison, the {@link angular.copy} function is used. This therefore means that
25754        *   watching complex objects will have adverse memory and performance implications.
25755        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
25756        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
25757        *   iteration limit is 10 to prevent an infinite loop deadlock.
25758        *
25759        *
25760        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
25761        * you can register a `watchExpression` function with no `listener`. (Be prepared for
25762        * multiple calls to your `watchExpression` because it will execute multiple times in a
25763        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
25764        *
25765        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
25766        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
25767        * watcher. In rare cases, this is undesirable because the listener is called when the result
25768        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
25769        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
25770        * listener was called due to initialization.
25771        *
25772        *
25773        *
25774        * # Example
25775        * ```js
25776            // let's assume that scope was dependency injected as the $rootScope
25777            var scope = $rootScope;
25778            scope.name = 'misko';
25779            scope.counter = 0;
25780
25781            expect(scope.counter).toEqual(0);
25782            scope.$watch('name', function(newValue, oldValue) {
25783              scope.counter = scope.counter + 1;
25784            });
25785            expect(scope.counter).toEqual(0);
25786
25787            scope.$digest();
25788            // the listener is always called during the first $digest loop after it was registered
25789            expect(scope.counter).toEqual(1);
25790
25791            scope.$digest();
25792            // but now it will not be called unless the value changes
25793            expect(scope.counter).toEqual(1);
25794
25795            scope.name = 'adam';
25796            scope.$digest();
25797            expect(scope.counter).toEqual(2);
25798
25799
25800
25801            // Using a function as a watchExpression
25802            var food;
25803            scope.foodCounter = 0;
25804            expect(scope.foodCounter).toEqual(0);
25805            scope.$watch(
25806              // This function returns the value being watched. It is called for each turn of the $digest loop
25807              function() { return food; },
25808              // This is the change listener, called when the value returned from the above function changes
25809              function(newValue, oldValue) {
25810                if ( newValue !== oldValue ) {
25811                  // Only increment the counter if the value changed
25812                  scope.foodCounter = scope.foodCounter + 1;
25813                }
25814              }
25815            );
25816            // No digest has been run so the counter will be zero
25817            expect(scope.foodCounter).toEqual(0);
25818
25819            // Run the digest but since food has not changed count will still be zero
25820            scope.$digest();
25821            expect(scope.foodCounter).toEqual(0);
25822
25823            // Update food and run digest.  Now the counter will increment
25824            food = 'cheeseburger';
25825            scope.$digest();
25826            expect(scope.foodCounter).toEqual(1);
25827
25828        * ```
25829        *
25830        *
25831        *
25832        * @param {(function()|string)} watchExpression Expression that is evaluated on each
25833        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
25834        *    a call to the `listener`.
25835        *
25836        *    - `string`: Evaluated as {@link guide/expression expression}
25837        *    - `function(scope)`: called with current `scope` as a parameter.
25838        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
25839        *    of `watchExpression` changes.
25840        *
25841        *    - `newVal` contains the current value of the `watchExpression`
25842        *    - `oldVal` contains the previous value of the `watchExpression`
25843        *    - `scope` refers to the current scope
25844        * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
25845        *     comparing for reference equality.
25846        * @returns {function()} Returns a deregistration function for this listener.
25847        */
25848       $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
25849         var get = $parse(watchExp);
25850
25851         if (get.$$watchDelegate) {
25852           return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
25853         }
25854         var scope = this,
25855             array = scope.$$watchers,
25856             watcher = {
25857               fn: listener,
25858               last: initWatchVal,
25859               get: get,
25860               exp: prettyPrintExpression || watchExp,
25861               eq: !!objectEquality
25862             };
25863
25864         lastDirtyWatch = null;
25865
25866         if (!isFunction(listener)) {
25867           watcher.fn = noop;
25868         }
25869
25870         if (!array) {
25871           array = scope.$$watchers = [];
25872         }
25873         // we use unshift since we use a while loop in $digest for speed.
25874         // the while loop reads in reverse order.
25875         array.unshift(watcher);
25876         incrementWatchersCount(this, 1);
25877
25878         return function deregisterWatch() {
25879           if (arrayRemove(array, watcher) >= 0) {
25880             incrementWatchersCount(scope, -1);
25881           }
25882           lastDirtyWatch = null;
25883         };
25884       },
25885
25886       /**
25887        * @ngdoc method
25888        * @name $rootScope.Scope#$watchGroup
25889        * @kind function
25890        *
25891        * @description
25892        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
25893        * If any one expression in the collection changes the `listener` is executed.
25894        *
25895        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
25896        *   call to $digest() to see if any items changes.
25897        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
25898        *
25899        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
25900        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
25901        *
25902        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
25903        *    expression in `watchExpressions` changes
25904        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
25905        *    those of `watchExpression`
25906        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
25907        *    those of `watchExpression`
25908        *    The `scope` refers to the current scope.
25909        * @returns {function()} Returns a de-registration function for all listeners.
25910        */
25911       $watchGroup: function(watchExpressions, listener) {
25912         var oldValues = new Array(watchExpressions.length);
25913         var newValues = new Array(watchExpressions.length);
25914         var deregisterFns = [];
25915         var self = this;
25916         var changeReactionScheduled = false;
25917         var firstRun = true;
25918
25919         if (!watchExpressions.length) {
25920           // No expressions means we call the listener ASAP
25921           var shouldCall = true;
25922           self.$evalAsync(function() {
25923             if (shouldCall) listener(newValues, newValues, self);
25924           });
25925           return function deregisterWatchGroup() {
25926             shouldCall = false;
25927           };
25928         }
25929
25930         if (watchExpressions.length === 1) {
25931           // Special case size of one
25932           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
25933             newValues[0] = value;
25934             oldValues[0] = oldValue;
25935             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
25936           });
25937         }
25938
25939         forEach(watchExpressions, function(expr, i) {
25940           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
25941             newValues[i] = value;
25942             oldValues[i] = oldValue;
25943             if (!changeReactionScheduled) {
25944               changeReactionScheduled = true;
25945               self.$evalAsync(watchGroupAction);
25946             }
25947           });
25948           deregisterFns.push(unwatchFn);
25949         });
25950
25951         function watchGroupAction() {
25952           changeReactionScheduled = false;
25953
25954           if (firstRun) {
25955             firstRun = false;
25956             listener(newValues, newValues, self);
25957           } else {
25958             listener(newValues, oldValues, self);
25959           }
25960         }
25961
25962         return function deregisterWatchGroup() {
25963           while (deregisterFns.length) {
25964             deregisterFns.shift()();
25965           }
25966         };
25967       },
25968
25969
25970       /**
25971        * @ngdoc method
25972        * @name $rootScope.Scope#$watchCollection
25973        * @kind function
25974        *
25975        * @description
25976        * Shallow watches the properties of an object and fires whenever any of the properties change
25977        * (for arrays, this implies watching the array items; for object maps, this implies watching
25978        * the properties). If a change is detected, the `listener` callback is fired.
25979        *
25980        * - The `obj` collection is observed via standard $watch operation and is examined on every
25981        *   call to $digest() to see if any items have been added, removed, or moved.
25982        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
25983        *   adding, removing, and moving items belonging to an object or array.
25984        *
25985        *
25986        * # Example
25987        * ```js
25988           $scope.names = ['igor', 'matias', 'misko', 'james'];
25989           $scope.dataCount = 4;
25990
25991           $scope.$watchCollection('names', function(newNames, oldNames) {
25992             $scope.dataCount = newNames.length;
25993           });
25994
25995           expect($scope.dataCount).toEqual(4);
25996           $scope.$digest();
25997
25998           //still at 4 ... no changes
25999           expect($scope.dataCount).toEqual(4);
26000
26001           $scope.names.pop();
26002           $scope.$digest();
26003
26004           //now there's been a change
26005           expect($scope.dataCount).toEqual(3);
26006        * ```
26007        *
26008        *
26009        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
26010        *    expression value should evaluate to an object or an array which is observed on each
26011        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
26012        *    collection will trigger a call to the `listener`.
26013        *
26014        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
26015        *    when a change is detected.
26016        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
26017        *    - The `oldCollection` object is a copy of the former collection data.
26018        *      Due to performance considerations, the`oldCollection` value is computed only if the
26019        *      `listener` function declares two or more arguments.
26020        *    - The `scope` argument refers to the current scope.
26021        *
26022        * @returns {function()} Returns a de-registration function for this listener. When the
26023        *    de-registration function is executed, the internal watch operation is terminated.
26024        */
26025       $watchCollection: function(obj, listener) {
26026         $watchCollectionInterceptor.$stateful = true;
26027
26028         var self = this;
26029         // the current value, updated on each dirty-check run
26030         var newValue;
26031         // a shallow copy of the newValue from the last dirty-check run,
26032         // updated to match newValue during dirty-check run
26033         var oldValue;
26034         // a shallow copy of the newValue from when the last change happened
26035         var veryOldValue;
26036         // only track veryOldValue if the listener is asking for it
26037         var trackVeryOldValue = (listener.length > 1);
26038         var changeDetected = 0;
26039         var changeDetector = $parse(obj, $watchCollectionInterceptor);
26040         var internalArray = [];
26041         var internalObject = {};
26042         var initRun = true;
26043         var oldLength = 0;
26044
26045         function $watchCollectionInterceptor(_value) {
26046           newValue = _value;
26047           var newLength, key, bothNaN, newItem, oldItem;
26048
26049           // If the new value is undefined, then return undefined as the watch may be a one-time watch
26050           if (isUndefined(newValue)) return;
26051
26052           if (!isObject(newValue)) { // if primitive
26053             if (oldValue !== newValue) {
26054               oldValue = newValue;
26055               changeDetected++;
26056             }
26057           } else if (isArrayLike(newValue)) {
26058             if (oldValue !== internalArray) {
26059               // we are transitioning from something which was not an array into array.
26060               oldValue = internalArray;
26061               oldLength = oldValue.length = 0;
26062               changeDetected++;
26063             }
26064
26065             newLength = newValue.length;
26066
26067             if (oldLength !== newLength) {
26068               // if lengths do not match we need to trigger change notification
26069               changeDetected++;
26070               oldValue.length = oldLength = newLength;
26071             }
26072             // copy the items to oldValue and look for changes.
26073             for (var i = 0; i < newLength; i++) {
26074               oldItem = oldValue[i];
26075               newItem = newValue[i];
26076
26077               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
26078               if (!bothNaN && (oldItem !== newItem)) {
26079                 changeDetected++;
26080                 oldValue[i] = newItem;
26081               }
26082             }
26083           } else {
26084             if (oldValue !== internalObject) {
26085               // we are transitioning from something which was not an object into object.
26086               oldValue = internalObject = {};
26087               oldLength = 0;
26088               changeDetected++;
26089             }
26090             // copy the items to oldValue and look for changes.
26091             newLength = 0;
26092             for (key in newValue) {
26093               if (hasOwnProperty.call(newValue, key)) {
26094                 newLength++;
26095                 newItem = newValue[key];
26096                 oldItem = oldValue[key];
26097
26098                 if (key in oldValue) {
26099                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
26100                   if (!bothNaN && (oldItem !== newItem)) {
26101                     changeDetected++;
26102                     oldValue[key] = newItem;
26103                   }
26104                 } else {
26105                   oldLength++;
26106                   oldValue[key] = newItem;
26107                   changeDetected++;
26108                 }
26109               }
26110             }
26111             if (oldLength > newLength) {
26112               // we used to have more keys, need to find them and destroy them.
26113               changeDetected++;
26114               for (key in oldValue) {
26115                 if (!hasOwnProperty.call(newValue, key)) {
26116                   oldLength--;
26117                   delete oldValue[key];
26118                 }
26119               }
26120             }
26121           }
26122           return changeDetected;
26123         }
26124
26125         function $watchCollectionAction() {
26126           if (initRun) {
26127             initRun = false;
26128             listener(newValue, newValue, self);
26129           } else {
26130             listener(newValue, veryOldValue, self);
26131           }
26132
26133           // make a copy for the next time a collection is changed
26134           if (trackVeryOldValue) {
26135             if (!isObject(newValue)) {
26136               //primitive
26137               veryOldValue = newValue;
26138             } else if (isArrayLike(newValue)) {
26139               veryOldValue = new Array(newValue.length);
26140               for (var i = 0; i < newValue.length; i++) {
26141                 veryOldValue[i] = newValue[i];
26142               }
26143             } else { // if object
26144               veryOldValue = {};
26145               for (var key in newValue) {
26146                 if (hasOwnProperty.call(newValue, key)) {
26147                   veryOldValue[key] = newValue[key];
26148                 }
26149               }
26150             }
26151           }
26152         }
26153
26154         return this.$watch(changeDetector, $watchCollectionAction);
26155       },
26156
26157       /**
26158        * @ngdoc method
26159        * @name $rootScope.Scope#$digest
26160        * @kind function
26161        *
26162        * @description
26163        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
26164        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
26165        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
26166        * until no more listeners are firing. This means that it is possible to get into an infinite
26167        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
26168        * iterations exceeds 10.
26169        *
26170        * Usually, you don't call `$digest()` directly in
26171        * {@link ng.directive:ngController controllers} or in
26172        * {@link ng.$compileProvider#directive directives}.
26173        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
26174        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
26175        *
26176        * If you want to be notified whenever `$digest()` is called,
26177        * you can register a `watchExpression` function with
26178        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
26179        *
26180        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
26181        *
26182        * # Example
26183        * ```js
26184            var scope = ...;
26185            scope.name = 'misko';
26186            scope.counter = 0;
26187
26188            expect(scope.counter).toEqual(0);
26189            scope.$watch('name', function(newValue, oldValue) {
26190              scope.counter = scope.counter + 1;
26191            });
26192            expect(scope.counter).toEqual(0);
26193
26194            scope.$digest();
26195            // the listener is always called during the first $digest loop after it was registered
26196            expect(scope.counter).toEqual(1);
26197
26198            scope.$digest();
26199            // but now it will not be called unless the value changes
26200            expect(scope.counter).toEqual(1);
26201
26202            scope.name = 'adam';
26203            scope.$digest();
26204            expect(scope.counter).toEqual(2);
26205        * ```
26206        *
26207        */
26208       $digest: function() {
26209         var watch, value, last, fn, get,
26210             watchers,
26211             length,
26212             dirty, ttl = TTL,
26213             next, current, target = this,
26214             watchLog = [],
26215             logIdx, asyncTask;
26216
26217         beginPhase('$digest');
26218         // Check for changes to browser url that happened in sync before the call to $digest
26219         $browser.$$checkUrlChange();
26220
26221         if (this === $rootScope && applyAsyncId !== null) {
26222           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
26223           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
26224           $browser.defer.cancel(applyAsyncId);
26225           flushApplyAsync();
26226         }
26227
26228         lastDirtyWatch = null;
26229
26230         do { // "while dirty" loop
26231           dirty = false;
26232           current = target;
26233
26234           while (asyncQueue.length) {
26235             try {
26236               asyncTask = asyncQueue.shift();
26237               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
26238             } catch (e) {
26239               $exceptionHandler(e);
26240             }
26241             lastDirtyWatch = null;
26242           }
26243
26244           traverseScopesLoop:
26245           do { // "traverse the scopes" loop
26246             if ((watchers = current.$$watchers)) {
26247               // process our watches
26248               length = watchers.length;
26249               while (length--) {
26250                 try {
26251                   watch = watchers[length];
26252                   // Most common watches are on primitives, in which case we can short
26253                   // circuit it with === operator, only when === fails do we use .equals
26254                   if (watch) {
26255                     get = watch.get;
26256                     if ((value = get(current)) !== (last = watch.last) &&
26257                         !(watch.eq
26258                             ? equals(value, last)
26259                             : (typeof value === 'number' && typeof last === 'number'
26260                                && isNaN(value) && isNaN(last)))) {
26261                       dirty = true;
26262                       lastDirtyWatch = watch;
26263                       watch.last = watch.eq ? copy(value, null) : value;
26264                       fn = watch.fn;
26265                       fn(value, ((last === initWatchVal) ? value : last), current);
26266                       if (ttl < 5) {
26267                         logIdx = 4 - ttl;
26268                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
26269                         watchLog[logIdx].push({
26270                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
26271                           newVal: value,
26272                           oldVal: last
26273                         });
26274                       }
26275                     } else if (watch === lastDirtyWatch) {
26276                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
26277                       // have already been tested.
26278                       dirty = false;
26279                       break traverseScopesLoop;
26280                     }
26281                   }
26282                 } catch (e) {
26283                   $exceptionHandler(e);
26284                 }
26285               }
26286             }
26287
26288             // Insanity Warning: scope depth-first traversal
26289             // yes, this code is a bit crazy, but it works and we have tests to prove it!
26290             // this piece should be kept in sync with the traversal in $broadcast
26291             if (!(next = ((current.$$watchersCount && current.$$childHead) ||
26292                 (current !== target && current.$$nextSibling)))) {
26293               while (current !== target && !(next = current.$$nextSibling)) {
26294                 current = current.$parent;
26295               }
26296             }
26297           } while ((current = next));
26298
26299           // `break traverseScopesLoop;` takes us to here
26300
26301           if ((dirty || asyncQueue.length) && !(ttl--)) {
26302             clearPhase();
26303             throw $rootScopeMinErr('infdig',
26304                 '{0} $digest() iterations reached. Aborting!\n' +
26305                 'Watchers fired in the last 5 iterations: {1}',
26306                 TTL, watchLog);
26307           }
26308
26309         } while (dirty || asyncQueue.length);
26310
26311         clearPhase();
26312
26313         while (postDigestQueue.length) {
26314           try {
26315             postDigestQueue.shift()();
26316           } catch (e) {
26317             $exceptionHandler(e);
26318           }
26319         }
26320       },
26321
26322
26323       /**
26324        * @ngdoc event
26325        * @name $rootScope.Scope#$destroy
26326        * @eventType broadcast on scope being destroyed
26327        *
26328        * @description
26329        * Broadcasted when a scope and its children are being destroyed.
26330        *
26331        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
26332        * clean up DOM bindings before an element is removed from the DOM.
26333        */
26334
26335       /**
26336        * @ngdoc method
26337        * @name $rootScope.Scope#$destroy
26338        * @kind function
26339        *
26340        * @description
26341        * Removes the current scope (and all of its children) from the parent scope. Removal implies
26342        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
26343        * propagate to the current scope and its children. Removal also implies that the current
26344        * scope is eligible for garbage collection.
26345        *
26346        * The `$destroy()` is usually used by directives such as
26347        * {@link ng.directive:ngRepeat ngRepeat} for managing the
26348        * unrolling of the loop.
26349        *
26350        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
26351        * Application code can register a `$destroy` event handler that will give it a chance to
26352        * perform any necessary cleanup.
26353        *
26354        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
26355        * clean up DOM bindings before an element is removed from the DOM.
26356        */
26357       $destroy: function() {
26358         // We can't destroy a scope that has been already destroyed.
26359         if (this.$$destroyed) return;
26360         var parent = this.$parent;
26361
26362         this.$broadcast('$destroy');
26363         this.$$destroyed = true;
26364
26365         if (this === $rootScope) {
26366           //Remove handlers attached to window when $rootScope is removed
26367           $browser.$$applicationDestroyed();
26368         }
26369
26370         incrementWatchersCount(this, -this.$$watchersCount);
26371         for (var eventName in this.$$listenerCount) {
26372           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
26373         }
26374
26375         // sever all the references to parent scopes (after this cleanup, the current scope should
26376         // not be retained by any of our references and should be eligible for garbage collection)
26377         if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
26378         if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
26379         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
26380         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
26381
26382         // Disable listeners, watchers and apply/digest methods
26383         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
26384         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
26385         this.$$listeners = {};
26386
26387         // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
26388         this.$$nextSibling = null;
26389         cleanUpScope(this);
26390       },
26391
26392       /**
26393        * @ngdoc method
26394        * @name $rootScope.Scope#$eval
26395        * @kind function
26396        *
26397        * @description
26398        * Executes the `expression` on the current scope and returns the result. Any exceptions in
26399        * the expression are propagated (uncaught). This is useful when evaluating Angular
26400        * expressions.
26401        *
26402        * # Example
26403        * ```js
26404            var scope = ng.$rootScope.Scope();
26405            scope.a = 1;
26406            scope.b = 2;
26407
26408            expect(scope.$eval('a+b')).toEqual(3);
26409            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
26410        * ```
26411        *
26412        * @param {(string|function())=} expression An angular expression to be executed.
26413        *
26414        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
26415        *    - `function(scope)`: execute the function with the current `scope` parameter.
26416        *
26417        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
26418        * @returns {*} The result of evaluating the expression.
26419        */
26420       $eval: function(expr, locals) {
26421         return $parse(expr)(this, locals);
26422       },
26423
26424       /**
26425        * @ngdoc method
26426        * @name $rootScope.Scope#$evalAsync
26427        * @kind function
26428        *
26429        * @description
26430        * Executes the expression on the current scope at a later point in time.
26431        *
26432        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
26433        * that:
26434        *
26435        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
26436        *     rendering).
26437        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
26438        *     `expression` execution.
26439        *
26440        * Any exceptions from the execution of the expression are forwarded to the
26441        * {@link ng.$exceptionHandler $exceptionHandler} service.
26442        *
26443        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
26444        * will be scheduled. However, it is encouraged to always call code that changes the model
26445        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
26446        *
26447        * @param {(string|function())=} expression An angular expression to be executed.
26448        *
26449        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26450        *    - `function(scope)`: execute the function with the current `scope` parameter.
26451        *
26452        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
26453        */
26454       $evalAsync: function(expr, locals) {
26455         // if we are outside of an $digest loop and this is the first time we are scheduling async
26456         // task also schedule async auto-flush
26457         if (!$rootScope.$$phase && !asyncQueue.length) {
26458           $browser.defer(function() {
26459             if (asyncQueue.length) {
26460               $rootScope.$digest();
26461             }
26462           });
26463         }
26464
26465         asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
26466       },
26467
26468       $$postDigest: function(fn) {
26469         postDigestQueue.push(fn);
26470       },
26471
26472       /**
26473        * @ngdoc method
26474        * @name $rootScope.Scope#$apply
26475        * @kind function
26476        *
26477        * @description
26478        * `$apply()` is used to execute an expression in angular from outside of the angular
26479        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
26480        * Because we are calling into the angular framework we need to perform proper scope life
26481        * cycle of {@link ng.$exceptionHandler exception handling},
26482        * {@link ng.$rootScope.Scope#$digest executing watches}.
26483        *
26484        * ## Life cycle
26485        *
26486        * # Pseudo-Code of `$apply()`
26487        * ```js
26488            function $apply(expr) {
26489              try {
26490                return $eval(expr);
26491              } catch (e) {
26492                $exceptionHandler(e);
26493              } finally {
26494                $root.$digest();
26495              }
26496            }
26497        * ```
26498        *
26499        *
26500        * Scope's `$apply()` method transitions through the following stages:
26501        *
26502        * 1. The {@link guide/expression expression} is executed using the
26503        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
26504        * 2. Any exceptions from the execution of the expression are forwarded to the
26505        *    {@link ng.$exceptionHandler $exceptionHandler} service.
26506        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
26507        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
26508        *
26509        *
26510        * @param {(string|function())=} exp An angular expression to be executed.
26511        *
26512        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26513        *    - `function(scope)`: execute the function with current `scope` parameter.
26514        *
26515        * @returns {*} The result of evaluating the expression.
26516        */
26517       $apply: function(expr) {
26518         try {
26519           beginPhase('$apply');
26520           try {
26521             return this.$eval(expr);
26522           } finally {
26523             clearPhase();
26524           }
26525         } catch (e) {
26526           $exceptionHandler(e);
26527         } finally {
26528           try {
26529             $rootScope.$digest();
26530           } catch (e) {
26531             $exceptionHandler(e);
26532             throw e;
26533           }
26534         }
26535       },
26536
26537       /**
26538        * @ngdoc method
26539        * @name $rootScope.Scope#$applyAsync
26540        * @kind function
26541        *
26542        * @description
26543        * Schedule the invocation of $apply to occur at a later time. The actual time difference
26544        * varies across browsers, but is typically around ~10 milliseconds.
26545        *
26546        * This can be used to queue up multiple expressions which need to be evaluated in the same
26547        * digest.
26548        *
26549        * @param {(string|function())=} exp An angular expression to be executed.
26550        *
26551        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26552        *    - `function(scope)`: execute the function with current `scope` parameter.
26553        */
26554       $applyAsync: function(expr) {
26555         var scope = this;
26556         expr && applyAsyncQueue.push($applyAsyncExpression);
26557         expr = $parse(expr);
26558         scheduleApplyAsync();
26559
26560         function $applyAsyncExpression() {
26561           scope.$eval(expr);
26562         }
26563       },
26564
26565       /**
26566        * @ngdoc method
26567        * @name $rootScope.Scope#$on
26568        * @kind function
26569        *
26570        * @description
26571        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
26572        * discussion of event life cycle.
26573        *
26574        * The event listener function format is: `function(event, args...)`. The `event` object
26575        * passed into the listener has the following attributes:
26576        *
26577        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
26578        *     `$broadcast`-ed.
26579        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
26580        *     event propagates through the scope hierarchy, this property is set to null.
26581        *   - `name` - `{string}`: name of the event.
26582        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
26583        *     further event propagation (available only for events that were `$emit`-ed).
26584        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
26585        *     to true.
26586        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
26587        *
26588        * @param {string} name Event name to listen on.
26589        * @param {function(event, ...args)} listener Function to call when the event is emitted.
26590        * @returns {function()} Returns a deregistration function for this listener.
26591        */
26592       $on: function(name, listener) {
26593         var namedListeners = this.$$listeners[name];
26594         if (!namedListeners) {
26595           this.$$listeners[name] = namedListeners = [];
26596         }
26597         namedListeners.push(listener);
26598
26599         var current = this;
26600         do {
26601           if (!current.$$listenerCount[name]) {
26602             current.$$listenerCount[name] = 0;
26603           }
26604           current.$$listenerCount[name]++;
26605         } while ((current = current.$parent));
26606
26607         var self = this;
26608         return function() {
26609           var indexOfListener = namedListeners.indexOf(listener);
26610           if (indexOfListener !== -1) {
26611             namedListeners[indexOfListener] = null;
26612             decrementListenerCount(self, 1, name);
26613           }
26614         };
26615       },
26616
26617
26618       /**
26619        * @ngdoc method
26620        * @name $rootScope.Scope#$emit
26621        * @kind function
26622        *
26623        * @description
26624        * Dispatches an event `name` upwards through the scope hierarchy notifying the
26625        * registered {@link ng.$rootScope.Scope#$on} listeners.
26626        *
26627        * The event life cycle starts at the scope on which `$emit` was called. All
26628        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
26629        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
26630        * registered listeners along the way. The event will stop propagating if one of the listeners
26631        * cancels it.
26632        *
26633        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
26634        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
26635        *
26636        * @param {string} name Event name to emit.
26637        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
26638        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
26639        */
26640       $emit: function(name, args) {
26641         var empty = [],
26642             namedListeners,
26643             scope = this,
26644             stopPropagation = false,
26645             event = {
26646               name: name,
26647               targetScope: scope,
26648               stopPropagation: function() {stopPropagation = true;},
26649               preventDefault: function() {
26650                 event.defaultPrevented = true;
26651               },
26652               defaultPrevented: false
26653             },
26654             listenerArgs = concat([event], arguments, 1),
26655             i, length;
26656
26657         do {
26658           namedListeners = scope.$$listeners[name] || empty;
26659           event.currentScope = scope;
26660           for (i = 0, length = namedListeners.length; i < length; i++) {
26661
26662             // if listeners were deregistered, defragment the array
26663             if (!namedListeners[i]) {
26664               namedListeners.splice(i, 1);
26665               i--;
26666               length--;
26667               continue;
26668             }
26669             try {
26670               //allow all listeners attached to the current scope to run
26671               namedListeners[i].apply(null, listenerArgs);
26672             } catch (e) {
26673               $exceptionHandler(e);
26674             }
26675           }
26676           //if any listener on the current scope stops propagation, prevent bubbling
26677           if (stopPropagation) {
26678             event.currentScope = null;
26679             return event;
26680           }
26681           //traverse upwards
26682           scope = scope.$parent;
26683         } while (scope);
26684
26685         event.currentScope = null;
26686
26687         return event;
26688       },
26689
26690
26691       /**
26692        * @ngdoc method
26693        * @name $rootScope.Scope#$broadcast
26694        * @kind function
26695        *
26696        * @description
26697        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
26698        * registered {@link ng.$rootScope.Scope#$on} listeners.
26699        *
26700        * The event life cycle starts at the scope on which `$broadcast` was called. All
26701        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
26702        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
26703        * scope and calls all registered listeners along the way. The event cannot be canceled.
26704        *
26705        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
26706        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
26707        *
26708        * @param {string} name Event name to broadcast.
26709        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
26710        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
26711        */
26712       $broadcast: function(name, args) {
26713         var target = this,
26714             current = target,
26715             next = target,
26716             event = {
26717               name: name,
26718               targetScope: target,
26719               preventDefault: function() {
26720                 event.defaultPrevented = true;
26721               },
26722               defaultPrevented: false
26723             };
26724
26725         if (!target.$$listenerCount[name]) return event;
26726
26727         var listenerArgs = concat([event], arguments, 1),
26728             listeners, i, length;
26729
26730         //down while you can, then up and next sibling or up and next sibling until back at root
26731         while ((current = next)) {
26732           event.currentScope = current;
26733           listeners = current.$$listeners[name] || [];
26734           for (i = 0, length = listeners.length; i < length; i++) {
26735             // if listeners were deregistered, defragment the array
26736             if (!listeners[i]) {
26737               listeners.splice(i, 1);
26738               i--;
26739               length--;
26740               continue;
26741             }
26742
26743             try {
26744               listeners[i].apply(null, listenerArgs);
26745             } catch (e) {
26746               $exceptionHandler(e);
26747             }
26748           }
26749
26750           // Insanity Warning: scope depth-first traversal
26751           // yes, this code is a bit crazy, but it works and we have tests to prove it!
26752           // this piece should be kept in sync with the traversal in $digest
26753           // (though it differs due to having the extra check for $$listenerCount)
26754           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
26755               (current !== target && current.$$nextSibling)))) {
26756             while (current !== target && !(next = current.$$nextSibling)) {
26757               current = current.$parent;
26758             }
26759           }
26760         }
26761
26762         event.currentScope = null;
26763         return event;
26764       }
26765     };
26766
26767     var $rootScope = new Scope();
26768
26769     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
26770     var asyncQueue = $rootScope.$$asyncQueue = [];
26771     var postDigestQueue = $rootScope.$$postDigestQueue = [];
26772     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
26773
26774     return $rootScope;
26775
26776
26777     function beginPhase(phase) {
26778       if ($rootScope.$$phase) {
26779         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
26780       }
26781
26782       $rootScope.$$phase = phase;
26783     }
26784
26785     function clearPhase() {
26786       $rootScope.$$phase = null;
26787     }
26788
26789     function incrementWatchersCount(current, count) {
26790       do {
26791         current.$$watchersCount += count;
26792       } while ((current = current.$parent));
26793     }
26794
26795     function decrementListenerCount(current, count, name) {
26796       do {
26797         current.$$listenerCount[name] -= count;
26798
26799         if (current.$$listenerCount[name] === 0) {
26800           delete current.$$listenerCount[name];
26801         }
26802       } while ((current = current.$parent));
26803     }
26804
26805     /**
26806      * function used as an initial value for watchers.
26807      * because it's unique we can easily tell it apart from other values
26808      */
26809     function initWatchVal() {}
26810
26811     function flushApplyAsync() {
26812       while (applyAsyncQueue.length) {
26813         try {
26814           applyAsyncQueue.shift()();
26815         } catch (e) {
26816           $exceptionHandler(e);
26817         }
26818       }
26819       applyAsyncId = null;
26820     }
26821
26822     function scheduleApplyAsync() {
26823       if (applyAsyncId === null) {
26824         applyAsyncId = $browser.defer(function() {
26825           $rootScope.$apply(flushApplyAsync);
26826         });
26827       }
26828     }
26829   }];
26830 }
26831
26832 /**
26833  * @ngdoc service
26834  * @name $rootElement
26835  *
26836  * @description
26837  * The root element of Angular application. This is either the element where {@link
26838  * ng.directive:ngApp ngApp} was declared or the element passed into
26839  * {@link angular.bootstrap}. The element represents the root element of application. It is also the
26840  * location where the application's {@link auto.$injector $injector} service gets
26841  * published, and can be retrieved using `$rootElement.injector()`.
26842  */
26843
26844
26845 // the implementation is in angular.bootstrap
26846
26847 /**
26848  * @description
26849  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
26850  */
26851 function $$SanitizeUriProvider() {
26852   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
26853     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
26854
26855   /**
26856    * @description
26857    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
26858    * urls during a[href] sanitization.
26859    *
26860    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
26861    *
26862    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
26863    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
26864    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
26865    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
26866    *
26867    * @param {RegExp=} regexp New regexp to whitelist urls with.
26868    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
26869    *    chaining otherwise.
26870    */
26871   this.aHrefSanitizationWhitelist = function(regexp) {
26872     if (isDefined(regexp)) {
26873       aHrefSanitizationWhitelist = regexp;
26874       return this;
26875     }
26876     return aHrefSanitizationWhitelist;
26877   };
26878
26879
26880   /**
26881    * @description
26882    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
26883    * urls during img[src] sanitization.
26884    *
26885    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
26886    *
26887    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
26888    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
26889    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
26890    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
26891    *
26892    * @param {RegExp=} regexp New regexp to whitelist urls with.
26893    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
26894    *    chaining otherwise.
26895    */
26896   this.imgSrcSanitizationWhitelist = function(regexp) {
26897     if (isDefined(regexp)) {
26898       imgSrcSanitizationWhitelist = regexp;
26899       return this;
26900     }
26901     return imgSrcSanitizationWhitelist;
26902   };
26903
26904   this.$get = function() {
26905     return function sanitizeUri(uri, isImage) {
26906       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
26907       var normalizedVal;
26908       normalizedVal = urlResolve(uri).href;
26909       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
26910         return 'unsafe:' + normalizedVal;
26911       }
26912       return uri;
26913     };
26914   };
26915 }
26916
26917 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26918  *     Any commits to this file should be reviewed with security in mind.  *
26919  *   Changes to this file can potentially create security vulnerabilities. *
26920  *          An approval from 2 Core members with history of modifying      *
26921  *                         this file is required.                          *
26922  *                                                                         *
26923  *  Does the change somehow allow for arbitrary javascript to be executed? *
26924  *    Or allows for someone to change the prototype of built-in objects?   *
26925  *     Or gives undesired access to variables likes document or window?    *
26926  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26927
26928 var $sceMinErr = minErr('$sce');
26929
26930 var SCE_CONTEXTS = {
26931   HTML: 'html',
26932   CSS: 'css',
26933   URL: 'url',
26934   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
26935   // url.  (e.g. ng-include, script src, templateUrl)
26936   RESOURCE_URL: 'resourceUrl',
26937   JS: 'js'
26938 };
26939
26940 // Helper functions follow.
26941
26942 function adjustMatcher(matcher) {
26943   if (matcher === 'self') {
26944     return matcher;
26945   } else if (isString(matcher)) {
26946     // Strings match exactly except for 2 wildcards - '*' and '**'.
26947     // '*' matches any character except those from the set ':/.?&'.
26948     // '**' matches any character (like .* in a RegExp).
26949     // More than 2 *'s raises an error as it's ill defined.
26950     if (matcher.indexOf('***') > -1) {
26951       throw $sceMinErr('iwcard',
26952           'Illegal sequence *** in string matcher.  String: {0}', matcher);
26953     }
26954     matcher = escapeForRegexp(matcher).
26955                   replace('\\*\\*', '.*').
26956                   replace('\\*', '[^:/.?&;]*');
26957     return new RegExp('^' + matcher + '$');
26958   } else if (isRegExp(matcher)) {
26959     // The only other type of matcher allowed is a Regexp.
26960     // Match entire URL / disallow partial matches.
26961     // Flags are reset (i.e. no global, ignoreCase or multiline)
26962     return new RegExp('^' + matcher.source + '$');
26963   } else {
26964     throw $sceMinErr('imatcher',
26965         'Matchers may only be "self", string patterns or RegExp objects');
26966   }
26967 }
26968
26969
26970 function adjustMatchers(matchers) {
26971   var adjustedMatchers = [];
26972   if (isDefined(matchers)) {
26973     forEach(matchers, function(matcher) {
26974       adjustedMatchers.push(adjustMatcher(matcher));
26975     });
26976   }
26977   return adjustedMatchers;
26978 }
26979
26980
26981 /**
26982  * @ngdoc service
26983  * @name $sceDelegate
26984  * @kind function
26985  *
26986  * @description
26987  *
26988  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
26989  * Contextual Escaping (SCE)} services to AngularJS.
26990  *
26991  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
26992  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
26993  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
26994  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
26995  * work because `$sce` delegates to `$sceDelegate` for these operations.
26996  *
26997  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
26998  *
26999  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
27000  * can override it completely to change the behavior of `$sce`, the common case would
27001  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
27002  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
27003  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
27004  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
27005  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
27006  */
27007
27008 /**
27009  * @ngdoc provider
27010  * @name $sceDelegateProvider
27011  * @description
27012  *
27013  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
27014  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
27015  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
27016  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
27017  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
27018  *
27019  * For the general details about this service in Angular, read the main page for {@link ng.$sce
27020  * Strict Contextual Escaping (SCE)}.
27021  *
27022  * **Example**:  Consider the following case. <a name="example"></a>
27023  *
27024  * - your app is hosted at url `http://myapp.example.com/`
27025  * - but some of your templates are hosted on other domains you control such as
27026  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
27027  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
27028  *
27029  * Here is what a secure configuration for this scenario might look like:
27030  *
27031  * ```
27032  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
27033  *    $sceDelegateProvider.resourceUrlWhitelist([
27034  *      // Allow same origin resource loads.
27035  *      'self',
27036  *      // Allow loading from our assets domain.  Notice the difference between * and **.
27037  *      'http://srv*.assets.example.com/**'
27038  *    ]);
27039  *
27040  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
27041  *    $sceDelegateProvider.resourceUrlBlacklist([
27042  *      'http://myapp.example.com/clickThru**'
27043  *    ]);
27044  *  });
27045  * ```
27046  */
27047
27048 function $SceDelegateProvider() {
27049   this.SCE_CONTEXTS = SCE_CONTEXTS;
27050
27051   // Resource URLs can also be trusted by policy.
27052   var resourceUrlWhitelist = ['self'],
27053       resourceUrlBlacklist = [];
27054
27055   /**
27056    * @ngdoc method
27057    * @name $sceDelegateProvider#resourceUrlWhitelist
27058    * @kind function
27059    *
27060    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
27061    *    provided.  This must be an array or null.  A snapshot of this array is used so further
27062    *    changes to the array are ignored.
27063    *
27064    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
27065    *    allowed in this array.
27066    *
27067    *    <div class="alert alert-warning">
27068    *    **Note:** an empty whitelist array will block all URLs!
27069    *    </div>
27070    *
27071    * @return {Array} the currently set whitelist array.
27072    *
27073    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
27074    * same origin resource requests.
27075    *
27076    * @description
27077    * Sets/Gets the whitelist of trusted resource URLs.
27078    */
27079   this.resourceUrlWhitelist = function(value) {
27080     if (arguments.length) {
27081       resourceUrlWhitelist = adjustMatchers(value);
27082     }
27083     return resourceUrlWhitelist;
27084   };
27085
27086   /**
27087    * @ngdoc method
27088    * @name $sceDelegateProvider#resourceUrlBlacklist
27089    * @kind function
27090    *
27091    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
27092    *    provided.  This must be an array or null.  A snapshot of this array is used so further
27093    *    changes to the array are ignored.
27094    *
27095    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
27096    *    allowed in this array.
27097    *
27098    *    The typical usage for the blacklist is to **block
27099    *    [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
27100    *    these would otherwise be trusted but actually return content from the redirected domain.
27101    *
27102    *    Finally, **the blacklist overrides the whitelist** and has the final say.
27103    *
27104    * @return {Array} the currently set blacklist array.
27105    *
27106    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
27107    * is no blacklist.)
27108    *
27109    * @description
27110    * Sets/Gets the blacklist of trusted resource URLs.
27111    */
27112
27113   this.resourceUrlBlacklist = function(value) {
27114     if (arguments.length) {
27115       resourceUrlBlacklist = adjustMatchers(value);
27116     }
27117     return resourceUrlBlacklist;
27118   };
27119
27120   this.$get = ['$injector', function($injector) {
27121
27122     var htmlSanitizer = function htmlSanitizer(html) {
27123       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
27124     };
27125
27126     if ($injector.has('$sanitize')) {
27127       htmlSanitizer = $injector.get('$sanitize');
27128     }
27129
27130
27131     function matchUrl(matcher, parsedUrl) {
27132       if (matcher === 'self') {
27133         return urlIsSameOrigin(parsedUrl);
27134       } else {
27135         // definitely a regex.  See adjustMatchers()
27136         return !!matcher.exec(parsedUrl.href);
27137       }
27138     }
27139
27140     function isResourceUrlAllowedByPolicy(url) {
27141       var parsedUrl = urlResolve(url.toString());
27142       var i, n, allowed = false;
27143       // Ensure that at least one item from the whitelist allows this url.
27144       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
27145         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
27146           allowed = true;
27147           break;
27148         }
27149       }
27150       if (allowed) {
27151         // Ensure that no item from the blacklist blocked this url.
27152         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
27153           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
27154             allowed = false;
27155             break;
27156           }
27157         }
27158       }
27159       return allowed;
27160     }
27161
27162     function generateHolderType(Base) {
27163       var holderType = function TrustedValueHolderType(trustedValue) {
27164         this.$$unwrapTrustedValue = function() {
27165           return trustedValue;
27166         };
27167       };
27168       if (Base) {
27169         holderType.prototype = new Base();
27170       }
27171       holderType.prototype.valueOf = function sceValueOf() {
27172         return this.$$unwrapTrustedValue();
27173       };
27174       holderType.prototype.toString = function sceToString() {
27175         return this.$$unwrapTrustedValue().toString();
27176       };
27177       return holderType;
27178     }
27179
27180     var trustedValueHolderBase = generateHolderType(),
27181         byType = {};
27182
27183     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
27184     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
27185     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
27186     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
27187     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
27188
27189     /**
27190      * @ngdoc method
27191      * @name $sceDelegate#trustAs
27192      *
27193      * @description
27194      * Returns an object that is trusted by angular for use in specified strict
27195      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
27196      * attribute interpolation, any dom event binding attribute interpolation
27197      * such as for onclick,  etc.) that uses the provided value.
27198      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
27199      *
27200      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
27201      *   resourceUrl, html, js and css.
27202      * @param {*} value The value that that should be considered trusted/safe.
27203      * @returns {*} A value that can be used to stand in for the provided `value` in places
27204      * where Angular expects a $sce.trustAs() return value.
27205      */
27206     function trustAs(type, trustedValue) {
27207       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
27208       if (!Constructor) {
27209         throw $sceMinErr('icontext',
27210             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
27211             type, trustedValue);
27212       }
27213       if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
27214         return trustedValue;
27215       }
27216       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
27217       // mutable objects, we ensure here that the value passed in is actually a string.
27218       if (typeof trustedValue !== 'string') {
27219         throw $sceMinErr('itype',
27220             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
27221             type);
27222       }
27223       return new Constructor(trustedValue);
27224     }
27225
27226     /**
27227      * @ngdoc method
27228      * @name $sceDelegate#valueOf
27229      *
27230      * @description
27231      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
27232      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
27233      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
27234      *
27235      * If the passed parameter is not a value that had been returned by {@link
27236      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
27237      *
27238      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
27239      *      call or anything else.
27240      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
27241      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
27242      *     `value` unchanged.
27243      */
27244     function valueOf(maybeTrusted) {
27245       if (maybeTrusted instanceof trustedValueHolderBase) {
27246         return maybeTrusted.$$unwrapTrustedValue();
27247       } else {
27248         return maybeTrusted;
27249       }
27250     }
27251
27252     /**
27253      * @ngdoc method
27254      * @name $sceDelegate#getTrusted
27255      *
27256      * @description
27257      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
27258      * returns the originally supplied value if the queried context type is a supertype of the
27259      * created type.  If this condition isn't satisfied, throws an exception.
27260      *
27261      * <div class="alert alert-danger">
27262      * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
27263      * (XSS) vulnerability in your application.
27264      * </div>
27265      *
27266      * @param {string} type The kind of context in which this value is to be used.
27267      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
27268      *     `$sceDelegate.trustAs`} call.
27269      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
27270      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
27271      */
27272     function getTrusted(type, maybeTrusted) {
27273       if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
27274         return maybeTrusted;
27275       }
27276       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
27277       if (constructor && maybeTrusted instanceof constructor) {
27278         return maybeTrusted.$$unwrapTrustedValue();
27279       }
27280       // If we get here, then we may only take one of two actions.
27281       // 1. sanitize the value for the requested type, or
27282       // 2. throw an exception.
27283       if (type === SCE_CONTEXTS.RESOURCE_URL) {
27284         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
27285           return maybeTrusted;
27286         } else {
27287           throw $sceMinErr('insecurl',
27288               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
27289               maybeTrusted.toString());
27290         }
27291       } else if (type === SCE_CONTEXTS.HTML) {
27292         return htmlSanitizer(maybeTrusted);
27293       }
27294       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
27295     }
27296
27297     return { trustAs: trustAs,
27298              getTrusted: getTrusted,
27299              valueOf: valueOf };
27300   }];
27301 }
27302
27303
27304 /**
27305  * @ngdoc provider
27306  * @name $sceProvider
27307  * @description
27308  *
27309  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
27310  * -   enable/disable Strict Contextual Escaping (SCE) in a module
27311  * -   override the default implementation with a custom delegate
27312  *
27313  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
27314  */
27315
27316 /* jshint maxlen: false*/
27317
27318 /**
27319  * @ngdoc service
27320  * @name $sce
27321  * @kind function
27322  *
27323  * @description
27324  *
27325  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
27326  *
27327  * # Strict Contextual Escaping
27328  *
27329  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
27330  * contexts to result in a value that is marked as safe to use for that context.  One example of
27331  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
27332  * to these contexts as privileged or SCE contexts.
27333  *
27334  * As of version 1.2, Angular ships with SCE enabled by default.
27335  *
27336  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
27337  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
27338  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
27339  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
27340  * to the top of your HTML document.
27341  *
27342  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
27343  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
27344  *
27345  * Here's an example of a binding in a privileged context:
27346  *
27347  * ```
27348  * <input ng-model="userHtml" aria-label="User input">
27349  * <div ng-bind-html="userHtml"></div>
27350  * ```
27351  *
27352  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
27353  * disabled, this application allows the user to render arbitrary HTML into the DIV.
27354  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
27355  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
27356  * security vulnerabilities.)
27357  *
27358  * For the case of HTML, you might use a library, either on the client side, or on the server side,
27359  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
27360  *
27361  * How would you ensure that every place that used these types of bindings was bound to a value that
27362  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
27363  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
27364  * properties/fields and forgot to update the binding to the sanitized value?
27365  *
27366  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
27367  * determine that something explicitly says it's safe to use a value for binding in that
27368  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
27369  * for those values that you can easily tell are safe - because they were received from your server,
27370  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
27371  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
27372  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
27373  *
27374  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
27375  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
27376  * obtain values that will be accepted by SCE / privileged contexts.
27377  *
27378  *
27379  * ## How does it work?
27380  *
27381  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
27382  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
27383  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
27384  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
27385  *
27386  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
27387  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
27388  * simplified):
27389  *
27390  * ```
27391  * var ngBindHtmlDirective = ['$sce', function($sce) {
27392  *   return function(scope, element, attr) {
27393  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
27394  *       element.html(value || '');
27395  *     });
27396  *   };
27397  * }];
27398  * ```
27399  *
27400  * ## Impact on loading templates
27401  *
27402  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
27403  * `templateUrl`'s specified by {@link guide/directive directives}.
27404  *
27405  * By default, Angular only loads templates from the same domain and protocol as the application
27406  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
27407  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
27408  * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
27409  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
27410  *
27411  * *Please note*:
27412  * The browser's
27413  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
27414  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
27415  * policy apply in addition to this and may further restrict whether the template is successfully
27416  * loaded.  This means that without the right CORS policy, loading templates from a different domain
27417  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
27418  * browsers.
27419  *
27420  * ## This feels like too much overhead
27421  *
27422  * It's important to remember that SCE only applies to interpolation expressions.
27423  *
27424  * If your expressions are constant literals, they're automatically trusted and you don't need to
27425  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
27426  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
27427  *
27428  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
27429  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
27430  *
27431  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
27432  * templates in `ng-include` from your application's domain without having to even know about SCE.
27433  * It blocks loading templates from other domains or loading templates over http from an https
27434  * served document.  You can change these by setting your own custom {@link
27435  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
27436  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
27437  *
27438  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
27439  * application that's secure and can be audited to verify that with much more ease than bolting
27440  * security onto an application later.
27441  *
27442  * <a name="contexts"></a>
27443  * ## What trusted context types are supported?
27444  *
27445  * | Context             | Notes          |
27446  * |---------------------|----------------|
27447  * | `$sce.HTML`         | For HTML that's safe to source into the application.  The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. |
27448  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
27449  * | `$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. |
27450  * | `$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. |
27451  * | `$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. |
27452  *
27453  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
27454  *
27455  *  Each element in these arrays must be one of the following:
27456  *
27457  *  - **'self'**
27458  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
27459  *      domain** as the application document using the **same protocol**.
27460  *  - **String** (except the special value `'self'`)
27461  *    - The string is matched against the full *normalized / absolute URL* of the resource
27462  *      being tested (substring matches are not good enough.)
27463  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
27464  *      match themselves.
27465  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
27466  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
27467  *      in a whitelist.
27468  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
27469  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
27470  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
27471  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
27472  *      http://foo.example.com/templates/**).
27473  *  - **RegExp** (*see caveat below*)
27474  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
27475  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
27476  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
27477  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
27478  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
27479  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
27480  *      is highly recommended to use the string patterns and only fall back to regular expressions
27481  *      as a last resort.
27482  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
27483  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
27484  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
27485  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
27486  *    - If you are generating your JavaScript from some other templating engine (not
27487  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
27488  *      remember to escape your regular expression (and be aware that you might need more than
27489  *      one level of escaping depending on your templating engine and the way you interpolated
27490  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
27491  *      enough before coding your own.  E.g. Ruby has
27492  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
27493  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
27494  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
27495  *      Closure library's [goog.string.regExpEscape(s)](
27496  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
27497  *
27498  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
27499  *
27500  * ## Show me an example using SCE.
27501  *
27502  * <example module="mySceApp" deps="angular-sanitize.js">
27503  * <file name="index.html">
27504  *   <div ng-controller="AppController as myCtrl">
27505  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
27506  *     <b>User comments</b><br>
27507  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
27508  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
27509  *     exploit.
27510  *     <div class="well">
27511  *       <div ng-repeat="userComment in myCtrl.userComments">
27512  *         <b>{{userComment.name}}</b>:
27513  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
27514  *         <br>
27515  *       </div>
27516  *     </div>
27517  *   </div>
27518  * </file>
27519  *
27520  * <file name="script.js">
27521  *   angular.module('mySceApp', ['ngSanitize'])
27522  *     .controller('AppController', ['$http', '$templateCache', '$sce',
27523  *       function($http, $templateCache, $sce) {
27524  *         var self = this;
27525  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
27526  *           self.userComments = userComments;
27527  *         });
27528  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
27529  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
27530  *             'sanitization.&quot;">Hover over this text.</span>');
27531  *       }]);
27532  * </file>
27533  *
27534  * <file name="test_data.json">
27535  * [
27536  *   { "name": "Alice",
27537  *     "htmlComment":
27538  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
27539  *   },
27540  *   { "name": "Bob",
27541  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
27542  *   }
27543  * ]
27544  * </file>
27545  *
27546  * <file name="protractor.js" type="protractor">
27547  *   describe('SCE doc demo', function() {
27548  *     it('should sanitize untrusted values', function() {
27549  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
27550  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
27551  *     });
27552  *
27553  *     it('should NOT sanitize explicitly trusted values', function() {
27554  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
27555  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
27556  *           'sanitization.&quot;">Hover over this text.</span>');
27557  *     });
27558  *   });
27559  * </file>
27560  * </example>
27561  *
27562  *
27563  *
27564  * ## Can I disable SCE completely?
27565  *
27566  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
27567  * for little coding overhead.  It will be much harder to take an SCE disabled application and
27568  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
27569  * for cases where you have a lot of existing code that was written before SCE was introduced and
27570  * you're migrating them a module at a time.
27571  *
27572  * That said, here's how you can completely disable SCE:
27573  *
27574  * ```
27575  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
27576  *   // Completely disable SCE.  For demonstration purposes only!
27577  *   // Do not use in new projects.
27578  *   $sceProvider.enabled(false);
27579  * });
27580  * ```
27581  *
27582  */
27583 /* jshint maxlen: 100 */
27584
27585 function $SceProvider() {
27586   var enabled = true;
27587
27588   /**
27589    * @ngdoc method
27590    * @name $sceProvider#enabled
27591    * @kind function
27592    *
27593    * @param {boolean=} value If provided, then enables/disables SCE.
27594    * @return {boolean} true if SCE is enabled, false otherwise.
27595    *
27596    * @description
27597    * Enables/disables SCE and returns the current value.
27598    */
27599   this.enabled = function(value) {
27600     if (arguments.length) {
27601       enabled = !!value;
27602     }
27603     return enabled;
27604   };
27605
27606
27607   /* Design notes on the default implementation for SCE.
27608    *
27609    * The API contract for the SCE delegate
27610    * -------------------------------------
27611    * The SCE delegate object must provide the following 3 methods:
27612    *
27613    * - trustAs(contextEnum, value)
27614    *     This method is used to tell the SCE service that the provided value is OK to use in the
27615    *     contexts specified by contextEnum.  It must return an object that will be accepted by
27616    *     getTrusted() for a compatible contextEnum and return this value.
27617    *
27618    * - valueOf(value)
27619    *     For values that were not produced by trustAs(), return them as is.  For values that were
27620    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
27621    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
27622    *     such a value.
27623    *
27624    * - getTrusted(contextEnum, value)
27625    *     This function should return the a value that is safe to use in the context specified by
27626    *     contextEnum or throw and exception otherwise.
27627    *
27628    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
27629    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
27630    * instance, an implementation could maintain a registry of all trusted objects by context.  In
27631    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
27632    * return the same object passed in if it was found in the registry under a compatible context or
27633    * throw an exception otherwise.  An implementation might only wrap values some of the time based
27634    * on some criteria.  getTrusted() might return a value and not throw an exception for special
27635    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
27636    *
27637    *
27638    * A note on the inheritance model for SCE contexts
27639    * ------------------------------------------------
27640    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
27641    * is purely an implementation details.
27642    *
27643    * The contract is simply this:
27644    *
27645    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
27646    *     will also succeed.
27647    *
27648    * Inheritance happens to capture this in a natural way.  In some future, we
27649    * may not use inheritance anymore.  That is OK because no code outside of
27650    * sce.js and sceSpecs.js would need to be aware of this detail.
27651    */
27652
27653   this.$get = ['$parse', '$sceDelegate', function(
27654                 $parse,   $sceDelegate) {
27655     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
27656     // the "expression(javascript expression)" syntax which is insecure.
27657     if (enabled && msie < 8) {
27658       throw $sceMinErr('iequirks',
27659         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
27660         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
27661         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
27662     }
27663
27664     var sce = shallowCopy(SCE_CONTEXTS);
27665
27666     /**
27667      * @ngdoc method
27668      * @name $sce#isEnabled
27669      * @kind function
27670      *
27671      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
27672      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
27673      *
27674      * @description
27675      * Returns a boolean indicating if SCE is enabled.
27676      */
27677     sce.isEnabled = function() {
27678       return enabled;
27679     };
27680     sce.trustAs = $sceDelegate.trustAs;
27681     sce.getTrusted = $sceDelegate.getTrusted;
27682     sce.valueOf = $sceDelegate.valueOf;
27683
27684     if (!enabled) {
27685       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
27686       sce.valueOf = identity;
27687     }
27688
27689     /**
27690      * @ngdoc method
27691      * @name $sce#parseAs
27692      *
27693      * @description
27694      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
27695      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
27696      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
27697      * *result*)}
27698      *
27699      * @param {string} type The kind of SCE context in which this result will be used.
27700      * @param {string} expression String expression to compile.
27701      * @returns {function(context, locals)} a function which represents the compiled expression:
27702      *
27703      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27704      *      are evaluated against (typically a scope object).
27705      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27706      *      `context`.
27707      */
27708     sce.parseAs = function sceParseAs(type, expr) {
27709       var parsed = $parse(expr);
27710       if (parsed.literal && parsed.constant) {
27711         return parsed;
27712       } else {
27713         return $parse(expr, function(value) {
27714           return sce.getTrusted(type, value);
27715         });
27716       }
27717     };
27718
27719     /**
27720      * @ngdoc method
27721      * @name $sce#trustAs
27722      *
27723      * @description
27724      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
27725      * returns an object that is trusted by angular for use in specified strict contextual
27726      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
27727      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
27728      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
27729      * escaping.
27730      *
27731      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
27732      *   resourceUrl, html, js and css.
27733      * @param {*} value The value that that should be considered trusted/safe.
27734      * @returns {*} A value that can be used to stand in for the provided `value` in places
27735      * where Angular expects a $sce.trustAs() return value.
27736      */
27737
27738     /**
27739      * @ngdoc method
27740      * @name $sce#trustAsHtml
27741      *
27742      * @description
27743      * Shorthand method.  `$sce.trustAsHtml(value)` â†’
27744      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
27745      *
27746      * @param {*} value The value to trustAs.
27747      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
27748      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
27749      *     only accept expressions that are either literal constants or are the
27750      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27751      */
27752
27753     /**
27754      * @ngdoc method
27755      * @name $sce#trustAsUrl
27756      *
27757      * @description
27758      * Shorthand method.  `$sce.trustAsUrl(value)` â†’
27759      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
27760      *
27761      * @param {*} value The value to trustAs.
27762      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
27763      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
27764      *     only accept expressions that are either literal constants or are the
27765      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27766      */
27767
27768     /**
27769      * @ngdoc method
27770      * @name $sce#trustAsResourceUrl
27771      *
27772      * @description
27773      * Shorthand method.  `$sce.trustAsResourceUrl(value)` â†’
27774      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
27775      *
27776      * @param {*} value The value to trustAs.
27777      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
27778      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
27779      *     only accept expressions that are either literal constants or are the return
27780      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
27781      */
27782
27783     /**
27784      * @ngdoc method
27785      * @name $sce#trustAsJs
27786      *
27787      * @description
27788      * Shorthand method.  `$sce.trustAsJs(value)` â†’
27789      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
27790      *
27791      * @param {*} value The value to trustAs.
27792      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
27793      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
27794      *     only accept expressions that are either literal constants or are the
27795      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27796      */
27797
27798     /**
27799      * @ngdoc method
27800      * @name $sce#getTrusted
27801      *
27802      * @description
27803      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
27804      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
27805      * originally supplied value if the queried context type is a supertype of the created type.
27806      * If this condition isn't satisfied, throws an exception.
27807      *
27808      * @param {string} type The kind of context in which this value is to be used.
27809      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
27810      *                         call.
27811      * @returns {*} The value the was originally provided to
27812      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
27813      *              Otherwise, throws an exception.
27814      */
27815
27816     /**
27817      * @ngdoc method
27818      * @name $sce#getTrustedHtml
27819      *
27820      * @description
27821      * Shorthand method.  `$sce.getTrustedHtml(value)` â†’
27822      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
27823      *
27824      * @param {*} value The value to pass to `$sce.getTrusted`.
27825      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
27826      */
27827
27828     /**
27829      * @ngdoc method
27830      * @name $sce#getTrustedCss
27831      *
27832      * @description
27833      * Shorthand method.  `$sce.getTrustedCss(value)` â†’
27834      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
27835      *
27836      * @param {*} value The value to pass to `$sce.getTrusted`.
27837      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
27838      */
27839
27840     /**
27841      * @ngdoc method
27842      * @name $sce#getTrustedUrl
27843      *
27844      * @description
27845      * Shorthand method.  `$sce.getTrustedUrl(value)` â†’
27846      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
27847      *
27848      * @param {*} value The value to pass to `$sce.getTrusted`.
27849      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
27850      */
27851
27852     /**
27853      * @ngdoc method
27854      * @name $sce#getTrustedResourceUrl
27855      *
27856      * @description
27857      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` â†’
27858      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
27859      *
27860      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
27861      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
27862      */
27863
27864     /**
27865      * @ngdoc method
27866      * @name $sce#getTrustedJs
27867      *
27868      * @description
27869      * Shorthand method.  `$sce.getTrustedJs(value)` â†’
27870      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
27871      *
27872      * @param {*} value The value to pass to `$sce.getTrusted`.
27873      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
27874      */
27875
27876     /**
27877      * @ngdoc method
27878      * @name $sce#parseAsHtml
27879      *
27880      * @description
27881      * Shorthand method.  `$sce.parseAsHtml(expression string)` â†’
27882      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
27883      *
27884      * @param {string} expression String expression to compile.
27885      * @returns {function(context, locals)} a function which represents the compiled expression:
27886      *
27887      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27888      *      are evaluated against (typically a scope object).
27889      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27890      *      `context`.
27891      */
27892
27893     /**
27894      * @ngdoc method
27895      * @name $sce#parseAsCss
27896      *
27897      * @description
27898      * Shorthand method.  `$sce.parseAsCss(value)` â†’
27899      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
27900      *
27901      * @param {string} expression String expression to compile.
27902      * @returns {function(context, locals)} a function which represents the compiled expression:
27903      *
27904      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27905      *      are evaluated against (typically a scope object).
27906      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27907      *      `context`.
27908      */
27909
27910     /**
27911      * @ngdoc method
27912      * @name $sce#parseAsUrl
27913      *
27914      * @description
27915      * Shorthand method.  `$sce.parseAsUrl(value)` â†’
27916      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
27917      *
27918      * @param {string} expression String expression to compile.
27919      * @returns {function(context, locals)} a function which represents the compiled expression:
27920      *
27921      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27922      *      are evaluated against (typically a scope object).
27923      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27924      *      `context`.
27925      */
27926
27927     /**
27928      * @ngdoc method
27929      * @name $sce#parseAsResourceUrl
27930      *
27931      * @description
27932      * Shorthand method.  `$sce.parseAsResourceUrl(value)` â†’
27933      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
27934      *
27935      * @param {string} expression String expression to compile.
27936      * @returns {function(context, locals)} a function which represents the compiled expression:
27937      *
27938      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27939      *      are evaluated against (typically a scope object).
27940      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27941      *      `context`.
27942      */
27943
27944     /**
27945      * @ngdoc method
27946      * @name $sce#parseAsJs
27947      *
27948      * @description
27949      * Shorthand method.  `$sce.parseAsJs(value)` â†’
27950      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
27951      *
27952      * @param {string} expression String expression to compile.
27953      * @returns {function(context, locals)} a function which represents the compiled expression:
27954      *
27955      *    * `context` â€“ `{object}` â€“ an object against which any expressions embedded in the strings
27956      *      are evaluated against (typically a scope object).
27957      *    * `locals` â€“ `{object=}` â€“ local variables context object, useful for overriding values in
27958      *      `context`.
27959      */
27960
27961     // Shorthand delegations.
27962     var parse = sce.parseAs,
27963         getTrusted = sce.getTrusted,
27964         trustAs = sce.trustAs;
27965
27966     forEach(SCE_CONTEXTS, function(enumValue, name) {
27967       var lName = lowercase(name);
27968       sce[camelCase("parse_as_" + lName)] = function(expr) {
27969         return parse(enumValue, expr);
27970       };
27971       sce[camelCase("get_trusted_" + lName)] = function(value) {
27972         return getTrusted(enumValue, value);
27973       };
27974       sce[camelCase("trust_as_" + lName)] = function(value) {
27975         return trustAs(enumValue, value);
27976       };
27977     });
27978
27979     return sce;
27980   }];
27981 }
27982
27983 /**
27984  * !!! This is an undocumented "private" service !!!
27985  *
27986  * @name $sniffer
27987  * @requires $window
27988  * @requires $document
27989  *
27990  * @property {boolean} history Does the browser support html5 history api ?
27991  * @property {boolean} transitions Does the browser support CSS transition events ?
27992  * @property {boolean} animations Does the browser support CSS animation events ?
27993  *
27994  * @description
27995  * This is very simple implementation of testing browser's features.
27996  */
27997 function $SnifferProvider() {
27998   this.$get = ['$window', '$document', function($window, $document) {
27999     var eventSupport = {},
28000         // Chrome Packaged Apps are not allowed to access `history.pushState`. They can be detected by
28001         // the presence of `chrome.app.runtime` (see https://developer.chrome.com/apps/api_index)
28002         isChromePackagedApp = $window.chrome && $window.chrome.app && $window.chrome.app.runtime,
28003         hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,
28004         android =
28005           toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
28006         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
28007         document = $document[0] || {},
28008         vendorPrefix,
28009         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
28010         bodyStyle = document.body && document.body.style,
28011         transitions = false,
28012         animations = false,
28013         match;
28014
28015     if (bodyStyle) {
28016       for (var prop in bodyStyle) {
28017         if (match = vendorRegex.exec(prop)) {
28018           vendorPrefix = match[0];
28019           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
28020           break;
28021         }
28022       }
28023
28024       if (!vendorPrefix) {
28025         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
28026       }
28027
28028       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
28029       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
28030
28031       if (android && (!transitions ||  !animations)) {
28032         transitions = isString(bodyStyle.webkitTransition);
28033         animations = isString(bodyStyle.webkitAnimation);
28034       }
28035     }
28036
28037
28038     return {
28039       // Android has history.pushState, but it does not update location correctly
28040       // so let's not use the history API at all.
28041       // http://code.google.com/p/android/issues/detail?id=17471
28042       // https://github.com/angular/angular.js/issues/904
28043
28044       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
28045       // so let's not use the history API also
28046       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
28047       // jshint -W018
28048       history: !!(hasHistoryPushState && !(android < 4) && !boxee),
28049       // jshint +W018
28050       hasEvent: function(event) {
28051         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
28052         // it. In particular the event is not fired when backspace or delete key are pressed or
28053         // when cut operation is performed.
28054         // IE10+ implements 'input' event but it erroneously fires under various situations,
28055         // e.g. when placeholder changes, or a form is focused.
28056         if (event === 'input' && msie <= 11) return false;
28057
28058         if (isUndefined(eventSupport[event])) {
28059           var divElm = document.createElement('div');
28060           eventSupport[event] = 'on' + event in divElm;
28061         }
28062
28063         return eventSupport[event];
28064       },
28065       csp: csp(),
28066       vendorPrefix: vendorPrefix,
28067       transitions: transitions,
28068       animations: animations,
28069       android: android
28070     };
28071   }];
28072 }
28073
28074 var $templateRequestMinErr = minErr('$compile');
28075
28076 /**
28077  * @ngdoc provider
28078  * @name $templateRequestProvider
28079  * @description
28080  * Used to configure the options passed to the {@link $http} service when making a template request.
28081  *
28082  * For example, it can be used for specifying the "Accept" header that is sent to the server, when
28083  * requesting a template.
28084  */
28085 function $TemplateRequestProvider() {
28086
28087   var httpOptions;
28088
28089   /**
28090    * @ngdoc method
28091    * @name $templateRequestProvider#httpOptions
28092    * @description
28093    * The options to be passed to the {@link $http} service when making the request.
28094    * You can use this to override options such as the "Accept" header for template requests.
28095    *
28096    * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
28097    * options if not overridden here.
28098    *
28099    * @param {string=} value new value for the {@link $http} options.
28100    * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
28101    */
28102   this.httpOptions = function(val) {
28103     if (val) {
28104       httpOptions = val;
28105       return this;
28106     }
28107     return httpOptions;
28108   };
28109
28110   /**
28111    * @ngdoc service
28112    * @name $templateRequest
28113    *
28114    * @description
28115    * The `$templateRequest` service runs security checks then downloads the provided template using
28116    * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
28117    * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
28118    * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
28119    * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
28120    * when `tpl` is of type string and `$templateCache` has the matching entry.
28121    *
28122    * If you want to pass custom options to the `$http` service, such as setting the Accept header you
28123    * can configure this via {@link $templateRequestProvider#httpOptions}.
28124    *
28125    * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
28126    * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
28127    *
28128    * @return {Promise} a promise for the HTTP response data of the given URL.
28129    *
28130    * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
28131    */
28132   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
28133
28134     function handleRequestFn(tpl, ignoreRequestError) {
28135       handleRequestFn.totalPendingRequests++;
28136
28137       // We consider the template cache holds only trusted templates, so
28138       // there's no need to go through whitelisting again for keys that already
28139       // are included in there. This also makes Angular accept any script
28140       // directive, no matter its name. However, we still need to unwrap trusted
28141       // types.
28142       if (!isString(tpl) || !$templateCache.get(tpl)) {
28143         tpl = $sce.getTrustedResourceUrl(tpl);
28144       }
28145
28146       var transformResponse = $http.defaults && $http.defaults.transformResponse;
28147
28148       if (isArray(transformResponse)) {
28149         transformResponse = transformResponse.filter(function(transformer) {
28150           return transformer !== defaultHttpResponseTransform;
28151         });
28152       } else if (transformResponse === defaultHttpResponseTransform) {
28153         transformResponse = null;
28154       }
28155
28156       return $http.get(tpl, extend({
28157           cache: $templateCache,
28158           transformResponse: transformResponse
28159         }, httpOptions))
28160         ['finally'](function() {
28161           handleRequestFn.totalPendingRequests--;
28162         })
28163         .then(function(response) {
28164           $templateCache.put(tpl, response.data);
28165           return response.data;
28166         }, handleError);
28167
28168       function handleError(resp) {
28169         if (!ignoreRequestError) {
28170           throw $templateRequestMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
28171             tpl, resp.status, resp.statusText);
28172         }
28173         return $q.reject(resp);
28174       }
28175     }
28176
28177     handleRequestFn.totalPendingRequests = 0;
28178
28179     return handleRequestFn;
28180   }];
28181 }
28182
28183 function $$TestabilityProvider() {
28184   this.$get = ['$rootScope', '$browser', '$location',
28185        function($rootScope,   $browser,   $location) {
28186
28187     /**
28188      * @name $testability
28189      *
28190      * @description
28191      * The private $$testability service provides a collection of methods for use when debugging
28192      * or by automated test and debugging tools.
28193      */
28194     var testability = {};
28195
28196     /**
28197      * @name $$testability#findBindings
28198      *
28199      * @description
28200      * Returns an array of elements that are bound (via ng-bind or {{}})
28201      * to expressions matching the input.
28202      *
28203      * @param {Element} element The element root to search from.
28204      * @param {string} expression The binding expression to match.
28205      * @param {boolean} opt_exactMatch If true, only returns exact matches
28206      *     for the expression. Filters and whitespace are ignored.
28207      */
28208     testability.findBindings = function(element, expression, opt_exactMatch) {
28209       var bindings = element.getElementsByClassName('ng-binding');
28210       var matches = [];
28211       forEach(bindings, function(binding) {
28212         var dataBinding = angular.element(binding).data('$binding');
28213         if (dataBinding) {
28214           forEach(dataBinding, function(bindingName) {
28215             if (opt_exactMatch) {
28216               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
28217               if (matcher.test(bindingName)) {
28218                 matches.push(binding);
28219               }
28220             } else {
28221               if (bindingName.indexOf(expression) != -1) {
28222                 matches.push(binding);
28223               }
28224             }
28225           });
28226         }
28227       });
28228       return matches;
28229     };
28230
28231     /**
28232      * @name $$testability#findModels
28233      *
28234      * @description
28235      * Returns an array of elements that are two-way found via ng-model to
28236      * expressions matching the input.
28237      *
28238      * @param {Element} element The element root to search from.
28239      * @param {string} expression The model expression to match.
28240      * @param {boolean} opt_exactMatch If true, only returns exact matches
28241      *     for the expression.
28242      */
28243     testability.findModels = function(element, expression, opt_exactMatch) {
28244       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
28245       for (var p = 0; p < prefixes.length; ++p) {
28246         var attributeEquals = opt_exactMatch ? '=' : '*=';
28247         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
28248         var elements = element.querySelectorAll(selector);
28249         if (elements.length) {
28250           return elements;
28251         }
28252       }
28253     };
28254
28255     /**
28256      * @name $$testability#getLocation
28257      *
28258      * @description
28259      * Shortcut for getting the location in a browser agnostic way. Returns
28260      *     the path, search, and hash. (e.g. /path?a=b#hash)
28261      */
28262     testability.getLocation = function() {
28263       return $location.url();
28264     };
28265
28266     /**
28267      * @name $$testability#setLocation
28268      *
28269      * @description
28270      * Shortcut for navigating to a location without doing a full page reload.
28271      *
28272      * @param {string} url The location url (path, search and hash,
28273      *     e.g. /path?a=b#hash) to go to.
28274      */
28275     testability.setLocation = function(url) {
28276       if (url !== $location.url()) {
28277         $location.url(url);
28278         $rootScope.$digest();
28279       }
28280     };
28281
28282     /**
28283      * @name $$testability#whenStable
28284      *
28285      * @description
28286      * Calls the callback when $timeout and $http requests are completed.
28287      *
28288      * @param {function} callback
28289      */
28290     testability.whenStable = function(callback) {
28291       $browser.notifyWhenNoOutstandingRequests(callback);
28292     };
28293
28294     return testability;
28295   }];
28296 }
28297
28298 function $TimeoutProvider() {
28299   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
28300        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
28301
28302     var deferreds = {};
28303
28304
28305      /**
28306       * @ngdoc service
28307       * @name $timeout
28308       *
28309       * @description
28310       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
28311       * block and delegates any exceptions to
28312       * {@link ng.$exceptionHandler $exceptionHandler} service.
28313       *
28314       * The return value of calling `$timeout` is a promise, which will be resolved when
28315       * the delay has passed and the timeout function, if provided, is executed.
28316       *
28317       * To cancel a timeout request, call `$timeout.cancel(promise)`.
28318       *
28319       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
28320       * synchronously flush the queue of deferred functions.
28321       *
28322       * If you only want a promise that will be resolved after some specified delay
28323       * then you can call `$timeout` without the `fn` function.
28324       *
28325       * @param {function()=} fn A function, whose execution should be delayed.
28326       * @param {number=} [delay=0] Delay in milliseconds.
28327       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
28328       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
28329       * @param {...*=} Pass additional parameters to the executed function.
28330       * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
28331       *   will be resolved with the return value of the `fn` function.
28332       *
28333       */
28334     function timeout(fn, delay, invokeApply) {
28335       if (!isFunction(fn)) {
28336         invokeApply = delay;
28337         delay = fn;
28338         fn = noop;
28339       }
28340
28341       var args = sliceArgs(arguments, 3),
28342           skipApply = (isDefined(invokeApply) && !invokeApply),
28343           deferred = (skipApply ? $$q : $q).defer(),
28344           promise = deferred.promise,
28345           timeoutId;
28346
28347       timeoutId = $browser.defer(function() {
28348         try {
28349           deferred.resolve(fn.apply(null, args));
28350         } catch (e) {
28351           deferred.reject(e);
28352           $exceptionHandler(e);
28353         }
28354         finally {
28355           delete deferreds[promise.$$timeoutId];
28356         }
28357
28358         if (!skipApply) $rootScope.$apply();
28359       }, delay);
28360
28361       promise.$$timeoutId = timeoutId;
28362       deferreds[timeoutId] = deferred;
28363
28364       return promise;
28365     }
28366
28367
28368      /**
28369       * @ngdoc method
28370       * @name $timeout#cancel
28371       *
28372       * @description
28373       * Cancels a task associated with the `promise`. As a result of this, the promise will be
28374       * resolved with a rejection.
28375       *
28376       * @param {Promise=} promise Promise returned by the `$timeout` function.
28377       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
28378       *   canceled.
28379       */
28380     timeout.cancel = function(promise) {
28381       if (promise && promise.$$timeoutId in deferreds) {
28382         deferreds[promise.$$timeoutId].reject('canceled');
28383         delete deferreds[promise.$$timeoutId];
28384         return $browser.defer.cancel(promise.$$timeoutId);
28385       }
28386       return false;
28387     };
28388
28389     return timeout;
28390   }];
28391 }
28392
28393 // NOTE:  The usage of window and document instead of $window and $document here is
28394 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
28395 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
28396 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
28397 // doesn't know about mocked locations and resolves URLs to the real document - which is
28398 // exactly the behavior needed here.  There is little value is mocking these out for this
28399 // service.
28400 var urlParsingNode = window.document.createElement("a");
28401 var originUrl = urlResolve(window.location.href);
28402
28403
28404 /**
28405  *
28406  * Implementation Notes for non-IE browsers
28407  * ----------------------------------------
28408  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
28409  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
28410  * URL will be resolved into an absolute URL in the context of the application document.
28411  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
28412  * properties are all populated to reflect the normalized URL.  This approach has wide
28413  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
28414  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
28415  *
28416  * Implementation Notes for IE
28417  * ---------------------------
28418  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
28419  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
28420  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
28421  * work around that by performing the parsing in a 2nd step by taking a previously normalized
28422  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
28423  * properties such as protocol, hostname, port, etc.
28424  *
28425  * References:
28426  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
28427  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
28428  *   http://url.spec.whatwg.org/#urlutils
28429  *   https://github.com/angular/angular.js/pull/2902
28430  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
28431  *
28432  * @kind function
28433  * @param {string} url The URL to be parsed.
28434  * @description Normalizes and parses a URL.
28435  * @returns {object} Returns the normalized URL as a dictionary.
28436  *
28437  *   | member name   | Description    |
28438  *   |---------------|----------------|
28439  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
28440  *   | protocol      | The protocol including the trailing colon                              |
28441  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
28442  *   | search        | The search params, minus the question mark                             |
28443  *   | hash          | The hash string, minus the hash symbol
28444  *   | hostname      | The hostname
28445  *   | port          | The port, without ":"
28446  *   | pathname      | The pathname, beginning with "/"
28447  *
28448  */
28449 function urlResolve(url) {
28450   var href = url;
28451
28452   if (msie) {
28453     // Normalize before parse.  Refer Implementation Notes on why this is
28454     // done in two steps on IE.
28455     urlParsingNode.setAttribute("href", href);
28456     href = urlParsingNode.href;
28457   }
28458
28459   urlParsingNode.setAttribute('href', href);
28460
28461   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
28462   return {
28463     href: urlParsingNode.href,
28464     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
28465     host: urlParsingNode.host,
28466     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
28467     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
28468     hostname: urlParsingNode.hostname,
28469     port: urlParsingNode.port,
28470     pathname: (urlParsingNode.pathname.charAt(0) === '/')
28471       ? urlParsingNode.pathname
28472       : '/' + urlParsingNode.pathname
28473   };
28474 }
28475
28476 /**
28477  * Parse a request URL and determine whether this is a same-origin request as the application document.
28478  *
28479  * @param {string|object} requestUrl The url of the request as a string that will be resolved
28480  * or a parsed URL object.
28481  * @returns {boolean} Whether the request is for the same origin as the application document.
28482  */
28483 function urlIsSameOrigin(requestUrl) {
28484   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
28485   return (parsed.protocol === originUrl.protocol &&
28486           parsed.host === originUrl.host);
28487 }
28488
28489 /**
28490  * @ngdoc service
28491  * @name $window
28492  *
28493  * @description
28494  * A reference to the browser's `window` object. While `window`
28495  * is globally available in JavaScript, it causes testability problems, because
28496  * it is a global variable. In angular we always refer to it through the
28497  * `$window` service, so it may be overridden, removed or mocked for testing.
28498  *
28499  * Expressions, like the one defined for the `ngClick` directive in the example
28500  * below, are evaluated with respect to the current scope.  Therefore, there is
28501  * no risk of inadvertently coding in a dependency on a global value in such an
28502  * expression.
28503  *
28504  * @example
28505    <example module="windowExample">
28506      <file name="index.html">
28507        <script>
28508          angular.module('windowExample', [])
28509            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
28510              $scope.greeting = 'Hello, World!';
28511              $scope.doGreeting = function(greeting) {
28512                $window.alert(greeting);
28513              };
28514            }]);
28515        </script>
28516        <div ng-controller="ExampleController">
28517          <input type="text" ng-model="greeting" aria-label="greeting" />
28518          <button ng-click="doGreeting(greeting)">ALERT</button>
28519        </div>
28520      </file>
28521      <file name="protractor.js" type="protractor">
28522       it('should display the greeting in the input box', function() {
28523        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
28524        // If we click the button it will block the test runner
28525        // element(':button').click();
28526       });
28527      </file>
28528    </example>
28529  */
28530 function $WindowProvider() {
28531   this.$get = valueFn(window);
28532 }
28533
28534 /**
28535  * @name $$cookieReader
28536  * @requires $document
28537  *
28538  * @description
28539  * This is a private service for reading cookies used by $http and ngCookies
28540  *
28541  * @return {Object} a key/value map of the current cookies
28542  */
28543 function $$CookieReader($document) {
28544   var rawDocument = $document[0] || {};
28545   var lastCookies = {};
28546   var lastCookieString = '';
28547
28548   function safeDecodeURIComponent(str) {
28549     try {
28550       return decodeURIComponent(str);
28551     } catch (e) {
28552       return str;
28553     }
28554   }
28555
28556   return function() {
28557     var cookieArray, cookie, i, index, name;
28558     var currentCookieString = rawDocument.cookie || '';
28559
28560     if (currentCookieString !== lastCookieString) {
28561       lastCookieString = currentCookieString;
28562       cookieArray = lastCookieString.split('; ');
28563       lastCookies = {};
28564
28565       for (i = 0; i < cookieArray.length; i++) {
28566         cookie = cookieArray[i];
28567         index = cookie.indexOf('=');
28568         if (index > 0) { //ignore nameless cookies
28569           name = safeDecodeURIComponent(cookie.substring(0, index));
28570           // the first value that is seen for a cookie is the most
28571           // specific one.  values for the same cookie name that
28572           // follow are for less specific paths.
28573           if (isUndefined(lastCookies[name])) {
28574             lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
28575           }
28576         }
28577       }
28578     }
28579     return lastCookies;
28580   };
28581 }
28582
28583 $$CookieReader.$inject = ['$document'];
28584
28585 function $$CookieReaderProvider() {
28586   this.$get = $$CookieReader;
28587 }
28588
28589 /* global currencyFilter: true,
28590  dateFilter: true,
28591  filterFilter: true,
28592  jsonFilter: true,
28593  limitToFilter: true,
28594  lowercaseFilter: true,
28595  numberFilter: true,
28596  orderByFilter: true,
28597  uppercaseFilter: true,
28598  */
28599
28600 /**
28601  * @ngdoc provider
28602  * @name $filterProvider
28603  * @description
28604  *
28605  * Filters are just functions which transform input to an output. However filters need to be
28606  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
28607  * annotated with dependencies and is responsible for creating a filter function.
28608  *
28609  * <div class="alert alert-warning">
28610  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
28611  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
28612  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
28613  * (`myapp_subsection_filterx`).
28614  * </div>
28615  *
28616  * ```js
28617  *   // Filter registration
28618  *   function MyModule($provide, $filterProvider) {
28619  *     // create a service to demonstrate injection (not always needed)
28620  *     $provide.value('greet', function(name){
28621  *       return 'Hello ' + name + '!';
28622  *     });
28623  *
28624  *     // register a filter factory which uses the
28625  *     // greet service to demonstrate DI.
28626  *     $filterProvider.register('greet', function(greet){
28627  *       // return the filter function which uses the greet service
28628  *       // to generate salutation
28629  *       return function(text) {
28630  *         // filters need to be forgiving so check input validity
28631  *         return text && greet(text) || text;
28632  *       };
28633  *     });
28634  *   }
28635  * ```
28636  *
28637  * The filter function is registered with the `$injector` under the filter name suffix with
28638  * `Filter`.
28639  *
28640  * ```js
28641  *   it('should be the same instance', inject(
28642  *     function($filterProvider) {
28643  *       $filterProvider.register('reverse', function(){
28644  *         return ...;
28645  *       });
28646  *     },
28647  *     function($filter, reverseFilter) {
28648  *       expect($filter('reverse')).toBe(reverseFilter);
28649  *     });
28650  * ```
28651  *
28652  *
28653  * For more information about how angular filters work, and how to create your own filters, see
28654  * {@link guide/filter Filters} in the Angular Developer Guide.
28655  */
28656
28657 /**
28658  * @ngdoc service
28659  * @name $filter
28660  * @kind function
28661  * @description
28662  * Filters are used for formatting data displayed to the user.
28663  *
28664  * The general syntax in templates is as follows:
28665  *
28666  *         {{ expression [| filter_name[:parameter_value] ... ] }}
28667  *
28668  * @param {String} name Name of the filter function to retrieve
28669  * @return {Function} the filter function
28670  * @example
28671    <example name="$filter" module="filterExample">
28672      <file name="index.html">
28673        <div ng-controller="MainCtrl">
28674         <h3>{{ originalText }}</h3>
28675         <h3>{{ filteredText }}</h3>
28676        </div>
28677      </file>
28678
28679      <file name="script.js">
28680       angular.module('filterExample', [])
28681       .controller('MainCtrl', function($scope, $filter) {
28682         $scope.originalText = 'hello';
28683         $scope.filteredText = $filter('uppercase')($scope.originalText);
28684       });
28685      </file>
28686    </example>
28687   */
28688 $FilterProvider.$inject = ['$provide'];
28689 function $FilterProvider($provide) {
28690   var suffix = 'Filter';
28691
28692   /**
28693    * @ngdoc method
28694    * @name $filterProvider#register
28695    * @param {string|Object} name Name of the filter function, or an object map of filters where
28696    *    the keys are the filter names and the values are the filter factories.
28697    *
28698    *    <div class="alert alert-warning">
28699    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
28700    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
28701    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
28702    *    (`myapp_subsection_filterx`).
28703    *    </div>
28704     * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
28705    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
28706    *    of the registered filter instances.
28707    */
28708   function register(name, factory) {
28709     if (isObject(name)) {
28710       var filters = {};
28711       forEach(name, function(filter, key) {
28712         filters[key] = register(key, filter);
28713       });
28714       return filters;
28715     } else {
28716       return $provide.factory(name + suffix, factory);
28717     }
28718   }
28719   this.register = register;
28720
28721   this.$get = ['$injector', function($injector) {
28722     return function(name) {
28723       return $injector.get(name + suffix);
28724     };
28725   }];
28726
28727   ////////////////////////////////////////
28728
28729   /* global
28730     currencyFilter: false,
28731     dateFilter: false,
28732     filterFilter: false,
28733     jsonFilter: false,
28734     limitToFilter: false,
28735     lowercaseFilter: false,
28736     numberFilter: false,
28737     orderByFilter: false,
28738     uppercaseFilter: false,
28739   */
28740
28741   register('currency', currencyFilter);
28742   register('date', dateFilter);
28743   register('filter', filterFilter);
28744   register('json', jsonFilter);
28745   register('limitTo', limitToFilter);
28746   register('lowercase', lowercaseFilter);
28747   register('number', numberFilter);
28748   register('orderBy', orderByFilter);
28749   register('uppercase', uppercaseFilter);
28750 }
28751
28752 /**
28753  * @ngdoc filter
28754  * @name filter
28755  * @kind function
28756  *
28757  * @description
28758  * Selects a subset of items from `array` and returns it as a new array.
28759  *
28760  * @param {Array} array The source array.
28761  * @param {string|Object|function()} expression The predicate to be used for selecting items from
28762  *   `array`.
28763  *
28764  *   Can be one of:
28765  *
28766  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
28767  *     objects with string properties in `array` that match this string will be returned. This also
28768  *     applies to nested object properties.
28769  *     The predicate can be negated by prefixing the string with `!`.
28770  *
28771  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
28772  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
28773  *     which have property `name` containing "M" and property `phone` containing "1". A special
28774  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
28775  *     property of the object or its nested object properties. That's equivalent to the simple
28776  *     substring match with a `string` as described above. The predicate can be negated by prefixing
28777  *     the string with `!`.
28778  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
28779  *     not containing "M".
28780  *
28781  *     Note that a named property will match properties on the same level only, while the special
28782  *     `$` property will match properties on the same level or deeper. E.g. an array item like
28783  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
28784  *     **will** be matched by `{$: 'John'}`.
28785  *
28786  *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
28787  *     The function is called for each element of the array, with the element, its index, and
28788  *     the entire array itself as arguments.
28789  *
28790  *     The final result is an array of those elements that the predicate returned true for.
28791  *
28792  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
28793  *     determining if the expected value (from the filter expression) and actual value (from
28794  *     the object in the array) should be considered a match.
28795  *
28796  *   Can be one of:
28797  *
28798  *   - `function(actual, expected)`:
28799  *     The function will be given the object value and the predicate value to compare and
28800  *     should return true if both values should be considered equal.
28801  *
28802  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
28803  *     This is essentially strict comparison of expected and actual.
28804  *
28805  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
28806  *     insensitive way.
28807  *
28808  *     Primitive values are converted to strings. Objects are not compared against primitives,
28809  *     unless they have a custom `toString` method (e.g. `Date` objects).
28810  *
28811  * @example
28812    <example>
28813      <file name="index.html">
28814        <div ng-init="friends = [{name:'John', phone:'555-1276'},
28815                                 {name:'Mary', phone:'800-BIG-MARY'},
28816                                 {name:'Mike', phone:'555-4321'},
28817                                 {name:'Adam', phone:'555-5678'},
28818                                 {name:'Julie', phone:'555-8765'},
28819                                 {name:'Juliette', phone:'555-5678'}]"></div>
28820
28821        <label>Search: <input ng-model="searchText"></label>
28822        <table id="searchTextResults">
28823          <tr><th>Name</th><th>Phone</th></tr>
28824          <tr ng-repeat="friend in friends | filter:searchText">
28825            <td>{{friend.name}}</td>
28826            <td>{{friend.phone}}</td>
28827          </tr>
28828        </table>
28829        <hr>
28830        <label>Any: <input ng-model="search.$"></label> <br>
28831        <label>Name only <input ng-model="search.name"></label><br>
28832        <label>Phone only <input ng-model="search.phone"></label><br>
28833        <label>Equality <input type="checkbox" ng-model="strict"></label><br>
28834        <table id="searchObjResults">
28835          <tr><th>Name</th><th>Phone</th></tr>
28836          <tr ng-repeat="friendObj in friends | filter:search:strict">
28837            <td>{{friendObj.name}}</td>
28838            <td>{{friendObj.phone}}</td>
28839          </tr>
28840        </table>
28841      </file>
28842      <file name="protractor.js" type="protractor">
28843        var expectFriendNames = function(expectedNames, key) {
28844          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
28845            arr.forEach(function(wd, i) {
28846              expect(wd.getText()).toMatch(expectedNames[i]);
28847            });
28848          });
28849        };
28850
28851        it('should search across all fields when filtering with a string', function() {
28852          var searchText = element(by.model('searchText'));
28853          searchText.clear();
28854          searchText.sendKeys('m');
28855          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
28856
28857          searchText.clear();
28858          searchText.sendKeys('76');
28859          expectFriendNames(['John', 'Julie'], 'friend');
28860        });
28861
28862        it('should search in specific fields when filtering with a predicate object', function() {
28863          var searchAny = element(by.model('search.$'));
28864          searchAny.clear();
28865          searchAny.sendKeys('i');
28866          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
28867        });
28868        it('should use a equal comparison when comparator is true', function() {
28869          var searchName = element(by.model('search.name'));
28870          var strict = element(by.model('strict'));
28871          searchName.clear();
28872          searchName.sendKeys('Julie');
28873          strict.click();
28874          expectFriendNames(['Julie'], 'friendObj');
28875        });
28876      </file>
28877    </example>
28878  */
28879 function filterFilter() {
28880   return function(array, expression, comparator) {
28881     if (!isArrayLike(array)) {
28882       if (array == null) {
28883         return array;
28884       } else {
28885         throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
28886       }
28887     }
28888
28889     var expressionType = getTypeForFilter(expression);
28890     var predicateFn;
28891     var matchAgainstAnyProp;
28892
28893     switch (expressionType) {
28894       case 'function':
28895         predicateFn = expression;
28896         break;
28897       case 'boolean':
28898       case 'null':
28899       case 'number':
28900       case 'string':
28901         matchAgainstAnyProp = true;
28902         //jshint -W086
28903       case 'object':
28904         //jshint +W086
28905         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
28906         break;
28907       default:
28908         return array;
28909     }
28910
28911     return Array.prototype.filter.call(array, predicateFn);
28912   };
28913 }
28914
28915 // Helper functions for `filterFilter`
28916 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
28917   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
28918   var predicateFn;
28919
28920   if (comparator === true) {
28921     comparator = equals;
28922   } else if (!isFunction(comparator)) {
28923     comparator = function(actual, expected) {
28924       if (isUndefined(actual)) {
28925         // No substring matching against `undefined`
28926         return false;
28927       }
28928       if ((actual === null) || (expected === null)) {
28929         // No substring matching against `null`; only match against `null`
28930         return actual === expected;
28931       }
28932       if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
28933         // Should not compare primitives against objects, unless they have custom `toString` method
28934         return false;
28935       }
28936
28937       actual = lowercase('' + actual);
28938       expected = lowercase('' + expected);
28939       return actual.indexOf(expected) !== -1;
28940     };
28941   }
28942
28943   predicateFn = function(item) {
28944     if (shouldMatchPrimitives && !isObject(item)) {
28945       return deepCompare(item, expression.$, comparator, false);
28946     }
28947     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
28948   };
28949
28950   return predicateFn;
28951 }
28952
28953 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
28954   var actualType = getTypeForFilter(actual);
28955   var expectedType = getTypeForFilter(expected);
28956
28957   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
28958     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
28959   } else if (isArray(actual)) {
28960     // In case `actual` is an array, consider it a match
28961     // if ANY of it's items matches `expected`
28962     return actual.some(function(item) {
28963       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
28964     });
28965   }
28966
28967   switch (actualType) {
28968     case 'object':
28969       var key;
28970       if (matchAgainstAnyProp) {
28971         for (key in actual) {
28972           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
28973             return true;
28974           }
28975         }
28976         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
28977       } else if (expectedType === 'object') {
28978         for (key in expected) {
28979           var expectedVal = expected[key];
28980           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
28981             continue;
28982           }
28983
28984           var matchAnyProperty = key === '$';
28985           var actualVal = matchAnyProperty ? actual : actual[key];
28986           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
28987             return false;
28988           }
28989         }
28990         return true;
28991       } else {
28992         return comparator(actual, expected);
28993       }
28994       break;
28995     case 'function':
28996       return false;
28997     default:
28998       return comparator(actual, expected);
28999   }
29000 }
29001
29002 // Used for easily differentiating between `null` and actual `object`
29003 function getTypeForFilter(val) {
29004   return (val === null) ? 'null' : typeof val;
29005 }
29006
29007 var MAX_DIGITS = 22;
29008 var DECIMAL_SEP = '.';
29009 var ZERO_CHAR = '0';
29010
29011 /**
29012  * @ngdoc filter
29013  * @name currency
29014  * @kind function
29015  *
29016  * @description
29017  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
29018  * symbol for current locale is used.
29019  *
29020  * @param {number} amount Input to filter.
29021  * @param {string=} symbol Currency symbol or identifier to be displayed.
29022  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
29023  * @returns {string} Formatted number.
29024  *
29025  *
29026  * @example
29027    <example module="currencyExample">
29028      <file name="index.html">
29029        <script>
29030          angular.module('currencyExample', [])
29031            .controller('ExampleController', ['$scope', function($scope) {
29032              $scope.amount = 1234.56;
29033            }]);
29034        </script>
29035        <div ng-controller="ExampleController">
29036          <input type="number" ng-model="amount" aria-label="amount"> <br>
29037          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
29038          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
29039          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
29040        </div>
29041      </file>
29042      <file name="protractor.js" type="protractor">
29043        it('should init with 1234.56', function() {
29044          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
29045          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
29046          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
29047        });
29048        it('should update', function() {
29049          if (browser.params.browser == 'safari') {
29050            // Safari does not understand the minus key. See
29051            // https://github.com/angular/protractor/issues/481
29052            return;
29053          }
29054          element(by.model('amount')).clear();
29055          element(by.model('amount')).sendKeys('-1234');
29056          expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
29057          expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
29058          expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
29059        });
29060      </file>
29061    </example>
29062  */
29063 currencyFilter.$inject = ['$locale'];
29064 function currencyFilter($locale) {
29065   var formats = $locale.NUMBER_FORMATS;
29066   return function(amount, currencySymbol, fractionSize) {
29067     if (isUndefined(currencySymbol)) {
29068       currencySymbol = formats.CURRENCY_SYM;
29069     }
29070
29071     if (isUndefined(fractionSize)) {
29072       fractionSize = formats.PATTERNS[1].maxFrac;
29073     }
29074
29075     // if null or undefined pass it through
29076     return (amount == null)
29077         ? amount
29078         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
29079             replace(/\u00A4/g, currencySymbol);
29080   };
29081 }
29082
29083 /**
29084  * @ngdoc filter
29085  * @name number
29086  * @kind function
29087  *
29088  * @description
29089  * Formats a number as text.
29090  *
29091  * If the input is null or undefined, it will just be returned.
29092  * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
29093  * If the input is not a number an empty string is returned.
29094  *
29095  *
29096  * @param {number|string} number Number to format.
29097  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
29098  * If this is not provided then the fraction size is computed from the current locale's number
29099  * formatting pattern. In the case of the default locale, it will be 3.
29100  * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
29101  *                   locale (e.g., in the en_US locale it will have "." as the decimal separator and
29102  *                   include "," group separators after each third digit).
29103  *
29104  * @example
29105    <example module="numberFilterExample">
29106      <file name="index.html">
29107        <script>
29108          angular.module('numberFilterExample', [])
29109            .controller('ExampleController', ['$scope', function($scope) {
29110              $scope.val = 1234.56789;
29111            }]);
29112        </script>
29113        <div ng-controller="ExampleController">
29114          <label>Enter number: <input ng-model='val'></label><br>
29115          Default formatting: <span id='number-default'>{{val | number}}</span><br>
29116          No fractions: <span>{{val | number:0}}</span><br>
29117          Negative number: <span>{{-val | number:4}}</span>
29118        </div>
29119      </file>
29120      <file name="protractor.js" type="protractor">
29121        it('should format numbers', function() {
29122          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
29123          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
29124          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
29125        });
29126
29127        it('should update', function() {
29128          element(by.model('val')).clear();
29129          element(by.model('val')).sendKeys('3374.333');
29130          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
29131          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
29132          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
29133       });
29134      </file>
29135    </example>
29136  */
29137 numberFilter.$inject = ['$locale'];
29138 function numberFilter($locale) {
29139   var formats = $locale.NUMBER_FORMATS;
29140   return function(number, fractionSize) {
29141
29142     // if null or undefined pass it through
29143     return (number == null)
29144         ? number
29145         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
29146                        fractionSize);
29147   };
29148 }
29149
29150 /**
29151  * Parse a number (as a string) into three components that can be used
29152  * for formatting the number.
29153  *
29154  * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
29155  *
29156  * @param  {string} numStr The number to parse
29157  * @return {object} An object describing this number, containing the following keys:
29158  *  - d : an array of digits containing leading zeros as necessary
29159  *  - i : the number of the digits in `d` that are to the left of the decimal point
29160  *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
29161  *
29162  */
29163 function parse(numStr) {
29164   var exponent = 0, digits, numberOfIntegerDigits;
29165   var i, j, zeros;
29166
29167   // Decimal point?
29168   if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
29169     numStr = numStr.replace(DECIMAL_SEP, '');
29170   }
29171
29172   // Exponential form?
29173   if ((i = numStr.search(/e/i)) > 0) {
29174     // Work out the exponent.
29175     if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
29176     numberOfIntegerDigits += +numStr.slice(i + 1);
29177     numStr = numStr.substring(0, i);
29178   } else if (numberOfIntegerDigits < 0) {
29179     // There was no decimal point or exponent so it is an integer.
29180     numberOfIntegerDigits = numStr.length;
29181   }
29182
29183   // Count the number of leading zeros.
29184   for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++) {/* jshint noempty: false */}
29185
29186   if (i == (zeros = numStr.length)) {
29187     // The digits are all zero.
29188     digits = [0];
29189     numberOfIntegerDigits = 1;
29190   } else {
29191     // Count the number of trailing zeros
29192     zeros--;
29193     while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
29194
29195     // Trailing zeros are insignificant so ignore them
29196     numberOfIntegerDigits -= i;
29197     digits = [];
29198     // Convert string to array of digits without leading/trailing zeros.
29199     for (j = 0; i <= zeros; i++, j++) {
29200       digits[j] = +numStr.charAt(i);
29201     }
29202   }
29203
29204   // If the number overflows the maximum allowed digits then use an exponent.
29205   if (numberOfIntegerDigits > MAX_DIGITS) {
29206     digits = digits.splice(0, MAX_DIGITS - 1);
29207     exponent = numberOfIntegerDigits - 1;
29208     numberOfIntegerDigits = 1;
29209   }
29210
29211   return { d: digits, e: exponent, i: numberOfIntegerDigits };
29212 }
29213
29214 /**
29215  * Round the parsed number to the specified number of decimal places
29216  * This function changed the parsedNumber in-place
29217  */
29218 function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
29219     var digits = parsedNumber.d;
29220     var fractionLen = digits.length - parsedNumber.i;
29221
29222     // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
29223     fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
29224
29225     // The index of the digit to where rounding is to occur
29226     var roundAt = fractionSize + parsedNumber.i;
29227     var digit = digits[roundAt];
29228
29229     if (roundAt > 0) {
29230       // Drop fractional digits beyond `roundAt`
29231       digits.splice(Math.max(parsedNumber.i, roundAt));
29232
29233       // Set non-fractional digits beyond `roundAt` to 0
29234       for (var j = roundAt; j < digits.length; j++) {
29235         digits[j] = 0;
29236       }
29237     } else {
29238       // We rounded to zero so reset the parsedNumber
29239       fractionLen = Math.max(0, fractionLen);
29240       parsedNumber.i = 1;
29241       digits.length = Math.max(1, roundAt = fractionSize + 1);
29242       digits[0] = 0;
29243       for (var i = 1; i < roundAt; i++) digits[i] = 0;
29244     }
29245
29246     if (digit >= 5) {
29247       if (roundAt - 1 < 0) {
29248         for (var k = 0; k > roundAt; k--) {
29249           digits.unshift(0);
29250           parsedNumber.i++;
29251         }
29252         digits.unshift(1);
29253         parsedNumber.i++;
29254       } else {
29255         digits[roundAt - 1]++;
29256       }
29257     }
29258
29259     // Pad out with zeros to get the required fraction length
29260     for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
29261
29262
29263     // Do any carrying, e.g. a digit was rounded up to 10
29264     var carry = digits.reduceRight(function(carry, d, i, digits) {
29265       d = d + carry;
29266       digits[i] = d % 10;
29267       return Math.floor(d / 10);
29268     }, 0);
29269     if (carry) {
29270       digits.unshift(carry);
29271       parsedNumber.i++;
29272     }
29273 }
29274
29275 /**
29276  * Format a number into a string
29277  * @param  {number} number       The number to format
29278  * @param  {{
29279  *           minFrac, // the minimum number of digits required in the fraction part of the number
29280  *           maxFrac, // the maximum number of digits required in the fraction part of the number
29281  *           gSize,   // number of digits in each group of separated digits
29282  *           lgSize,  // number of digits in the last group of digits before the decimal separator
29283  *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
29284  *           posPre,  // the string to go in front of a positive number
29285  *           negSuf,  // the string to go after a negative number (e.g. `)`)
29286  *           posSuf   // the string to go after a positive number
29287  *         }} pattern
29288  * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
29289  * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
29290  * @param  {[type]} fractionSize The size of the fractional part of the number
29291  * @return {string}              The number formatted as a string
29292  */
29293 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
29294
29295   if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
29296
29297   var isInfinity = !isFinite(number);
29298   var isZero = false;
29299   var numStr = Math.abs(number) + '',
29300       formattedText = '',
29301       parsedNumber;
29302
29303   if (isInfinity) {
29304     formattedText = '\u221e';
29305   } else {
29306     parsedNumber = parse(numStr);
29307
29308     roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
29309
29310     var digits = parsedNumber.d;
29311     var integerLen = parsedNumber.i;
29312     var exponent = parsedNumber.e;
29313     var decimals = [];
29314     isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
29315
29316     // pad zeros for small numbers
29317     while (integerLen < 0) {
29318       digits.unshift(0);
29319       integerLen++;
29320     }
29321
29322     // extract decimals digits
29323     if (integerLen > 0) {
29324       decimals = digits.splice(integerLen);
29325     } else {
29326       decimals = digits;
29327       digits = [0];
29328     }
29329
29330     // format the integer digits with grouping separators
29331     var groups = [];
29332     if (digits.length >= pattern.lgSize) {
29333       groups.unshift(digits.splice(-pattern.lgSize).join(''));
29334     }
29335     while (digits.length > pattern.gSize) {
29336       groups.unshift(digits.splice(-pattern.gSize).join(''));
29337     }
29338     if (digits.length) {
29339       groups.unshift(digits.join(''));
29340     }
29341     formattedText = groups.join(groupSep);
29342
29343     // append the decimal digits
29344     if (decimals.length) {
29345       formattedText += decimalSep + decimals.join('');
29346     }
29347
29348     if (exponent) {
29349       formattedText += 'e+' + exponent;
29350     }
29351   }
29352   if (number < 0 && !isZero) {
29353     return pattern.negPre + formattedText + pattern.negSuf;
29354   } else {
29355     return pattern.posPre + formattedText + pattern.posSuf;
29356   }
29357 }
29358
29359 function padNumber(num, digits, trim, negWrap) {
29360   var neg = '';
29361   if (num < 0 || (negWrap && num <= 0)) {
29362     if (negWrap) {
29363       num = -num + 1;
29364     } else {
29365       num = -num;
29366       neg = '-';
29367     }
29368   }
29369   num = '' + num;
29370   while (num.length < digits) num = ZERO_CHAR + num;
29371   if (trim) {
29372     num = num.substr(num.length - digits);
29373   }
29374   return neg + num;
29375 }
29376
29377
29378 function dateGetter(name, size, offset, trim, negWrap) {
29379   offset = offset || 0;
29380   return function(date) {
29381     var value = date['get' + name]();
29382     if (offset > 0 || value > -offset) {
29383       value += offset;
29384     }
29385     if (value === 0 && offset == -12) value = 12;
29386     return padNumber(value, size, trim, negWrap);
29387   };
29388 }
29389
29390 function dateStrGetter(name, shortForm, standAlone) {
29391   return function(date, formats) {
29392     var value = date['get' + name]();
29393     var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
29394     var get = uppercase(propPrefix + name);
29395
29396     return formats[get][value];
29397   };
29398 }
29399
29400 function timeZoneGetter(date, formats, offset) {
29401   var zone = -1 * offset;
29402   var paddedZone = (zone >= 0) ? "+" : "";
29403
29404   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
29405                 padNumber(Math.abs(zone % 60), 2);
29406
29407   return paddedZone;
29408 }
29409
29410 function getFirstThursdayOfYear(year) {
29411     // 0 = index of January
29412     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
29413     // 4 = index of Thursday (+1 to account for 1st = 5)
29414     // 11 = index of *next* Thursday (+1 account for 1st = 12)
29415     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
29416 }
29417
29418 function getThursdayThisWeek(datetime) {
29419     return new Date(datetime.getFullYear(), datetime.getMonth(),
29420       // 4 = index of Thursday
29421       datetime.getDate() + (4 - datetime.getDay()));
29422 }
29423
29424 function weekGetter(size) {
29425    return function(date) {
29426       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
29427          thisThurs = getThursdayThisWeek(date);
29428
29429       var diff = +thisThurs - +firstThurs,
29430          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
29431
29432       return padNumber(result, size);
29433    };
29434 }
29435
29436 function ampmGetter(date, formats) {
29437   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
29438 }
29439
29440 function eraGetter(date, formats) {
29441   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
29442 }
29443
29444 function longEraGetter(date, formats) {
29445   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
29446 }
29447
29448 var DATE_FORMATS = {
29449   yyyy: dateGetter('FullYear', 4, 0, false, true),
29450     yy: dateGetter('FullYear', 2, 0, true, true),
29451      y: dateGetter('FullYear', 1, 0, false, true),
29452   MMMM: dateStrGetter('Month'),
29453    MMM: dateStrGetter('Month', true),
29454     MM: dateGetter('Month', 2, 1),
29455      M: dateGetter('Month', 1, 1),
29456   LLLL: dateStrGetter('Month', false, true),
29457     dd: dateGetter('Date', 2),
29458      d: dateGetter('Date', 1),
29459     HH: dateGetter('Hours', 2),
29460      H: dateGetter('Hours', 1),
29461     hh: dateGetter('Hours', 2, -12),
29462      h: dateGetter('Hours', 1, -12),
29463     mm: dateGetter('Minutes', 2),
29464      m: dateGetter('Minutes', 1),
29465     ss: dateGetter('Seconds', 2),
29466      s: dateGetter('Seconds', 1),
29467      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
29468      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
29469    sss: dateGetter('Milliseconds', 3),
29470   EEEE: dateStrGetter('Day'),
29471    EEE: dateStrGetter('Day', true),
29472      a: ampmGetter,
29473      Z: timeZoneGetter,
29474     ww: weekGetter(2),
29475      w: weekGetter(1),
29476      G: eraGetter,
29477      GG: eraGetter,
29478      GGG: eraGetter,
29479      GGGG: longEraGetter
29480 };
29481
29482 var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
29483     NUMBER_STRING = /^\-?\d+$/;
29484
29485 /**
29486  * @ngdoc filter
29487  * @name date
29488  * @kind function
29489  *
29490  * @description
29491  *   Formats `date` to a string based on the requested `format`.
29492  *
29493  *   `format` string can be composed of the following elements:
29494  *
29495  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
29496  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
29497  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
29498  *   * `'MMMM'`: Month in year (January-December)
29499  *   * `'MMM'`: Month in year (Jan-Dec)
29500  *   * `'MM'`: Month in year, padded (01-12)
29501  *   * `'M'`: Month in year (1-12)
29502  *   * `'LLLL'`: Stand-alone month in year (January-December)
29503  *   * `'dd'`: Day in month, padded (01-31)
29504  *   * `'d'`: Day in month (1-31)
29505  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
29506  *   * `'EEE'`: Day in Week, (Sun-Sat)
29507  *   * `'HH'`: Hour in day, padded (00-23)
29508  *   * `'H'`: Hour in day (0-23)
29509  *   * `'hh'`: Hour in AM/PM, padded (01-12)
29510  *   * `'h'`: Hour in AM/PM, (1-12)
29511  *   * `'mm'`: Minute in hour, padded (00-59)
29512  *   * `'m'`: Minute in hour (0-59)
29513  *   * `'ss'`: Second in minute, padded (00-59)
29514  *   * `'s'`: Second in minute (0-59)
29515  *   * `'sss'`: Millisecond in second, padded (000-999)
29516  *   * `'a'`: AM/PM marker
29517  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
29518  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
29519  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
29520  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
29521  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
29522  *
29523  *   `format` string can also be one of the following predefined
29524  *   {@link guide/i18n localizable formats}:
29525  *
29526  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
29527  *     (e.g. Sep 3, 2010 12:05:08 PM)
29528  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
29529  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
29530  *     (e.g. Friday, September 3, 2010)
29531  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
29532  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
29533  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
29534  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
29535  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
29536  *
29537  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
29538  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
29539  *   (e.g. `"h 'o''clock'"`).
29540  *
29541  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
29542  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
29543  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
29544  *    specified in the string input, the time is considered to be in the local timezone.
29545  * @param {string=} format Formatting rules (see Description). If not specified,
29546  *    `mediumDate` is used.
29547  * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
29548  *    continental US time zone abbreviations, but for general use, use a time zone offset, for
29549  *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
29550  *    If not specified, the timezone of the browser will be used.
29551  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
29552  *
29553  * @example
29554    <example>
29555      <file name="index.html">
29556        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
29557            <span>{{1288323623006 | date:'medium'}}</span><br>
29558        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
29559           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
29560        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
29561           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
29562        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
29563           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
29564      </file>
29565      <file name="protractor.js" type="protractor">
29566        it('should format date', function() {
29567          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
29568             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
29569          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
29570             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
29571          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
29572             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
29573          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
29574             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
29575        });
29576      </file>
29577    </example>
29578  */
29579 dateFilter.$inject = ['$locale'];
29580 function dateFilter($locale) {
29581
29582
29583   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
29584                      // 1        2       3         4          5          6          7          8  9     10      11
29585   function jsonStringToDate(string) {
29586     var match;
29587     if (match = string.match(R_ISO8601_STR)) {
29588       var date = new Date(0),
29589           tzHour = 0,
29590           tzMin  = 0,
29591           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
29592           timeSetter = match[8] ? date.setUTCHours : date.setHours;
29593
29594       if (match[9]) {
29595         tzHour = toInt(match[9] + match[10]);
29596         tzMin = toInt(match[9] + match[11]);
29597       }
29598       dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
29599       var h = toInt(match[4] || 0) - tzHour;
29600       var m = toInt(match[5] || 0) - tzMin;
29601       var s = toInt(match[6] || 0);
29602       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
29603       timeSetter.call(date, h, m, s, ms);
29604       return date;
29605     }
29606     return string;
29607   }
29608
29609
29610   return function(date, format, timezone) {
29611     var text = '',
29612         parts = [],
29613         fn, match;
29614
29615     format = format || 'mediumDate';
29616     format = $locale.DATETIME_FORMATS[format] || format;
29617     if (isString(date)) {
29618       date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
29619     }
29620
29621     if (isNumber(date)) {
29622       date = new Date(date);
29623     }
29624
29625     if (!isDate(date) || !isFinite(date.getTime())) {
29626       return date;
29627     }
29628
29629     while (format) {
29630       match = DATE_FORMATS_SPLIT.exec(format);
29631       if (match) {
29632         parts = concat(parts, match, 1);
29633         format = parts.pop();
29634       } else {
29635         parts.push(format);
29636         format = null;
29637       }
29638     }
29639
29640     var dateTimezoneOffset = date.getTimezoneOffset();
29641     if (timezone) {
29642       dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
29643       date = convertTimezoneToLocal(date, timezone, true);
29644     }
29645     forEach(parts, function(value) {
29646       fn = DATE_FORMATS[value];
29647       text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
29648                  : value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
29649     });
29650
29651     return text;
29652   };
29653 }
29654
29655
29656 /**
29657  * @ngdoc filter
29658  * @name json
29659  * @kind function
29660  *
29661  * @description
29662  *   Allows you to convert a JavaScript object into JSON string.
29663  *
29664  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
29665  *   the binding is automatically converted to JSON.
29666  *
29667  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
29668  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
29669  * @returns {string} JSON string.
29670  *
29671  *
29672  * @example
29673    <example>
29674      <file name="index.html">
29675        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
29676        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
29677      </file>
29678      <file name="protractor.js" type="protractor">
29679        it('should jsonify filtered objects', function() {
29680          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
29681          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
29682        });
29683      </file>
29684    </example>
29685  *
29686  */
29687 function jsonFilter() {
29688   return function(object, spacing) {
29689     if (isUndefined(spacing)) {
29690         spacing = 2;
29691     }
29692     return toJson(object, spacing);
29693   };
29694 }
29695
29696
29697 /**
29698  * @ngdoc filter
29699  * @name lowercase
29700  * @kind function
29701  * @description
29702  * Converts string to lowercase.
29703  * @see angular.lowercase
29704  */
29705 var lowercaseFilter = valueFn(lowercase);
29706
29707
29708 /**
29709  * @ngdoc filter
29710  * @name uppercase
29711  * @kind function
29712  * @description
29713  * Converts string to uppercase.
29714  * @see angular.uppercase
29715  */
29716 var uppercaseFilter = valueFn(uppercase);
29717
29718 /**
29719  * @ngdoc filter
29720  * @name limitTo
29721  * @kind function
29722  *
29723  * @description
29724  * Creates a new array or string containing only a specified number of elements. The elements
29725  * are taken from either the beginning or the end of the source array, string or number, as specified by
29726  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
29727  * converted to a string.
29728  *
29729  * @param {Array|string|number} input Source array, string or number to be limited.
29730  * @param {string|number} limit The length of the returned array or string. If the `limit` number
29731  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
29732  *     If the number is negative, `limit` number  of items from the end of the source array/string
29733  *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
29734  *     the input will be returned unchanged.
29735  * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
29736  *     indicates an offset from the end of `input`. Defaults to `0`.
29737  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
29738  *     had less than `limit` elements.
29739  *
29740  * @example
29741    <example module="limitToExample">
29742      <file name="index.html">
29743        <script>
29744          angular.module('limitToExample', [])
29745            .controller('ExampleController', ['$scope', function($scope) {
29746              $scope.numbers = [1,2,3,4,5,6,7,8,9];
29747              $scope.letters = "abcdefghi";
29748              $scope.longNumber = 2345432342;
29749              $scope.numLimit = 3;
29750              $scope.letterLimit = 3;
29751              $scope.longNumberLimit = 3;
29752            }]);
29753        </script>
29754        <div ng-controller="ExampleController">
29755          <label>
29756             Limit {{numbers}} to:
29757             <input type="number" step="1" ng-model="numLimit">
29758          </label>
29759          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
29760          <label>
29761             Limit {{letters}} to:
29762             <input type="number" step="1" ng-model="letterLimit">
29763          </label>
29764          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
29765          <label>
29766             Limit {{longNumber}} to:
29767             <input type="number" step="1" ng-model="longNumberLimit">
29768          </label>
29769          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
29770        </div>
29771      </file>
29772      <file name="protractor.js" type="protractor">
29773        var numLimitInput = element(by.model('numLimit'));
29774        var letterLimitInput = element(by.model('letterLimit'));
29775        var longNumberLimitInput = element(by.model('longNumberLimit'));
29776        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
29777        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
29778        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
29779
29780        it('should limit the number array to first three items', function() {
29781          expect(numLimitInput.getAttribute('value')).toBe('3');
29782          expect(letterLimitInput.getAttribute('value')).toBe('3');
29783          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
29784          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
29785          expect(limitedLetters.getText()).toEqual('Output letters: abc');
29786          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
29787        });
29788
29789        // There is a bug in safari and protractor that doesn't like the minus key
29790        // it('should update the output when -3 is entered', function() {
29791        //   numLimitInput.clear();
29792        //   numLimitInput.sendKeys('-3');
29793        //   letterLimitInput.clear();
29794        //   letterLimitInput.sendKeys('-3');
29795        //   longNumberLimitInput.clear();
29796        //   longNumberLimitInput.sendKeys('-3');
29797        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
29798        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
29799        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
29800        // });
29801
29802        it('should not exceed the maximum size of input array', function() {
29803          numLimitInput.clear();
29804          numLimitInput.sendKeys('100');
29805          letterLimitInput.clear();
29806          letterLimitInput.sendKeys('100');
29807          longNumberLimitInput.clear();
29808          longNumberLimitInput.sendKeys('100');
29809          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
29810          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
29811          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
29812        });
29813      </file>
29814    </example>
29815 */
29816 function limitToFilter() {
29817   return function(input, limit, begin) {
29818     if (Math.abs(Number(limit)) === Infinity) {
29819       limit = Number(limit);
29820     } else {
29821       limit = toInt(limit);
29822     }
29823     if (isNaN(limit)) return input;
29824
29825     if (isNumber(input)) input = input.toString();
29826     if (!isArray(input) && !isString(input)) return input;
29827
29828     begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
29829     begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
29830
29831     if (limit >= 0) {
29832       return input.slice(begin, begin + limit);
29833     } else {
29834       if (begin === 0) {
29835         return input.slice(limit, input.length);
29836       } else {
29837         return input.slice(Math.max(0, begin + limit), begin);
29838       }
29839     }
29840   };
29841 }
29842
29843 /**
29844  * @ngdoc filter
29845  * @name orderBy
29846  * @kind function
29847  *
29848  * @description
29849  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
29850  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
29851  * as expected, make sure they are actually being saved as numbers and not strings.
29852  * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
29853  *
29854  * @param {Array} array The array (or array-like object) to sort.
29855  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
29856  *    used by the comparator to determine the order of elements.
29857  *
29858  *    Can be one of:
29859  *
29860  *    - `function`: Getter function. The result of this function will be sorted using the
29861  *      `<`, `===`, `>` operator.
29862  *    - `string`: An Angular expression. The result of this expression is used to compare elements
29863  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
29864  *      3 first characters of a property called `name`). The result of a constant expression
29865  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
29866  *      to sort object by the value of their `special name` property). An expression can be
29867  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
29868  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
29869  *      element itself is used to compare where sorting.
29870  *    - `Array`: An array of function or string predicates. The first predicate in the array
29871  *      is used for sorting, but when two items are equivalent, the next predicate is used.
29872  *
29873  *    If the predicate is missing or empty then it defaults to `'+'`.
29874  *
29875  * @param {boolean=} reverse Reverse the order of the array.
29876  * @returns {Array} Sorted copy of the source array.
29877  *
29878  *
29879  * @example
29880  * The example below demonstrates a simple ngRepeat, where the data is sorted
29881  * by age in descending order (predicate is set to `'-age'`).
29882  * `reverse` is not set, which means it defaults to `false`.
29883    <example module="orderByExample">
29884      <file name="index.html">
29885        <div ng-controller="ExampleController">
29886          <table class="friend">
29887            <tr>
29888              <th>Name</th>
29889              <th>Phone Number</th>
29890              <th>Age</th>
29891            </tr>
29892            <tr ng-repeat="friend in friends | orderBy:'-age'">
29893              <td>{{friend.name}}</td>
29894              <td>{{friend.phone}}</td>
29895              <td>{{friend.age}}</td>
29896            </tr>
29897          </table>
29898        </div>
29899      </file>
29900      <file name="script.js">
29901        angular.module('orderByExample', [])
29902          .controller('ExampleController', ['$scope', function($scope) {
29903            $scope.friends =
29904                [{name:'John', phone:'555-1212', age:10},
29905                 {name:'Mary', phone:'555-9876', age:19},
29906                 {name:'Mike', phone:'555-4321', age:21},
29907                 {name:'Adam', phone:'555-5678', age:35},
29908                 {name:'Julie', phone:'555-8765', age:29}];
29909          }]);
29910      </file>
29911    </example>
29912  *
29913  * The predicate and reverse parameters can be controlled dynamically through scope properties,
29914  * as shown in the next example.
29915  * @example
29916    <example module="orderByExample">
29917      <file name="index.html">
29918        <div ng-controller="ExampleController">
29919          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
29920          <hr/>
29921          <button ng-click="predicate=''">Set to unsorted</button>
29922          <table class="friend">
29923            <tr>
29924             <th>
29925                 <button ng-click="order('name')">Name</button>
29926                 <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29927             </th>
29928             <th>
29929                 <button ng-click="order('phone')">Phone Number</button>
29930                 <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29931             </th>
29932             <th>
29933                 <button ng-click="order('age')">Age</button>
29934                 <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29935             </th>
29936            </tr>
29937            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
29938              <td>{{friend.name}}</td>
29939              <td>{{friend.phone}}</td>
29940              <td>{{friend.age}}</td>
29941            </tr>
29942          </table>
29943        </div>
29944      </file>
29945      <file name="script.js">
29946        angular.module('orderByExample', [])
29947          .controller('ExampleController', ['$scope', function($scope) {
29948            $scope.friends =
29949                [{name:'John', phone:'555-1212', age:10},
29950                 {name:'Mary', phone:'555-9876', age:19},
29951                 {name:'Mike', phone:'555-4321', age:21},
29952                 {name:'Adam', phone:'555-5678', age:35},
29953                 {name:'Julie', phone:'555-8765', age:29}];
29954            $scope.predicate = 'age';
29955            $scope.reverse = true;
29956            $scope.order = function(predicate) {
29957              $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
29958              $scope.predicate = predicate;
29959            };
29960          }]);
29961       </file>
29962      <file name="style.css">
29963        .sortorder:after {
29964          content: '\25b2';
29965        }
29966        .sortorder.reverse:after {
29967          content: '\25bc';
29968        }
29969      </file>
29970    </example>
29971  *
29972  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
29973  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
29974  * desired parameters.
29975  *
29976  * Example:
29977  *
29978  * @example
29979   <example module="orderByExample">
29980     <file name="index.html">
29981     <div ng-controller="ExampleController">
29982       <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
29983       <table class="friend">
29984         <tr>
29985           <th>
29986               <button ng-click="order('name')">Name</button>
29987               <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29988           </th>
29989           <th>
29990               <button ng-click="order('phone')">Phone Number</button>
29991               <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29992           </th>
29993           <th>
29994               <button ng-click="order('age')">Age</button>
29995               <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29996           </th>
29997         </tr>
29998         <tr ng-repeat="friend in friends">
29999           <td>{{friend.name}}</td>
30000           <td>{{friend.phone}}</td>
30001           <td>{{friend.age}}</td>
30002         </tr>
30003       </table>
30004     </div>
30005     </file>
30006
30007     <file name="script.js">
30008       angular.module('orderByExample', [])
30009         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
30010           var orderBy = $filter('orderBy');
30011           $scope.friends = [
30012             { name: 'John',    phone: '555-1212',    age: 10 },
30013             { name: 'Mary',    phone: '555-9876',    age: 19 },
30014             { name: 'Mike',    phone: '555-4321',    age: 21 },
30015             { name: 'Adam',    phone: '555-5678',    age: 35 },
30016             { name: 'Julie',   phone: '555-8765',    age: 29 }
30017           ];
30018           $scope.order = function(predicate) {
30019             $scope.predicate = predicate;
30020             $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
30021             $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
30022           };
30023           $scope.order('age', true);
30024         }]);
30025     </file>
30026
30027     <file name="style.css">
30028        .sortorder:after {
30029          content: '\25b2';
30030        }
30031        .sortorder.reverse:after {
30032          content: '\25bc';
30033        }
30034     </file>
30035 </example>
30036  */
30037 orderByFilter.$inject = ['$parse'];
30038 function orderByFilter($parse) {
30039   return function(array, sortPredicate, reverseOrder) {
30040
30041     if (array == null) return array;
30042     if (!isArrayLike(array)) {
30043       throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
30044     }
30045
30046     if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
30047     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
30048
30049     var predicates = processPredicates(sortPredicate, reverseOrder);
30050     // Add a predicate at the end that evaluates to the element index. This makes the
30051     // sort stable as it works as a tie-breaker when all the input predicates cannot
30052     // distinguish between two elements.
30053     predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
30054
30055     // The next three lines are a version of a Swartzian Transform idiom from Perl
30056     // (sometimes called the Decorate-Sort-Undecorate idiom)
30057     // See https://en.wikipedia.org/wiki/Schwartzian_transform
30058     var compareValues = Array.prototype.map.call(array, getComparisonObject);
30059     compareValues.sort(doComparison);
30060     array = compareValues.map(function(item) { return item.value; });
30061
30062     return array;
30063
30064     function getComparisonObject(value, index) {
30065       return {
30066         value: value,
30067         predicateValues: predicates.map(function(predicate) {
30068           return getPredicateValue(predicate.get(value), index);
30069         })
30070       };
30071     }
30072
30073     function doComparison(v1, v2) {
30074       var result = 0;
30075       for (var index=0, length = predicates.length; index < length; ++index) {
30076         result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
30077         if (result) break;
30078       }
30079       return result;
30080     }
30081   };
30082
30083   function processPredicates(sortPredicate, reverseOrder) {
30084     reverseOrder = reverseOrder ? -1 : 1;
30085     return sortPredicate.map(function(predicate) {
30086       var descending = 1, get = identity;
30087
30088       if (isFunction(predicate)) {
30089         get = predicate;
30090       } else if (isString(predicate)) {
30091         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
30092           descending = predicate.charAt(0) == '-' ? -1 : 1;
30093           predicate = predicate.substring(1);
30094         }
30095         if (predicate !== '') {
30096           get = $parse(predicate);
30097           if (get.constant) {
30098             var key = get();
30099             get = function(value) { return value[key]; };
30100           }
30101         }
30102       }
30103       return { get: get, descending: descending * reverseOrder };
30104     });
30105   }
30106
30107   function isPrimitive(value) {
30108     switch (typeof value) {
30109       case 'number': /* falls through */
30110       case 'boolean': /* falls through */
30111       case 'string':
30112         return true;
30113       default:
30114         return false;
30115     }
30116   }
30117
30118   function objectValue(value, index) {
30119     // If `valueOf` is a valid function use that
30120     if (typeof value.valueOf === 'function') {
30121       value = value.valueOf();
30122       if (isPrimitive(value)) return value;
30123     }
30124     // If `toString` is a valid function and not the one from `Object.prototype` use that
30125     if (hasCustomToString(value)) {
30126       value = value.toString();
30127       if (isPrimitive(value)) return value;
30128     }
30129     // We have a basic object so we use the position of the object in the collection
30130     return index;
30131   }
30132
30133   function getPredicateValue(value, index) {
30134     var type = typeof value;
30135     if (value === null) {
30136       type = 'string';
30137       value = 'null';
30138     } else if (type === 'string') {
30139       value = value.toLowerCase();
30140     } else if (type === 'object') {
30141       value = objectValue(value, index);
30142     }
30143     return { value: value, type: type };
30144   }
30145
30146   function compare(v1, v2) {
30147     var result = 0;
30148     if (v1.type === v2.type) {
30149       if (v1.value !== v2.value) {
30150         result = v1.value < v2.value ? -1 : 1;
30151       }
30152     } else {
30153       result = v1.type < v2.type ? -1 : 1;
30154     }
30155     return result;
30156   }
30157 }
30158
30159 function ngDirective(directive) {
30160   if (isFunction(directive)) {
30161     directive = {
30162       link: directive
30163     };
30164   }
30165   directive.restrict = directive.restrict || 'AC';
30166   return valueFn(directive);
30167 }
30168
30169 /**
30170  * @ngdoc directive
30171  * @name a
30172  * @restrict E
30173  *
30174  * @description
30175  * Modifies the default behavior of the html A tag so that the default action is prevented when
30176  * the href attribute is empty.
30177  *
30178  * This change permits the easy creation of action links with the `ngClick` directive
30179  * without changing the location or causing page reloads, e.g.:
30180  * `<a href="" ng-click="list.addItem()">Add Item</a>`
30181  */
30182 var htmlAnchorDirective = valueFn({
30183   restrict: 'E',
30184   compile: function(element, attr) {
30185     if (!attr.href && !attr.xlinkHref) {
30186       return function(scope, element) {
30187         // If the linked element is not an anchor tag anymore, do nothing
30188         if (element[0].nodeName.toLowerCase() !== 'a') return;
30189
30190         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
30191         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
30192                    'xlink:href' : 'href';
30193         element.on('click', function(event) {
30194           // if we have no href url, then don't navigate anywhere.
30195           if (!element.attr(href)) {
30196             event.preventDefault();
30197           }
30198         });
30199       };
30200     }
30201   }
30202 });
30203
30204 /**
30205  * @ngdoc directive
30206  * @name ngHref
30207  * @restrict A
30208  * @priority 99
30209  *
30210  * @description
30211  * Using Angular markup like `{{hash}}` in an href attribute will
30212  * make the link go to the wrong URL if the user clicks it before
30213  * Angular has a chance to replace the `{{hash}}` markup with its
30214  * value. Until Angular replaces the markup the link will be broken
30215  * and will most likely return a 404 error. The `ngHref` directive
30216  * solves this problem.
30217  *
30218  * The wrong way to write it:
30219  * ```html
30220  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
30221  * ```
30222  *
30223  * The correct way to write it:
30224  * ```html
30225  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
30226  * ```
30227  *
30228  * @element A
30229  * @param {template} ngHref any string which can contain `{{}}` markup.
30230  *
30231  * @example
30232  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
30233  * in links and their different behaviors:
30234     <example>
30235       <file name="index.html">
30236         <input ng-model="value" /><br />
30237         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
30238         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
30239         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
30240         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
30241         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
30242         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
30243       </file>
30244       <file name="protractor.js" type="protractor">
30245         it('should execute ng-click but not reload when href without value', function() {
30246           element(by.id('link-1')).click();
30247           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
30248           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
30249         });
30250
30251         it('should execute ng-click but not reload when href empty string', function() {
30252           element(by.id('link-2')).click();
30253           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
30254           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
30255         });
30256
30257         it('should execute ng-click and change url when ng-href specified', function() {
30258           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
30259
30260           element(by.id('link-3')).click();
30261
30262           // At this point, we navigate away from an Angular page, so we need
30263           // to use browser.driver to get the base webdriver.
30264
30265           browser.wait(function() {
30266             return browser.driver.getCurrentUrl().then(function(url) {
30267               return url.match(/\/123$/);
30268             });
30269           }, 5000, 'page should navigate to /123');
30270         });
30271
30272         it('should execute ng-click but not reload when href empty string and name specified', function() {
30273           element(by.id('link-4')).click();
30274           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
30275           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
30276         });
30277
30278         it('should execute ng-click but not reload when no href but name specified', function() {
30279           element(by.id('link-5')).click();
30280           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
30281           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
30282         });
30283
30284         it('should only change url when only ng-href', function() {
30285           element(by.model('value')).clear();
30286           element(by.model('value')).sendKeys('6');
30287           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
30288
30289           element(by.id('link-6')).click();
30290
30291           // At this point, we navigate away from an Angular page, so we need
30292           // to use browser.driver to get the base webdriver.
30293           browser.wait(function() {
30294             return browser.driver.getCurrentUrl().then(function(url) {
30295               return url.match(/\/6$/);
30296             });
30297           }, 5000, 'page should navigate to /6');
30298         });
30299       </file>
30300     </example>
30301  */
30302
30303 /**
30304  * @ngdoc directive
30305  * @name ngSrc
30306  * @restrict A
30307  * @priority 99
30308  *
30309  * @description
30310  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
30311  * work right: The browser will fetch from the URL with the literal
30312  * text `{{hash}}` until Angular replaces the expression inside
30313  * `{{hash}}`. The `ngSrc` directive solves this problem.
30314  *
30315  * The buggy way to write it:
30316  * ```html
30317  * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
30318  * ```
30319  *
30320  * The correct way to write it:
30321  * ```html
30322  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
30323  * ```
30324  *
30325  * @element IMG
30326  * @param {template} ngSrc any string which can contain `{{}}` markup.
30327  */
30328
30329 /**
30330  * @ngdoc directive
30331  * @name ngSrcset
30332  * @restrict A
30333  * @priority 99
30334  *
30335  * @description
30336  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
30337  * work right: The browser will fetch from the URL with the literal
30338  * text `{{hash}}` until Angular replaces the expression inside
30339  * `{{hash}}`. The `ngSrcset` directive solves this problem.
30340  *
30341  * The buggy way to write it:
30342  * ```html
30343  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
30344  * ```
30345  *
30346  * The correct way to write it:
30347  * ```html
30348  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
30349  * ```
30350  *
30351  * @element IMG
30352  * @param {template} ngSrcset any string which can contain `{{}}` markup.
30353  */
30354
30355 /**
30356  * @ngdoc directive
30357  * @name ngDisabled
30358  * @restrict A
30359  * @priority 100
30360  *
30361  * @description
30362  *
30363  * This directive sets the `disabled` attribute on the element if the
30364  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
30365  *
30366  * A special directive is necessary because we cannot use interpolation inside the `disabled`
30367  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30368  *
30369  * @example
30370     <example>
30371       <file name="index.html">
30372         <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
30373         <button ng-model="button" ng-disabled="checked">Button</button>
30374       </file>
30375       <file name="protractor.js" type="protractor">
30376         it('should toggle button', function() {
30377           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
30378           element(by.model('checked')).click();
30379           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
30380         });
30381       </file>
30382     </example>
30383  *
30384  * @element INPUT
30385  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
30386  *     then the `disabled` attribute will be set on the element
30387  */
30388
30389
30390 /**
30391  * @ngdoc directive
30392  * @name ngChecked
30393  * @restrict A
30394  * @priority 100
30395  *
30396  * @description
30397  * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
30398  *
30399  * Note that this directive should not be used together with {@link ngModel `ngModel`},
30400  * as this can lead to unexpected behavior.
30401  *
30402  * A special directive is necessary because we cannot use interpolation inside the `checked`
30403  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30404  *
30405  * @example
30406     <example>
30407       <file name="index.html">
30408         <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
30409         <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
30410       </file>
30411       <file name="protractor.js" type="protractor">
30412         it('should check both checkBoxes', function() {
30413           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
30414           element(by.model('master')).click();
30415           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
30416         });
30417       </file>
30418     </example>
30419  *
30420  * @element INPUT
30421  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
30422  *     then the `checked` attribute will be set on the element
30423  */
30424
30425
30426 /**
30427  * @ngdoc directive
30428  * @name ngReadonly
30429  * @restrict A
30430  * @priority 100
30431  *
30432  * @description
30433  *
30434  * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
30435  *
30436  * A special directive is necessary because we cannot use interpolation inside the `readOnly`
30437  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30438  *
30439  * @example
30440     <example>
30441       <file name="index.html">
30442         <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
30443         <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
30444       </file>
30445       <file name="protractor.js" type="protractor">
30446         it('should toggle readonly attr', function() {
30447           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
30448           element(by.model('checked')).click();
30449           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
30450         });
30451       </file>
30452     </example>
30453  *
30454  * @element INPUT
30455  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
30456  *     then special attribute "readonly" will be set on the element
30457  */
30458
30459
30460 /**
30461  * @ngdoc directive
30462  * @name ngSelected
30463  * @restrict A
30464  * @priority 100
30465  *
30466  * @description
30467  *
30468  * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
30469  *
30470  * A special directive is necessary because we cannot use interpolation inside the `selected`
30471  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30472  *
30473  * @example
30474     <example>
30475       <file name="index.html">
30476         <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
30477         <select aria-label="ngSelected demo">
30478           <option>Hello!</option>
30479           <option id="greet" ng-selected="selected">Greetings!</option>
30480         </select>
30481       </file>
30482       <file name="protractor.js" type="protractor">
30483         it('should select Greetings!', function() {
30484           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
30485           element(by.model('selected')).click();
30486           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
30487         });
30488       </file>
30489     </example>
30490  *
30491  * @element OPTION
30492  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
30493  *     then special attribute "selected" will be set on the element
30494  */
30495
30496 /**
30497  * @ngdoc directive
30498  * @name ngOpen
30499  * @restrict A
30500  * @priority 100
30501  *
30502  * @description
30503  *
30504  * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
30505  *
30506  * A special directive is necessary because we cannot use interpolation inside the `open`
30507  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30508  *
30509  * @example
30510      <example>
30511        <file name="index.html">
30512          <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
30513          <details id="details" ng-open="open">
30514             <summary>Show/Hide me</summary>
30515          </details>
30516        </file>
30517        <file name="protractor.js" type="protractor">
30518          it('should toggle open', function() {
30519            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
30520            element(by.model('open')).click();
30521            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
30522          });
30523        </file>
30524      </example>
30525  *
30526  * @element DETAILS
30527  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
30528  *     then special attribute "open" will be set on the element
30529  */
30530
30531 var ngAttributeAliasDirectives = {};
30532
30533 // boolean attrs are evaluated
30534 forEach(BOOLEAN_ATTR, function(propName, attrName) {
30535   // binding to multiple is not supported
30536   if (propName == "multiple") return;
30537
30538   function defaultLinkFn(scope, element, attr) {
30539     scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
30540       attr.$set(attrName, !!value);
30541     });
30542   }
30543
30544   var normalized = directiveNormalize('ng-' + attrName);
30545   var linkFn = defaultLinkFn;
30546
30547   if (propName === 'checked') {
30548     linkFn = function(scope, element, attr) {
30549       // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
30550       if (attr.ngModel !== attr[normalized]) {
30551         defaultLinkFn(scope, element, attr);
30552       }
30553     };
30554   }
30555
30556   ngAttributeAliasDirectives[normalized] = function() {
30557     return {
30558       restrict: 'A',
30559       priority: 100,
30560       link: linkFn
30561     };
30562   };
30563 });
30564
30565 // aliased input attrs are evaluated
30566 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
30567   ngAttributeAliasDirectives[ngAttr] = function() {
30568     return {
30569       priority: 100,
30570       link: function(scope, element, attr) {
30571         //special case ngPattern when a literal regular expression value
30572         //is used as the expression (this way we don't have to watch anything).
30573         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
30574           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
30575           if (match) {
30576             attr.$set("ngPattern", new RegExp(match[1], match[2]));
30577             return;
30578           }
30579         }
30580
30581         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
30582           attr.$set(ngAttr, value);
30583         });
30584       }
30585     };
30586   };
30587 });
30588
30589 // ng-src, ng-srcset, ng-href are interpolated
30590 forEach(['src', 'srcset', 'href'], function(attrName) {
30591   var normalized = directiveNormalize('ng-' + attrName);
30592   ngAttributeAliasDirectives[normalized] = function() {
30593     return {
30594       priority: 99, // it needs to run after the attributes are interpolated
30595       link: function(scope, element, attr) {
30596         var propName = attrName,
30597             name = attrName;
30598
30599         if (attrName === 'href' &&
30600             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
30601           name = 'xlinkHref';
30602           attr.$attr[name] = 'xlink:href';
30603           propName = null;
30604         }
30605
30606         attr.$observe(normalized, function(value) {
30607           if (!value) {
30608             if (attrName === 'href') {
30609               attr.$set(name, null);
30610             }
30611             return;
30612           }
30613
30614           attr.$set(name, value);
30615
30616           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
30617           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
30618           // to set the property as well to achieve the desired effect.
30619           // we use attr[attrName] value since $set can sanitize the url.
30620           if (msie && propName) element.prop(propName, attr[name]);
30621         });
30622       }
30623     };
30624   };
30625 });
30626
30627 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
30628  */
30629 var nullFormCtrl = {
30630   $addControl: noop,
30631   $$renameControl: nullFormRenameControl,
30632   $removeControl: noop,
30633   $setValidity: noop,
30634   $setDirty: noop,
30635   $setPristine: noop,
30636   $setSubmitted: noop
30637 },
30638 SUBMITTED_CLASS = 'ng-submitted';
30639
30640 function nullFormRenameControl(control, name) {
30641   control.$name = name;
30642 }
30643
30644 /**
30645  * @ngdoc type
30646  * @name form.FormController
30647  *
30648  * @property {boolean} $pristine True if user has not interacted with the form yet.
30649  * @property {boolean} $dirty True if user has already interacted with the form.
30650  * @property {boolean} $valid True if all of the containing forms and controls are valid.
30651  * @property {boolean} $invalid True if at least one containing control or form is invalid.
30652  * @property {boolean} $pending True if at least one containing control or form is pending.
30653  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
30654  *
30655  * @property {Object} $error Is an object hash, containing references to controls or
30656  *  forms with failing validators, where:
30657  *
30658  *  - keys are validation tokens (error names),
30659  *  - values are arrays of controls or forms that have a failing validator for given error name.
30660  *
30661  *  Built-in validation tokens:
30662  *
30663  *  - `email`
30664  *  - `max`
30665  *  - `maxlength`
30666  *  - `min`
30667  *  - `minlength`
30668  *  - `number`
30669  *  - `pattern`
30670  *  - `required`
30671  *  - `url`
30672  *  - `date`
30673  *  - `datetimelocal`
30674  *  - `time`
30675  *  - `week`
30676  *  - `month`
30677  *
30678  * @description
30679  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
30680  * such as being valid/invalid or dirty/pristine.
30681  *
30682  * Each {@link ng.directive:form form} directive creates an instance
30683  * of `FormController`.
30684  *
30685  */
30686 //asks for $scope to fool the BC controller module
30687 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
30688 function FormController(element, attrs, $scope, $animate, $interpolate) {
30689   var form = this,
30690       controls = [];
30691
30692   // init state
30693   form.$error = {};
30694   form.$$success = {};
30695   form.$pending = undefined;
30696   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
30697   form.$dirty = false;
30698   form.$pristine = true;
30699   form.$valid = true;
30700   form.$invalid = false;
30701   form.$submitted = false;
30702   form.$$parentForm = nullFormCtrl;
30703
30704   /**
30705    * @ngdoc method
30706    * @name form.FormController#$rollbackViewValue
30707    *
30708    * @description
30709    * Rollback all form controls pending updates to the `$modelValue`.
30710    *
30711    * Updates may be pending by a debounced event or because the input is waiting for a some future
30712    * event defined in `ng-model-options`. This method is typically needed by the reset button of
30713    * a form that uses `ng-model-options` to pend updates.
30714    */
30715   form.$rollbackViewValue = function() {
30716     forEach(controls, function(control) {
30717       control.$rollbackViewValue();
30718     });
30719   };
30720
30721   /**
30722    * @ngdoc method
30723    * @name form.FormController#$commitViewValue
30724    *
30725    * @description
30726    * Commit all form controls pending updates to the `$modelValue`.
30727    *
30728    * Updates may be pending by a debounced event or because the input is waiting for a some future
30729    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
30730    * usually handles calling this in response to input events.
30731    */
30732   form.$commitViewValue = function() {
30733     forEach(controls, function(control) {
30734       control.$commitViewValue();
30735     });
30736   };
30737
30738   /**
30739    * @ngdoc method
30740    * @name form.FormController#$addControl
30741    * @param {object} control control object, either a {@link form.FormController} or an
30742    * {@link ngModel.NgModelController}
30743    *
30744    * @description
30745    * Register a control with the form. Input elements using ngModelController do this automatically
30746    * when they are linked.
30747    *
30748    * Note that the current state of the control will not be reflected on the new parent form. This
30749    * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
30750    * state.
30751    *
30752    * However, if the method is used programmatically, for example by adding dynamically created controls,
30753    * or controls that have been previously removed without destroying their corresponding DOM element,
30754    * it's the developers responsibility to make sure the current state propagates to the parent form.
30755    *
30756    * For example, if an input control is added that is already `$dirty` and has `$error` properties,
30757    * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
30758    */
30759   form.$addControl = function(control) {
30760     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
30761     // and not added to the scope.  Now we throw an error.
30762     assertNotHasOwnProperty(control.$name, 'input');
30763     controls.push(control);
30764
30765     if (control.$name) {
30766       form[control.$name] = control;
30767     }
30768
30769     control.$$parentForm = form;
30770   };
30771
30772   // Private API: rename a form control
30773   form.$$renameControl = function(control, newName) {
30774     var oldName = control.$name;
30775
30776     if (form[oldName] === control) {
30777       delete form[oldName];
30778     }
30779     form[newName] = control;
30780     control.$name = newName;
30781   };
30782
30783   /**
30784    * @ngdoc method
30785    * @name form.FormController#$removeControl
30786    * @param {object} control control object, either a {@link form.FormController} or an
30787    * {@link ngModel.NgModelController}
30788    *
30789    * @description
30790    * Deregister a control from the form.
30791    *
30792    * Input elements using ngModelController do this automatically when they are destroyed.
30793    *
30794    * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
30795    * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
30796    * different from case to case. For example, removing the only `$dirty` control from a form may or
30797    * may not mean that the form is still `$dirty`.
30798    */
30799   form.$removeControl = function(control) {
30800     if (control.$name && form[control.$name] === control) {
30801       delete form[control.$name];
30802     }
30803     forEach(form.$pending, function(value, name) {
30804       form.$setValidity(name, null, control);
30805     });
30806     forEach(form.$error, function(value, name) {
30807       form.$setValidity(name, null, control);
30808     });
30809     forEach(form.$$success, function(value, name) {
30810       form.$setValidity(name, null, control);
30811     });
30812
30813     arrayRemove(controls, control);
30814     control.$$parentForm = nullFormCtrl;
30815   };
30816
30817
30818   /**
30819    * @ngdoc method
30820    * @name form.FormController#$setValidity
30821    *
30822    * @description
30823    * Sets the validity of a form control.
30824    *
30825    * This method will also propagate to parent forms.
30826    */
30827   addSetValidityMethod({
30828     ctrl: this,
30829     $element: element,
30830     set: function(object, property, controller) {
30831       var list = object[property];
30832       if (!list) {
30833         object[property] = [controller];
30834       } else {
30835         var index = list.indexOf(controller);
30836         if (index === -1) {
30837           list.push(controller);
30838         }
30839       }
30840     },
30841     unset: function(object, property, controller) {
30842       var list = object[property];
30843       if (!list) {
30844         return;
30845       }
30846       arrayRemove(list, controller);
30847       if (list.length === 0) {
30848         delete object[property];
30849       }
30850     },
30851     $animate: $animate
30852   });
30853
30854   /**
30855    * @ngdoc method
30856    * @name form.FormController#$setDirty
30857    *
30858    * @description
30859    * Sets the form to a dirty state.
30860    *
30861    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
30862    * state (ng-dirty class). This method will also propagate to parent forms.
30863    */
30864   form.$setDirty = function() {
30865     $animate.removeClass(element, PRISTINE_CLASS);
30866     $animate.addClass(element, DIRTY_CLASS);
30867     form.$dirty = true;
30868     form.$pristine = false;
30869     form.$$parentForm.$setDirty();
30870   };
30871
30872   /**
30873    * @ngdoc method
30874    * @name form.FormController#$setPristine
30875    *
30876    * @description
30877    * Sets the form to its pristine state.
30878    *
30879    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
30880    * state (ng-pristine class). This method will also propagate to all the controls contained
30881    * in this form.
30882    *
30883    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
30884    * saving or resetting it.
30885    */
30886   form.$setPristine = function() {
30887     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
30888     form.$dirty = false;
30889     form.$pristine = true;
30890     form.$submitted = false;
30891     forEach(controls, function(control) {
30892       control.$setPristine();
30893     });
30894   };
30895
30896   /**
30897    * @ngdoc method
30898    * @name form.FormController#$setUntouched
30899    *
30900    * @description
30901    * Sets the form to its untouched state.
30902    *
30903    * This method can be called to remove the 'ng-touched' class and set the form controls to their
30904    * untouched state (ng-untouched class).
30905    *
30906    * Setting a form controls back to their untouched state is often useful when setting the form
30907    * back to its pristine state.
30908    */
30909   form.$setUntouched = function() {
30910     forEach(controls, function(control) {
30911       control.$setUntouched();
30912     });
30913   };
30914
30915   /**
30916    * @ngdoc method
30917    * @name form.FormController#$setSubmitted
30918    *
30919    * @description
30920    * Sets the form to its submitted state.
30921    */
30922   form.$setSubmitted = function() {
30923     $animate.addClass(element, SUBMITTED_CLASS);
30924     form.$submitted = true;
30925     form.$$parentForm.$setSubmitted();
30926   };
30927 }
30928
30929 /**
30930  * @ngdoc directive
30931  * @name ngForm
30932  * @restrict EAC
30933  *
30934  * @description
30935  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
30936  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
30937  * sub-group of controls needs to be determined.
30938  *
30939  * Note: the purpose of `ngForm` is to group controls,
30940  * but not to be a replacement for the `<form>` tag with all of its capabilities
30941  * (e.g. posting to the server, ...).
30942  *
30943  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
30944  *                       related scope, under this name.
30945  *
30946  */
30947
30948  /**
30949  * @ngdoc directive
30950  * @name form
30951  * @restrict E
30952  *
30953  * @description
30954  * Directive that instantiates
30955  * {@link form.FormController FormController}.
30956  *
30957  * If the `name` attribute is specified, the form controller is published onto the current scope under
30958  * this name.
30959  *
30960  * # Alias: {@link ng.directive:ngForm `ngForm`}
30961  *
30962  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
30963  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
30964  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
30965  * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
30966  * of controls needs to be determined.
30967  *
30968  * # CSS classes
30969  *  - `ng-valid` is set if the form is valid.
30970  *  - `ng-invalid` is set if the form is invalid.
30971  *  - `ng-pending` is set if the form is pending.
30972  *  - `ng-pristine` is set if the form is pristine.
30973  *  - `ng-dirty` is set if the form is dirty.
30974  *  - `ng-submitted` is set if the form was submitted.
30975  *
30976  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
30977  *
30978  *
30979  * # Submitting a form and preventing the default action
30980  *
30981  * Since the role of forms in client-side Angular applications is different than in classical
30982  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
30983  * page reload that sends the data to the server. Instead some javascript logic should be triggered
30984  * to handle the form submission in an application-specific way.
30985  *
30986  * For this reason, Angular prevents the default action (form submission to the server) unless the
30987  * `<form>` element has an `action` attribute specified.
30988  *
30989  * You can use one of the following two ways to specify what javascript method should be called when
30990  * a form is submitted:
30991  *
30992  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
30993  * - {@link ng.directive:ngClick ngClick} directive on the first
30994   *  button or input field of type submit (input[type=submit])
30995  *
30996  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
30997  * or {@link ng.directive:ngClick ngClick} directives.
30998  * This is because of the following form submission rules in the HTML specification:
30999  *
31000  * - If a form has only one input field then hitting enter in this field triggers form submit
31001  * (`ngSubmit`)
31002  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
31003  * doesn't trigger submit
31004  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
31005  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
31006  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
31007  *
31008  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
31009  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
31010  * to have access to the updated model.
31011  *
31012  * ## Animation Hooks
31013  *
31014  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
31015  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
31016  * other validations that are performed within the form. Animations in ngForm are similar to how
31017  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
31018  * as JS animations.
31019  *
31020  * The following example shows a simple way to utilize CSS transitions to style a form element
31021  * that has been rendered as invalid after it has been validated:
31022  *
31023  * <pre>
31024  * //be sure to include ngAnimate as a module to hook into more
31025  * //advanced animations
31026  * .my-form {
31027  *   transition:0.5s linear all;
31028  *   background: white;
31029  * }
31030  * .my-form.ng-invalid {
31031  *   background: red;
31032  *   color:white;
31033  * }
31034  * </pre>
31035  *
31036  * @example
31037     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
31038       <file name="index.html">
31039        <script>
31040          angular.module('formExample', [])
31041            .controller('FormController', ['$scope', function($scope) {
31042              $scope.userType = 'guest';
31043            }]);
31044        </script>
31045        <style>
31046         .my-form {
31047           transition:all linear 0.5s;
31048           background: transparent;
31049         }
31050         .my-form.ng-invalid {
31051           background: red;
31052         }
31053        </style>
31054        <form name="myForm" ng-controller="FormController" class="my-form">
31055          userType: <input name="input" ng-model="userType" required>
31056          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
31057          <code>userType = {{userType}}</code><br>
31058          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
31059          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
31060          <code>myForm.$valid = {{myForm.$valid}}</code><br>
31061          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
31062         </form>
31063       </file>
31064       <file name="protractor.js" type="protractor">
31065         it('should initialize to model', function() {
31066           var userType = element(by.binding('userType'));
31067           var valid = element(by.binding('myForm.input.$valid'));
31068
31069           expect(userType.getText()).toContain('guest');
31070           expect(valid.getText()).toContain('true');
31071         });
31072
31073         it('should be invalid if empty', function() {
31074           var userType = element(by.binding('userType'));
31075           var valid = element(by.binding('myForm.input.$valid'));
31076           var userInput = element(by.model('userType'));
31077
31078           userInput.clear();
31079           userInput.sendKeys('');
31080
31081           expect(userType.getText()).toEqual('userType =');
31082           expect(valid.getText()).toContain('false');
31083         });
31084       </file>
31085     </example>
31086  *
31087  * @param {string=} name Name of the form. If specified, the form controller will be published into
31088  *                       related scope, under this name.
31089  */
31090 var formDirectiveFactory = function(isNgForm) {
31091   return ['$timeout', '$parse', function($timeout, $parse) {
31092     var formDirective = {
31093       name: 'form',
31094       restrict: isNgForm ? 'EAC' : 'E',
31095       require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
31096       controller: FormController,
31097       compile: function ngFormCompile(formElement, attr) {
31098         // Setup initial state of the control
31099         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
31100
31101         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
31102
31103         return {
31104           pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
31105             var controller = ctrls[0];
31106
31107             // if `action` attr is not present on the form, prevent the default action (submission)
31108             if (!('action' in attr)) {
31109               // we can't use jq events because if a form is destroyed during submission the default
31110               // action is not prevented. see #1238
31111               //
31112               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
31113               // page reload if the form was destroyed by submission of the form via a click handler
31114               // on a button in the form. Looks like an IE9 specific bug.
31115               var handleFormSubmission = function(event) {
31116                 scope.$apply(function() {
31117                   controller.$commitViewValue();
31118                   controller.$setSubmitted();
31119                 });
31120
31121                 event.preventDefault();
31122               };
31123
31124               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
31125
31126               // unregister the preventDefault listener so that we don't not leak memory but in a
31127               // way that will achieve the prevention of the default action.
31128               formElement.on('$destroy', function() {
31129                 $timeout(function() {
31130                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
31131                 }, 0, false);
31132               });
31133             }
31134
31135             var parentFormCtrl = ctrls[1] || controller.$$parentForm;
31136             parentFormCtrl.$addControl(controller);
31137
31138             var setter = nameAttr ? getSetter(controller.$name) : noop;
31139
31140             if (nameAttr) {
31141               setter(scope, controller);
31142               attr.$observe(nameAttr, function(newValue) {
31143                 if (controller.$name === newValue) return;
31144                 setter(scope, undefined);
31145                 controller.$$parentForm.$$renameControl(controller, newValue);
31146                 setter = getSetter(controller.$name);
31147                 setter(scope, controller);
31148               });
31149             }
31150             formElement.on('$destroy', function() {
31151               controller.$$parentForm.$removeControl(controller);
31152               setter(scope, undefined);
31153               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
31154             });
31155           }
31156         };
31157       }
31158     };
31159
31160     return formDirective;
31161
31162     function getSetter(expression) {
31163       if (expression === '') {
31164         //create an assignable expression, so forms with an empty name can be renamed later
31165         return $parse('this[""]').assign;
31166       }
31167       return $parse(expression).assign || noop;
31168     }
31169   }];
31170 };
31171
31172 var formDirective = formDirectiveFactory();
31173 var ngFormDirective = formDirectiveFactory(true);
31174
31175 /* global VALID_CLASS: false,
31176   INVALID_CLASS: false,
31177   PRISTINE_CLASS: false,
31178   DIRTY_CLASS: false,
31179   UNTOUCHED_CLASS: false,
31180   TOUCHED_CLASS: false,
31181   ngModelMinErr: false,
31182 */
31183
31184 // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
31185 var ISO_DATE_REGEXP = /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/;
31186 // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
31187 // Note: We are being more lenient, because browsers are too.
31188 //   1. Scheme
31189 //   2. Slashes
31190 //   3. Username
31191 //   4. Password
31192 //   5. Hostname
31193 //   6. Port
31194 //   7. Path
31195 //   8. Query
31196 //   9. Fragment
31197 //                 1111111111111111 222   333333    44444        555555555555555555555555    666     77777777     8888888     999
31198 var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
31199 var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
31200 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
31201 var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
31202 var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
31203 var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
31204 var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
31205 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
31206
31207 var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
31208 var PARTIAL_VALIDATION_TYPES = createMap();
31209 forEach('date,datetime-local,month,time,week'.split(','), function(type) {
31210   PARTIAL_VALIDATION_TYPES[type] = true;
31211 });
31212
31213 var inputType = {
31214
31215   /**
31216    * @ngdoc input
31217    * @name input[text]
31218    *
31219    * @description
31220    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
31221    *
31222    *
31223    * @param {string} ngModel Assignable angular expression to data-bind to.
31224    * @param {string=} name Property name of the form under which the control is published.
31225    * @param {string=} required Adds `required` validation error key if the value is not entered.
31226    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31227    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31228    *    `required` when you want to data-bind to the `required` attribute.
31229    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31230    *    minlength.
31231    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31232    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31233    *    any length.
31234    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31235    *    that contains the regular expression body that will be converted to a regular expression
31236    *    as in the ngPattern directive.
31237    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31238    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31239    *    If the expression evaluates to a RegExp object, then this is used directly.
31240    *    If the expression evaluates to a string, then it will be converted to a RegExp
31241    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31242    *    `new RegExp('^abc$')`.<br />
31243    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31244    *    start at the index of the last search's match, thus not taking the whole input value into
31245    *    account.
31246    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31247    *    interaction with the input element.
31248    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
31249    *    This parameter is ignored for input[type=password] controls, which will never trim the
31250    *    input.
31251    *
31252    * @example
31253       <example name="text-input-directive" module="textInputExample">
31254         <file name="index.html">
31255          <script>
31256            angular.module('textInputExample', [])
31257              .controller('ExampleController', ['$scope', function($scope) {
31258                $scope.example = {
31259                  text: 'guest',
31260                  word: /^\s*\w*\s*$/
31261                };
31262              }]);
31263          </script>
31264          <form name="myForm" ng-controller="ExampleController">
31265            <label>Single word:
31266              <input type="text" name="input" ng-model="example.text"
31267                     ng-pattern="example.word" required ng-trim="false">
31268            </label>
31269            <div role="alert">
31270              <span class="error" ng-show="myForm.input.$error.required">
31271                Required!</span>
31272              <span class="error" ng-show="myForm.input.$error.pattern">
31273                Single word only!</span>
31274            </div>
31275            <tt>text = {{example.text}}</tt><br/>
31276            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31277            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31278            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31279            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31280           </form>
31281         </file>
31282         <file name="protractor.js" type="protractor">
31283           var text = element(by.binding('example.text'));
31284           var valid = element(by.binding('myForm.input.$valid'));
31285           var input = element(by.model('example.text'));
31286
31287           it('should initialize to model', function() {
31288             expect(text.getText()).toContain('guest');
31289             expect(valid.getText()).toContain('true');
31290           });
31291
31292           it('should be invalid if empty', function() {
31293             input.clear();
31294             input.sendKeys('');
31295
31296             expect(text.getText()).toEqual('text =');
31297             expect(valid.getText()).toContain('false');
31298           });
31299
31300           it('should be invalid if multi word', function() {
31301             input.clear();
31302             input.sendKeys('hello world');
31303
31304             expect(valid.getText()).toContain('false');
31305           });
31306         </file>
31307       </example>
31308    */
31309   'text': textInputType,
31310
31311     /**
31312      * @ngdoc input
31313      * @name input[date]
31314      *
31315      * @description
31316      * Input with date validation and transformation. In browsers that do not yet support
31317      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
31318      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
31319      * modern browsers do not yet support this input type, it is important to provide cues to users on the
31320      * expected input format via a placeholder or label.
31321      *
31322      * The model must always be a Date object, otherwise Angular will throw an error.
31323      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31324      *
31325      * The timezone to be used to read/write the `Date` instance in the model can be defined using
31326      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31327      *
31328      * @param {string} ngModel Assignable angular expression to data-bind to.
31329      * @param {string=} name Property name of the form under which the control is published.
31330      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
31331      *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
31332      *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
31333      *   constraint validation.
31334      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
31335      *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
31336      *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
31337      *   constraint validation.
31338      * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
31339      *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31340      * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
31341      *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31342      * @param {string=} required Sets `required` validation error key if the value is not entered.
31343      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31344      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31345      *    `required` when you want to data-bind to the `required` attribute.
31346      * @param {string=} ngChange Angular expression to be executed when input changes due to user
31347      *    interaction with the input element.
31348      *
31349      * @example
31350      <example name="date-input-directive" module="dateInputExample">
31351      <file name="index.html">
31352        <script>
31353           angular.module('dateInputExample', [])
31354             .controller('DateController', ['$scope', function($scope) {
31355               $scope.example = {
31356                 value: new Date(2013, 9, 22)
31357               };
31358             }]);
31359        </script>
31360        <form name="myForm" ng-controller="DateController as dateCtrl">
31361           <label for="exampleInput">Pick a date in 2013:</label>
31362           <input type="date" id="exampleInput" name="input" ng-model="example.value"
31363               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
31364           <div role="alert">
31365             <span class="error" ng-show="myForm.input.$error.required">
31366                 Required!</span>
31367             <span class="error" ng-show="myForm.input.$error.date">
31368                 Not a valid date!</span>
31369            </div>
31370            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
31371            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31372            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31373            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31374            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31375        </form>
31376      </file>
31377      <file name="protractor.js" type="protractor">
31378         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
31379         var valid = element(by.binding('myForm.input.$valid'));
31380         var input = element(by.model('example.value'));
31381
31382         // currently protractor/webdriver does not support
31383         // sending keys to all known HTML5 input controls
31384         // for various browsers (see https://github.com/angular/protractor/issues/562).
31385         function setInput(val) {
31386           // set the value of the element and force validation.
31387           var scr = "var ipt = document.getElementById('exampleInput'); " +
31388           "ipt.value = '" + val + "';" +
31389           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31390           browser.executeScript(scr);
31391         }
31392
31393         it('should initialize to model', function() {
31394           expect(value.getText()).toContain('2013-10-22');
31395           expect(valid.getText()).toContain('myForm.input.$valid = true');
31396         });
31397
31398         it('should be invalid if empty', function() {
31399           setInput('');
31400           expect(value.getText()).toEqual('value =');
31401           expect(valid.getText()).toContain('myForm.input.$valid = false');
31402         });
31403
31404         it('should be invalid if over max', function() {
31405           setInput('2015-01-01');
31406           expect(value.getText()).toContain('');
31407           expect(valid.getText()).toContain('myForm.input.$valid = false');
31408         });
31409      </file>
31410      </example>
31411      */
31412   'date': createDateInputType('date', DATE_REGEXP,
31413          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
31414          'yyyy-MM-dd'),
31415
31416    /**
31417     * @ngdoc input
31418     * @name input[datetime-local]
31419     *
31420     * @description
31421     * Input with datetime validation and transformation. In browsers that do not yet support
31422     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31423     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
31424     *
31425     * The model must always be a Date object, otherwise Angular will throw an error.
31426     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31427     *
31428     * The timezone to be used to read/write the `Date` instance in the model can be defined using
31429     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31430     *
31431     * @param {string} ngModel Assignable angular expression to data-bind to.
31432     * @param {string=} name Property name of the form under which the control is published.
31433     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31434     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
31435     *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
31436     *   Note that `min` will also add native HTML5 constraint validation.
31437     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31438     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
31439     *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
31440     *   Note that `max` will also add native HTML5 constraint validation.
31441     * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
31442     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31443     * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
31444     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31445     * @param {string=} required Sets `required` validation error key if the value is not entered.
31446     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31447     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31448     *    `required` when you want to data-bind to the `required` attribute.
31449     * @param {string=} ngChange Angular expression to be executed when input changes due to user
31450     *    interaction with the input element.
31451     *
31452     * @example
31453     <example name="datetimelocal-input-directive" module="dateExample">
31454     <file name="index.html">
31455       <script>
31456         angular.module('dateExample', [])
31457           .controller('DateController', ['$scope', function($scope) {
31458             $scope.example = {
31459               value: new Date(2010, 11, 28, 14, 57)
31460             };
31461           }]);
31462       </script>
31463       <form name="myForm" ng-controller="DateController as dateCtrl">
31464         <label for="exampleInput">Pick a date between in 2013:</label>
31465         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
31466             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
31467         <div role="alert">
31468           <span class="error" ng-show="myForm.input.$error.required">
31469               Required!</span>
31470           <span class="error" ng-show="myForm.input.$error.datetimelocal">
31471               Not a valid date!</span>
31472         </div>
31473         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
31474         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31475         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31476         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31477         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31478       </form>
31479     </file>
31480     <file name="protractor.js" type="protractor">
31481       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
31482       var valid = element(by.binding('myForm.input.$valid'));
31483       var input = element(by.model('example.value'));
31484
31485       // currently protractor/webdriver does not support
31486       // sending keys to all known HTML5 input controls
31487       // for various browsers (https://github.com/angular/protractor/issues/562).
31488       function setInput(val) {
31489         // set the value of the element and force validation.
31490         var scr = "var ipt = document.getElementById('exampleInput'); " +
31491         "ipt.value = '" + val + "';" +
31492         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31493         browser.executeScript(scr);
31494       }
31495
31496       it('should initialize to model', function() {
31497         expect(value.getText()).toContain('2010-12-28T14:57:00');
31498         expect(valid.getText()).toContain('myForm.input.$valid = true');
31499       });
31500
31501       it('should be invalid if empty', function() {
31502         setInput('');
31503         expect(value.getText()).toEqual('value =');
31504         expect(valid.getText()).toContain('myForm.input.$valid = false');
31505       });
31506
31507       it('should be invalid if over max', function() {
31508         setInput('2015-01-01T23:59:00');
31509         expect(value.getText()).toContain('');
31510         expect(valid.getText()).toContain('myForm.input.$valid = false');
31511       });
31512     </file>
31513     </example>
31514     */
31515   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
31516       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
31517       'yyyy-MM-ddTHH:mm:ss.sss'),
31518
31519   /**
31520    * @ngdoc input
31521    * @name input[time]
31522    *
31523    * @description
31524    * Input with time validation and transformation. In browsers that do not yet support
31525    * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31526    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
31527    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
31528    *
31529    * The model must always be a Date object, otherwise Angular will throw an error.
31530    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31531    *
31532    * The timezone to be used to read/write the `Date` instance in the model can be defined using
31533    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31534    *
31535    * @param {string} ngModel Assignable angular expression to data-bind to.
31536    * @param {string=} name Property name of the form under which the control is published.
31537    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31538    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
31539    *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
31540    *   native HTML5 constraint validation.
31541    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31542    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
31543    *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
31544    *   native HTML5 constraint validation.
31545    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
31546    *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31547    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
31548    *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31549    * @param {string=} required Sets `required` validation error key if the value is not entered.
31550    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31551    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31552    *    `required` when you want to data-bind to the `required` attribute.
31553    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31554    *    interaction with the input element.
31555    *
31556    * @example
31557    <example name="time-input-directive" module="timeExample">
31558    <file name="index.html">
31559      <script>
31560       angular.module('timeExample', [])
31561         .controller('DateController', ['$scope', function($scope) {
31562           $scope.example = {
31563             value: new Date(1970, 0, 1, 14, 57, 0)
31564           };
31565         }]);
31566      </script>
31567      <form name="myForm" ng-controller="DateController as dateCtrl">
31568         <label for="exampleInput">Pick a time between 8am and 5pm:</label>
31569         <input type="time" id="exampleInput" name="input" ng-model="example.value"
31570             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
31571         <div role="alert">
31572           <span class="error" ng-show="myForm.input.$error.required">
31573               Required!</span>
31574           <span class="error" ng-show="myForm.input.$error.time">
31575               Not a valid date!</span>
31576         </div>
31577         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
31578         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31579         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31580         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31581         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31582      </form>
31583    </file>
31584    <file name="protractor.js" type="protractor">
31585       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
31586       var valid = element(by.binding('myForm.input.$valid'));
31587       var input = element(by.model('example.value'));
31588
31589       // currently protractor/webdriver does not support
31590       // sending keys to all known HTML5 input controls
31591       // for various browsers (https://github.com/angular/protractor/issues/562).
31592       function setInput(val) {
31593         // set the value of the element and force validation.
31594         var scr = "var ipt = document.getElementById('exampleInput'); " +
31595         "ipt.value = '" + val + "';" +
31596         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31597         browser.executeScript(scr);
31598       }
31599
31600       it('should initialize to model', function() {
31601         expect(value.getText()).toContain('14:57:00');
31602         expect(valid.getText()).toContain('myForm.input.$valid = true');
31603       });
31604
31605       it('should be invalid if empty', function() {
31606         setInput('');
31607         expect(value.getText()).toEqual('value =');
31608         expect(valid.getText()).toContain('myForm.input.$valid = false');
31609       });
31610
31611       it('should be invalid if over max', function() {
31612         setInput('23:59:00');
31613         expect(value.getText()).toContain('');
31614         expect(valid.getText()).toContain('myForm.input.$valid = false');
31615       });
31616    </file>
31617    </example>
31618    */
31619   'time': createDateInputType('time', TIME_REGEXP,
31620       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
31621      'HH:mm:ss.sss'),
31622
31623    /**
31624     * @ngdoc input
31625     * @name input[week]
31626     *
31627     * @description
31628     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
31629     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31630     * week format (yyyy-W##), for example: `2013-W02`.
31631     *
31632     * The model must always be a Date object, otherwise Angular will throw an error.
31633     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31634     *
31635     * The timezone to be used to read/write the `Date` instance in the model can be defined using
31636     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31637     *
31638     * @param {string} ngModel Assignable angular expression to data-bind to.
31639     * @param {string=} name Property name of the form under which the control is published.
31640     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31641     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
31642     *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
31643     *   native HTML5 constraint validation.
31644     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31645     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
31646     *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
31647     *   native HTML5 constraint validation.
31648     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
31649     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31650     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
31651     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31652     * @param {string=} required Sets `required` validation error key if the value is not entered.
31653     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31654     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31655     *    `required` when you want to data-bind to the `required` attribute.
31656     * @param {string=} ngChange Angular expression to be executed when input changes due to user
31657     *    interaction with the input element.
31658     *
31659     * @example
31660     <example name="week-input-directive" module="weekExample">
31661     <file name="index.html">
31662       <script>
31663       angular.module('weekExample', [])
31664         .controller('DateController', ['$scope', function($scope) {
31665           $scope.example = {
31666             value: new Date(2013, 0, 3)
31667           };
31668         }]);
31669       </script>
31670       <form name="myForm" ng-controller="DateController as dateCtrl">
31671         <label>Pick a date between in 2013:
31672           <input id="exampleInput" type="week" name="input" ng-model="example.value"
31673                  placeholder="YYYY-W##" min="2012-W32"
31674                  max="2013-W52" required />
31675         </label>
31676         <div role="alert">
31677           <span class="error" ng-show="myForm.input.$error.required">
31678               Required!</span>
31679           <span class="error" ng-show="myForm.input.$error.week">
31680               Not a valid date!</span>
31681         </div>
31682         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
31683         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31684         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31685         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31686         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31687       </form>
31688     </file>
31689     <file name="protractor.js" type="protractor">
31690       var value = element(by.binding('example.value | date: "yyyy-Www"'));
31691       var valid = element(by.binding('myForm.input.$valid'));
31692       var input = element(by.model('example.value'));
31693
31694       // currently protractor/webdriver does not support
31695       // sending keys to all known HTML5 input controls
31696       // for various browsers (https://github.com/angular/protractor/issues/562).
31697       function setInput(val) {
31698         // set the value of the element and force validation.
31699         var scr = "var ipt = document.getElementById('exampleInput'); " +
31700         "ipt.value = '" + val + "';" +
31701         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31702         browser.executeScript(scr);
31703       }
31704
31705       it('should initialize to model', function() {
31706         expect(value.getText()).toContain('2013-W01');
31707         expect(valid.getText()).toContain('myForm.input.$valid = true');
31708       });
31709
31710       it('should be invalid if empty', function() {
31711         setInput('');
31712         expect(value.getText()).toEqual('value =');
31713         expect(valid.getText()).toContain('myForm.input.$valid = false');
31714       });
31715
31716       it('should be invalid if over max', function() {
31717         setInput('2015-W01');
31718         expect(value.getText()).toContain('');
31719         expect(valid.getText()).toContain('myForm.input.$valid = false');
31720       });
31721     </file>
31722     </example>
31723     */
31724   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
31725
31726   /**
31727    * @ngdoc input
31728    * @name input[month]
31729    *
31730    * @description
31731    * Input with month validation and transformation. In browsers that do not yet support
31732    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31733    * month format (yyyy-MM), for example: `2009-01`.
31734    *
31735    * The model must always be a Date object, otherwise Angular will throw an error.
31736    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31737    * If the model is not set to the first of the month, the next view to model update will set it
31738    * to the first of the month.
31739    *
31740    * The timezone to be used to read/write the `Date` instance in the model can be defined using
31741    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31742    *
31743    * @param {string} ngModel Assignable angular expression to data-bind to.
31744    * @param {string=} name Property name of the form under which the control is published.
31745    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31746    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
31747    *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
31748    *   native HTML5 constraint validation.
31749    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31750    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
31751    *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
31752    *   native HTML5 constraint validation.
31753    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
31754    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31755    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
31756    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31757
31758    * @param {string=} required Sets `required` validation error key if the value is not entered.
31759    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31760    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31761    *    `required` when you want to data-bind to the `required` attribute.
31762    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31763    *    interaction with the input element.
31764    *
31765    * @example
31766    <example name="month-input-directive" module="monthExample">
31767    <file name="index.html">
31768      <script>
31769       angular.module('monthExample', [])
31770         .controller('DateController', ['$scope', function($scope) {
31771           $scope.example = {
31772             value: new Date(2013, 9, 1)
31773           };
31774         }]);
31775      </script>
31776      <form name="myForm" ng-controller="DateController as dateCtrl">
31777        <label for="exampleInput">Pick a month in 2013:</label>
31778        <input id="exampleInput" type="month" name="input" ng-model="example.value"
31779           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
31780        <div role="alert">
31781          <span class="error" ng-show="myForm.input.$error.required">
31782             Required!</span>
31783          <span class="error" ng-show="myForm.input.$error.month">
31784             Not a valid month!</span>
31785        </div>
31786        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
31787        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31788        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31789        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31790        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31791      </form>
31792    </file>
31793    <file name="protractor.js" type="protractor">
31794       var value = element(by.binding('example.value | date: "yyyy-MM"'));
31795       var valid = element(by.binding('myForm.input.$valid'));
31796       var input = element(by.model('example.value'));
31797
31798       // currently protractor/webdriver does not support
31799       // sending keys to all known HTML5 input controls
31800       // for various browsers (https://github.com/angular/protractor/issues/562).
31801       function setInput(val) {
31802         // set the value of the element and force validation.
31803         var scr = "var ipt = document.getElementById('exampleInput'); " +
31804         "ipt.value = '" + val + "';" +
31805         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31806         browser.executeScript(scr);
31807       }
31808
31809       it('should initialize to model', function() {
31810         expect(value.getText()).toContain('2013-10');
31811         expect(valid.getText()).toContain('myForm.input.$valid = true');
31812       });
31813
31814       it('should be invalid if empty', function() {
31815         setInput('');
31816         expect(value.getText()).toEqual('value =');
31817         expect(valid.getText()).toContain('myForm.input.$valid = false');
31818       });
31819
31820       it('should be invalid if over max', function() {
31821         setInput('2015-01');
31822         expect(value.getText()).toContain('');
31823         expect(valid.getText()).toContain('myForm.input.$valid = false');
31824       });
31825    </file>
31826    </example>
31827    */
31828   'month': createDateInputType('month', MONTH_REGEXP,
31829      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
31830      'yyyy-MM'),
31831
31832   /**
31833    * @ngdoc input
31834    * @name input[number]
31835    *
31836    * @description
31837    * Text input with number validation and transformation. Sets the `number` validation
31838    * error if not a valid number.
31839    *
31840    * <div class="alert alert-warning">
31841    * The model must always be of type `number` otherwise Angular will throw an error.
31842    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
31843    * error docs for more information and an example of how to convert your model if necessary.
31844    * </div>
31845    *
31846    * ## Issues with HTML5 constraint validation
31847    *
31848    * In browsers that follow the
31849    * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
31850    * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
31851    * If a non-number is entered in the input, the browser will report the value as an empty string,
31852    * which means the view / model values in `ngModel` and subsequently the scope value
31853    * will also be an empty string.
31854    *
31855    *
31856    * @param {string} ngModel Assignable angular expression to data-bind to.
31857    * @param {string=} name Property name of the form under which the control is published.
31858    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31859    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31860    * @param {string=} required Sets `required` validation error key if the value is not entered.
31861    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31862    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31863    *    `required` when you want to data-bind to the `required` attribute.
31864    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31865    *    minlength.
31866    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31867    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31868    *    any length.
31869    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31870    *    that contains the regular expression body that will be converted to a regular expression
31871    *    as in the ngPattern directive.
31872    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31873    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31874    *    If the expression evaluates to a RegExp object, then this is used directly.
31875    *    If the expression evaluates to a string, then it will be converted to a RegExp
31876    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31877    *    `new RegExp('^abc$')`.<br />
31878    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31879    *    start at the index of the last search's match, thus not taking the whole input value into
31880    *    account.
31881    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31882    *    interaction with the input element.
31883    *
31884    * @example
31885       <example name="number-input-directive" module="numberExample">
31886         <file name="index.html">
31887          <script>
31888            angular.module('numberExample', [])
31889              .controller('ExampleController', ['$scope', function($scope) {
31890                $scope.example = {
31891                  value: 12
31892                };
31893              }]);
31894          </script>
31895          <form name="myForm" ng-controller="ExampleController">
31896            <label>Number:
31897              <input type="number" name="input" ng-model="example.value"
31898                     min="0" max="99" required>
31899           </label>
31900            <div role="alert">
31901              <span class="error" ng-show="myForm.input.$error.required">
31902                Required!</span>
31903              <span class="error" ng-show="myForm.input.$error.number">
31904                Not valid number!</span>
31905            </div>
31906            <tt>value = {{example.value}}</tt><br/>
31907            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31908            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31909            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31910            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31911           </form>
31912         </file>
31913         <file name="protractor.js" type="protractor">
31914           var value = element(by.binding('example.value'));
31915           var valid = element(by.binding('myForm.input.$valid'));
31916           var input = element(by.model('example.value'));
31917
31918           it('should initialize to model', function() {
31919             expect(value.getText()).toContain('12');
31920             expect(valid.getText()).toContain('true');
31921           });
31922
31923           it('should be invalid if empty', function() {
31924             input.clear();
31925             input.sendKeys('');
31926             expect(value.getText()).toEqual('value =');
31927             expect(valid.getText()).toContain('false');
31928           });
31929
31930           it('should be invalid if over max', function() {
31931             input.clear();
31932             input.sendKeys('123');
31933             expect(value.getText()).toEqual('value =');
31934             expect(valid.getText()).toContain('false');
31935           });
31936         </file>
31937       </example>
31938    */
31939   'number': numberInputType,
31940
31941
31942   /**
31943    * @ngdoc input
31944    * @name input[url]
31945    *
31946    * @description
31947    * Text input with URL validation. Sets the `url` validation error key if the content is not a
31948    * valid URL.
31949    *
31950    * <div class="alert alert-warning">
31951    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
31952    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
31953    * the built-in validators (see the {@link guide/forms Forms guide})
31954    * </div>
31955    *
31956    * @param {string} ngModel Assignable angular expression to data-bind to.
31957    * @param {string=} name Property name of the form under which the control is published.
31958    * @param {string=} required Sets `required` validation error key if the value is not entered.
31959    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31960    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31961    *    `required` when you want to data-bind to the `required` attribute.
31962    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31963    *    minlength.
31964    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31965    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31966    *    any length.
31967    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31968    *    that contains the regular expression body that will be converted to a regular expression
31969    *    as in the ngPattern directive.
31970    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31971    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31972    *    If the expression evaluates to a RegExp object, then this is used directly.
31973    *    If the expression evaluates to a string, then it will be converted to a RegExp
31974    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31975    *    `new RegExp('^abc$')`.<br />
31976    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31977    *    start at the index of the last search's match, thus not taking the whole input value into
31978    *    account.
31979    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31980    *    interaction with the input element.
31981    *
31982    * @example
31983       <example name="url-input-directive" module="urlExample">
31984         <file name="index.html">
31985          <script>
31986            angular.module('urlExample', [])
31987              .controller('ExampleController', ['$scope', function($scope) {
31988                $scope.url = {
31989                  text: 'http://google.com'
31990                };
31991              }]);
31992          </script>
31993          <form name="myForm" ng-controller="ExampleController">
31994            <label>URL:
31995              <input type="url" name="input" ng-model="url.text" required>
31996            <label>
31997            <div role="alert">
31998              <span class="error" ng-show="myForm.input.$error.required">
31999                Required!</span>
32000              <span class="error" ng-show="myForm.input.$error.url">
32001                Not valid url!</span>
32002            </div>
32003            <tt>text = {{url.text}}</tt><br/>
32004            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
32005            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
32006            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
32007            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
32008            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
32009           </form>
32010         </file>
32011         <file name="protractor.js" type="protractor">
32012           var text = element(by.binding('url.text'));
32013           var valid = element(by.binding('myForm.input.$valid'));
32014           var input = element(by.model('url.text'));
32015
32016           it('should initialize to model', function() {
32017             expect(text.getText()).toContain('http://google.com');
32018             expect(valid.getText()).toContain('true');
32019           });
32020
32021           it('should be invalid if empty', function() {
32022             input.clear();
32023             input.sendKeys('');
32024
32025             expect(text.getText()).toEqual('text =');
32026             expect(valid.getText()).toContain('false');
32027           });
32028
32029           it('should be invalid if not url', function() {
32030             input.clear();
32031             input.sendKeys('box');
32032
32033             expect(valid.getText()).toContain('false');
32034           });
32035         </file>
32036       </example>
32037    */
32038   'url': urlInputType,
32039
32040
32041   /**
32042    * @ngdoc input
32043    * @name input[email]
32044    *
32045    * @description
32046    * Text input with email validation. Sets the `email` validation error key if not a valid email
32047    * address.
32048    *
32049    * <div class="alert alert-warning">
32050    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
32051    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
32052    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
32053    * </div>
32054    *
32055    * @param {string} ngModel Assignable angular expression to data-bind to.
32056    * @param {string=} name Property name of the form under which the control is published.
32057    * @param {string=} required Sets `required` validation error key if the value is not entered.
32058    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
32059    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
32060    *    `required` when you want to data-bind to the `required` attribute.
32061    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
32062    *    minlength.
32063    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
32064    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
32065    *    any length.
32066    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
32067    *    that contains the regular expression body that will be converted to a regular expression
32068    *    as in the ngPattern directive.
32069    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32070    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
32071    *    If the expression evaluates to a RegExp object, then this is used directly.
32072    *    If the expression evaluates to a string, then it will be converted to a RegExp
32073    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
32074    *    `new RegExp('^abc$')`.<br />
32075    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32076    *    start at the index of the last search's match, thus not taking the whole input value into
32077    *    account.
32078    * @param {string=} ngChange Angular expression to be executed when input changes due to user
32079    *    interaction with the input element.
32080    *
32081    * @example
32082       <example name="email-input-directive" module="emailExample">
32083         <file name="index.html">
32084          <script>
32085            angular.module('emailExample', [])
32086              .controller('ExampleController', ['$scope', function($scope) {
32087                $scope.email = {
32088                  text: 'me@example.com'
32089                };
32090              }]);
32091          </script>
32092            <form name="myForm" ng-controller="ExampleController">
32093              <label>Email:
32094                <input type="email" name="input" ng-model="email.text" required>
32095              </label>
32096              <div role="alert">
32097                <span class="error" ng-show="myForm.input.$error.required">
32098                  Required!</span>
32099                <span class="error" ng-show="myForm.input.$error.email">
32100                  Not valid email!</span>
32101              </div>
32102              <tt>text = {{email.text}}</tt><br/>
32103              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
32104              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
32105              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
32106              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
32107              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
32108            </form>
32109          </file>
32110         <file name="protractor.js" type="protractor">
32111           var text = element(by.binding('email.text'));
32112           var valid = element(by.binding('myForm.input.$valid'));
32113           var input = element(by.model('email.text'));
32114
32115           it('should initialize to model', function() {
32116             expect(text.getText()).toContain('me@example.com');
32117             expect(valid.getText()).toContain('true');
32118           });
32119
32120           it('should be invalid if empty', function() {
32121             input.clear();
32122             input.sendKeys('');
32123             expect(text.getText()).toEqual('text =');
32124             expect(valid.getText()).toContain('false');
32125           });
32126
32127           it('should be invalid if not email', function() {
32128             input.clear();
32129             input.sendKeys('xxx');
32130
32131             expect(valid.getText()).toContain('false');
32132           });
32133         </file>
32134       </example>
32135    */
32136   'email': emailInputType,
32137
32138
32139   /**
32140    * @ngdoc input
32141    * @name input[radio]
32142    *
32143    * @description
32144    * HTML radio button.
32145    *
32146    * @param {string} ngModel Assignable angular expression to data-bind to.
32147    * @param {string} value The value to which the `ngModel` expression should be set when selected.
32148    *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
32149    *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
32150    * @param {string=} name Property name of the form under which the control is published.
32151    * @param {string=} ngChange Angular expression to be executed when input changes due to user
32152    *    interaction with the input element.
32153    * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
32154    *    is selected. Should be used instead of the `value` attribute if you need
32155    *    a non-string `ngModel` (`boolean`, `array`, ...).
32156    *
32157    * @example
32158       <example name="radio-input-directive" module="radioExample">
32159         <file name="index.html">
32160          <script>
32161            angular.module('radioExample', [])
32162              .controller('ExampleController', ['$scope', function($scope) {
32163                $scope.color = {
32164                  name: 'blue'
32165                };
32166                $scope.specialValue = {
32167                  "id": "12345",
32168                  "value": "green"
32169                };
32170              }]);
32171          </script>
32172          <form name="myForm" ng-controller="ExampleController">
32173            <label>
32174              <input type="radio" ng-model="color.name" value="red">
32175              Red
32176            </label><br/>
32177            <label>
32178              <input type="radio" ng-model="color.name" ng-value="specialValue">
32179              Green
32180            </label><br/>
32181            <label>
32182              <input type="radio" ng-model="color.name" value="blue">
32183              Blue
32184            </label><br/>
32185            <tt>color = {{color.name | json}}</tt><br/>
32186           </form>
32187           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
32188         </file>
32189         <file name="protractor.js" type="protractor">
32190           it('should change state', function() {
32191             var color = element(by.binding('color.name'));
32192
32193             expect(color.getText()).toContain('blue');
32194
32195             element.all(by.model('color.name')).get(0).click();
32196
32197             expect(color.getText()).toContain('red');
32198           });
32199         </file>
32200       </example>
32201    */
32202   'radio': radioInputType,
32203
32204
32205   /**
32206    * @ngdoc input
32207    * @name input[checkbox]
32208    *
32209    * @description
32210    * HTML checkbox.
32211    *
32212    * @param {string} ngModel Assignable angular expression to data-bind to.
32213    * @param {string=} name Property name of the form under which the control is published.
32214    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
32215    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
32216    * @param {string=} ngChange Angular expression to be executed when input changes due to user
32217    *    interaction with the input element.
32218    *
32219    * @example
32220       <example name="checkbox-input-directive" module="checkboxExample">
32221         <file name="index.html">
32222          <script>
32223            angular.module('checkboxExample', [])
32224              .controller('ExampleController', ['$scope', function($scope) {
32225                $scope.checkboxModel = {
32226                 value1 : true,
32227                 value2 : 'YES'
32228               };
32229              }]);
32230          </script>
32231          <form name="myForm" ng-controller="ExampleController">
32232            <label>Value1:
32233              <input type="checkbox" ng-model="checkboxModel.value1">
32234            </label><br/>
32235            <label>Value2:
32236              <input type="checkbox" ng-model="checkboxModel.value2"
32237                     ng-true-value="'YES'" ng-false-value="'NO'">
32238             </label><br/>
32239            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
32240            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
32241           </form>
32242         </file>
32243         <file name="protractor.js" type="protractor">
32244           it('should change state', function() {
32245             var value1 = element(by.binding('checkboxModel.value1'));
32246             var value2 = element(by.binding('checkboxModel.value2'));
32247
32248             expect(value1.getText()).toContain('true');
32249             expect(value2.getText()).toContain('YES');
32250
32251             element(by.model('checkboxModel.value1')).click();
32252             element(by.model('checkboxModel.value2')).click();
32253
32254             expect(value1.getText()).toContain('false');
32255             expect(value2.getText()).toContain('NO');
32256           });
32257         </file>
32258       </example>
32259    */
32260   'checkbox': checkboxInputType,
32261
32262   'hidden': noop,
32263   'button': noop,
32264   'submit': noop,
32265   'reset': noop,
32266   'file': noop
32267 };
32268
32269 function stringBasedInputType(ctrl) {
32270   ctrl.$formatters.push(function(value) {
32271     return ctrl.$isEmpty(value) ? value : value.toString();
32272   });
32273 }
32274
32275 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32276   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32277   stringBasedInputType(ctrl);
32278 }
32279
32280 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32281   var type = lowercase(element[0].type);
32282
32283   // In composition mode, users are still inputing intermediate text buffer,
32284   // hold the listener until composition is done.
32285   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
32286   if (!$sniffer.android) {
32287     var composing = false;
32288
32289     element.on('compositionstart', function() {
32290       composing = true;
32291     });
32292
32293     element.on('compositionend', function() {
32294       composing = false;
32295       listener();
32296     });
32297   }
32298
32299   var timeout;
32300
32301   var listener = function(ev) {
32302     if (timeout) {
32303       $browser.defer.cancel(timeout);
32304       timeout = null;
32305     }
32306     if (composing) return;
32307     var value = element.val(),
32308         event = ev && ev.type;
32309
32310     // By default we will trim the value
32311     // If the attribute ng-trim exists we will avoid trimming
32312     // If input type is 'password', the value is never trimmed
32313     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
32314       value = trim(value);
32315     }
32316
32317     // If a control is suffering from bad input (due to native validators), browsers discard its
32318     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
32319     // control's value is the same empty value twice in a row.
32320     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
32321       ctrl.$setViewValue(value, event);
32322     }
32323   };
32324
32325   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
32326   // input event on backspace, delete or cut
32327   if ($sniffer.hasEvent('input')) {
32328     element.on('input', listener);
32329   } else {
32330     var deferListener = function(ev, input, origValue) {
32331       if (!timeout) {
32332         timeout = $browser.defer(function() {
32333           timeout = null;
32334           if (!input || input.value !== origValue) {
32335             listener(ev);
32336           }
32337         });
32338       }
32339     };
32340
32341     element.on('keydown', function(event) {
32342       var key = event.keyCode;
32343
32344       // ignore
32345       //    command            modifiers                   arrows
32346       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
32347
32348       deferListener(event, this, this.value);
32349     });
32350
32351     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
32352     if ($sniffer.hasEvent('paste')) {
32353       element.on('paste cut', deferListener);
32354     }
32355   }
32356
32357   // if user paste into input using mouse on older browser
32358   // or form autocomplete on newer browser, we need "change" event to catch it
32359   element.on('change', listener);
32360
32361   // Some native input types (date-family) have the ability to change validity without
32362   // firing any input/change events.
32363   // For these event types, when native validators are present and the browser supports the type,
32364   // check for validity changes on various DOM events.
32365   if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
32366     element.on(PARTIAL_VALIDATION_EVENTS, function(ev) {
32367       if (!timeout) {
32368         var validity = this[VALIDITY_STATE_PROPERTY];
32369         var origBadInput = validity.badInput;
32370         var origTypeMismatch = validity.typeMismatch;
32371         timeout = $browser.defer(function() {
32372           timeout = null;
32373           if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
32374             listener(ev);
32375           }
32376         });
32377       }
32378     });
32379   }
32380
32381   ctrl.$render = function() {
32382     // Workaround for Firefox validation #12102.
32383     var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
32384     if (element.val() !== value) {
32385       element.val(value);
32386     }
32387   };
32388 }
32389
32390 function weekParser(isoWeek, existingDate) {
32391   if (isDate(isoWeek)) {
32392     return isoWeek;
32393   }
32394
32395   if (isString(isoWeek)) {
32396     WEEK_REGEXP.lastIndex = 0;
32397     var parts = WEEK_REGEXP.exec(isoWeek);
32398     if (parts) {
32399       var year = +parts[1],
32400           week = +parts[2],
32401           hours = 0,
32402           minutes = 0,
32403           seconds = 0,
32404           milliseconds = 0,
32405           firstThurs = getFirstThursdayOfYear(year),
32406           addDays = (week - 1) * 7;
32407
32408       if (existingDate) {
32409         hours = existingDate.getHours();
32410         minutes = existingDate.getMinutes();
32411         seconds = existingDate.getSeconds();
32412         milliseconds = existingDate.getMilliseconds();
32413       }
32414
32415       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
32416     }
32417   }
32418
32419   return NaN;
32420 }
32421
32422 function createDateParser(regexp, mapping) {
32423   return function(iso, date) {
32424     var parts, map;
32425
32426     if (isDate(iso)) {
32427       return iso;
32428     }
32429
32430     if (isString(iso)) {
32431       // When a date is JSON'ified to wraps itself inside of an extra
32432       // set of double quotes. This makes the date parsing code unable
32433       // to match the date string and parse it as a date.
32434       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
32435         iso = iso.substring(1, iso.length - 1);
32436       }
32437       if (ISO_DATE_REGEXP.test(iso)) {
32438         return new Date(iso);
32439       }
32440       regexp.lastIndex = 0;
32441       parts = regexp.exec(iso);
32442
32443       if (parts) {
32444         parts.shift();
32445         if (date) {
32446           map = {
32447             yyyy: date.getFullYear(),
32448             MM: date.getMonth() + 1,
32449             dd: date.getDate(),
32450             HH: date.getHours(),
32451             mm: date.getMinutes(),
32452             ss: date.getSeconds(),
32453             sss: date.getMilliseconds() / 1000
32454           };
32455         } else {
32456           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
32457         }
32458
32459         forEach(parts, function(part, index) {
32460           if (index < mapping.length) {
32461             map[mapping[index]] = +part;
32462           }
32463         });
32464         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
32465       }
32466     }
32467
32468     return NaN;
32469   };
32470 }
32471
32472 function createDateInputType(type, regexp, parseDate, format) {
32473   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
32474     badInputChecker(scope, element, attr, ctrl);
32475     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32476     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
32477     var previousDate;
32478
32479     ctrl.$$parserName = type;
32480     ctrl.$parsers.push(function(value) {
32481       if (ctrl.$isEmpty(value)) return null;
32482       if (regexp.test(value)) {
32483         // Note: We cannot read ctrl.$modelValue, as there might be a different
32484         // parser/formatter in the processing chain so that the model
32485         // contains some different data format!
32486         var parsedDate = parseDate(value, previousDate);
32487         if (timezone) {
32488           parsedDate = convertTimezoneToLocal(parsedDate, timezone);
32489         }
32490         return parsedDate;
32491       }
32492       return undefined;
32493     });
32494
32495     ctrl.$formatters.push(function(value) {
32496       if (value && !isDate(value)) {
32497         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
32498       }
32499       if (isValidDate(value)) {
32500         previousDate = value;
32501         if (previousDate && timezone) {
32502           previousDate = convertTimezoneToLocal(previousDate, timezone, true);
32503         }
32504         return $filter('date')(value, format, timezone);
32505       } else {
32506         previousDate = null;
32507         return '';
32508       }
32509     });
32510
32511     if (isDefined(attr.min) || attr.ngMin) {
32512       var minVal;
32513       ctrl.$validators.min = function(value) {
32514         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
32515       };
32516       attr.$observe('min', function(val) {
32517         minVal = parseObservedDateValue(val);
32518         ctrl.$validate();
32519       });
32520     }
32521
32522     if (isDefined(attr.max) || attr.ngMax) {
32523       var maxVal;
32524       ctrl.$validators.max = function(value) {
32525         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
32526       };
32527       attr.$observe('max', function(val) {
32528         maxVal = parseObservedDateValue(val);
32529         ctrl.$validate();
32530       });
32531     }
32532
32533     function isValidDate(value) {
32534       // Invalid Date: getTime() returns NaN
32535       return value && !(value.getTime && value.getTime() !== value.getTime());
32536     }
32537
32538     function parseObservedDateValue(val) {
32539       return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
32540     }
32541   };
32542 }
32543
32544 function badInputChecker(scope, element, attr, ctrl) {
32545   var node = element[0];
32546   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
32547   if (nativeValidation) {
32548     ctrl.$parsers.push(function(value) {
32549       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
32550       return validity.badInput || validity.typeMismatch ? undefined : value;
32551     });
32552   }
32553 }
32554
32555 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32556   badInputChecker(scope, element, attr, ctrl);
32557   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32558
32559   ctrl.$$parserName = 'number';
32560   ctrl.$parsers.push(function(value) {
32561     if (ctrl.$isEmpty(value))      return null;
32562     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
32563     return undefined;
32564   });
32565
32566   ctrl.$formatters.push(function(value) {
32567     if (!ctrl.$isEmpty(value)) {
32568       if (!isNumber(value)) {
32569         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
32570       }
32571       value = value.toString();
32572     }
32573     return value;
32574   });
32575
32576   if (isDefined(attr.min) || attr.ngMin) {
32577     var minVal;
32578     ctrl.$validators.min = function(value) {
32579       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
32580     };
32581
32582     attr.$observe('min', function(val) {
32583       if (isDefined(val) && !isNumber(val)) {
32584         val = parseFloat(val, 10);
32585       }
32586       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
32587       // TODO(matsko): implement validateLater to reduce number of validations
32588       ctrl.$validate();
32589     });
32590   }
32591
32592   if (isDefined(attr.max) || attr.ngMax) {
32593     var maxVal;
32594     ctrl.$validators.max = function(value) {
32595       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
32596     };
32597
32598     attr.$observe('max', function(val) {
32599       if (isDefined(val) && !isNumber(val)) {
32600         val = parseFloat(val, 10);
32601       }
32602       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
32603       // TODO(matsko): implement validateLater to reduce number of validations
32604       ctrl.$validate();
32605     });
32606   }
32607 }
32608
32609 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32610   // Note: no badInputChecker here by purpose as `url` is only a validation
32611   // in browsers, i.e. we can always read out input.value even if it is not valid!
32612   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32613   stringBasedInputType(ctrl);
32614
32615   ctrl.$$parserName = 'url';
32616   ctrl.$validators.url = function(modelValue, viewValue) {
32617     var value = modelValue || viewValue;
32618     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
32619   };
32620 }
32621
32622 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32623   // Note: no badInputChecker here by purpose as `url` is only a validation
32624   // in browsers, i.e. we can always read out input.value even if it is not valid!
32625   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32626   stringBasedInputType(ctrl);
32627
32628   ctrl.$$parserName = 'email';
32629   ctrl.$validators.email = function(modelValue, viewValue) {
32630     var value = modelValue || viewValue;
32631     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
32632   };
32633 }
32634
32635 function radioInputType(scope, element, attr, ctrl) {
32636   // make the name unique, if not defined
32637   if (isUndefined(attr.name)) {
32638     element.attr('name', nextUid());
32639   }
32640
32641   var listener = function(ev) {
32642     if (element[0].checked) {
32643       ctrl.$setViewValue(attr.value, ev && ev.type);
32644     }
32645   };
32646
32647   element.on('click', listener);
32648
32649   ctrl.$render = function() {
32650     var value = attr.value;
32651     element[0].checked = (value == ctrl.$viewValue);
32652   };
32653
32654   attr.$observe('value', ctrl.$render);
32655 }
32656
32657 function parseConstantExpr($parse, context, name, expression, fallback) {
32658   var parseFn;
32659   if (isDefined(expression)) {
32660     parseFn = $parse(expression);
32661     if (!parseFn.constant) {
32662       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
32663                                    '`{1}`.', name, expression);
32664     }
32665     return parseFn(context);
32666   }
32667   return fallback;
32668 }
32669
32670 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
32671   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
32672   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
32673
32674   var listener = function(ev) {
32675     ctrl.$setViewValue(element[0].checked, ev && ev.type);
32676   };
32677
32678   element.on('click', listener);
32679
32680   ctrl.$render = function() {
32681     element[0].checked = ctrl.$viewValue;
32682   };
32683
32684   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
32685   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
32686   // it to a boolean.
32687   ctrl.$isEmpty = function(value) {
32688     return value === false;
32689   };
32690
32691   ctrl.$formatters.push(function(value) {
32692     return equals(value, trueValue);
32693   });
32694
32695   ctrl.$parsers.push(function(value) {
32696     return value ? trueValue : falseValue;
32697   });
32698 }
32699
32700
32701 /**
32702  * @ngdoc directive
32703  * @name textarea
32704  * @restrict E
32705  *
32706  * @description
32707  * HTML textarea element control with angular data-binding. The data-binding and validation
32708  * properties of this element are exactly the same as those of the
32709  * {@link ng.directive:input input element}.
32710  *
32711  * @param {string} ngModel Assignable angular expression to data-bind to.
32712  * @param {string=} name Property name of the form under which the control is published.
32713  * @param {string=} required Sets `required` validation error key if the value is not entered.
32714  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
32715  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
32716  *    `required` when you want to data-bind to the `required` attribute.
32717  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
32718  *    minlength.
32719  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
32720  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
32721  *    length.
32722  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32723  *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
32724  *    If the expression evaluates to a RegExp object, then this is used directly.
32725  *    If the expression evaluates to a string, then it will be converted to a RegExp
32726  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
32727  *    `new RegExp('^abc$')`.<br />
32728  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32729  *    start at the index of the last search's match, thus not taking the whole input value into
32730  *    account.
32731  * @param {string=} ngChange Angular expression to be executed when input changes due to user
32732  *    interaction with the input element.
32733  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
32734  */
32735
32736
32737 /**
32738  * @ngdoc directive
32739  * @name input
32740  * @restrict E
32741  *
32742  * @description
32743  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
32744  * input state control, and validation.
32745  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
32746  *
32747  * <div class="alert alert-warning">
32748  * **Note:** Not every feature offered is available for all input types.
32749  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
32750  * </div>
32751  *
32752  * @param {string} ngModel Assignable angular expression to data-bind to.
32753  * @param {string=} name Property name of the form under which the control is published.
32754  * @param {string=} required Sets `required` validation error key if the value is not entered.
32755  * @param {boolean=} ngRequired Sets `required` attribute if set to true
32756  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
32757  *    minlength.
32758  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
32759  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
32760  *    length.
32761  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32762  *    value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
32763  *    If the expression evaluates to a RegExp object, then this is used directly.
32764  *    If the expression evaluates to a string, then it will be converted to a RegExp
32765  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
32766  *    `new RegExp('^abc$')`.<br />
32767  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32768  *    start at the index of the last search's match, thus not taking the whole input value into
32769  *    account.
32770  * @param {string=} ngChange Angular expression to be executed when input changes due to user
32771  *    interaction with the input element.
32772  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
32773  *    This parameter is ignored for input[type=password] controls, which will never trim the
32774  *    input.
32775  *
32776  * @example
32777     <example name="input-directive" module="inputExample">
32778       <file name="index.html">
32779        <script>
32780           angular.module('inputExample', [])
32781             .controller('ExampleController', ['$scope', function($scope) {
32782               $scope.user = {name: 'guest', last: 'visitor'};
32783             }]);
32784        </script>
32785        <div ng-controller="ExampleController">
32786          <form name="myForm">
32787            <label>
32788               User name:
32789               <input type="text" name="userName" ng-model="user.name" required>
32790            </label>
32791            <div role="alert">
32792              <span class="error" ng-show="myForm.userName.$error.required">
32793               Required!</span>
32794            </div>
32795            <label>
32796               Last name:
32797               <input type="text" name="lastName" ng-model="user.last"
32798               ng-minlength="3" ng-maxlength="10">
32799            </label>
32800            <div role="alert">
32801              <span class="error" ng-show="myForm.lastName.$error.minlength">
32802                Too short!</span>
32803              <span class="error" ng-show="myForm.lastName.$error.maxlength">
32804                Too long!</span>
32805            </div>
32806          </form>
32807          <hr>
32808          <tt>user = {{user}}</tt><br/>
32809          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
32810          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
32811          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
32812          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
32813          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
32814          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
32815          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
32816          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
32817        </div>
32818       </file>
32819       <file name="protractor.js" type="protractor">
32820         var user = element(by.exactBinding('user'));
32821         var userNameValid = element(by.binding('myForm.userName.$valid'));
32822         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
32823         var lastNameError = element(by.binding('myForm.lastName.$error'));
32824         var formValid = element(by.binding('myForm.$valid'));
32825         var userNameInput = element(by.model('user.name'));
32826         var userLastInput = element(by.model('user.last'));
32827
32828         it('should initialize to model', function() {
32829           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
32830           expect(userNameValid.getText()).toContain('true');
32831           expect(formValid.getText()).toContain('true');
32832         });
32833
32834         it('should be invalid if empty when required', function() {
32835           userNameInput.clear();
32836           userNameInput.sendKeys('');
32837
32838           expect(user.getText()).toContain('{"last":"visitor"}');
32839           expect(userNameValid.getText()).toContain('false');
32840           expect(formValid.getText()).toContain('false');
32841         });
32842
32843         it('should be valid if empty when min length is set', function() {
32844           userLastInput.clear();
32845           userLastInput.sendKeys('');
32846
32847           expect(user.getText()).toContain('{"name":"guest","last":""}');
32848           expect(lastNameValid.getText()).toContain('true');
32849           expect(formValid.getText()).toContain('true');
32850         });
32851
32852         it('should be invalid if less than required min length', function() {
32853           userLastInput.clear();
32854           userLastInput.sendKeys('xx');
32855
32856           expect(user.getText()).toContain('{"name":"guest"}');
32857           expect(lastNameValid.getText()).toContain('false');
32858           expect(lastNameError.getText()).toContain('minlength');
32859           expect(formValid.getText()).toContain('false');
32860         });
32861
32862         it('should be invalid if longer than max length', function() {
32863           userLastInput.clear();
32864           userLastInput.sendKeys('some ridiculously long name');
32865
32866           expect(user.getText()).toContain('{"name":"guest"}');
32867           expect(lastNameValid.getText()).toContain('false');
32868           expect(lastNameError.getText()).toContain('maxlength');
32869           expect(formValid.getText()).toContain('false');
32870         });
32871       </file>
32872     </example>
32873  */
32874 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
32875     function($browser, $sniffer, $filter, $parse) {
32876   return {
32877     restrict: 'E',
32878     require: ['?ngModel'],
32879     link: {
32880       pre: function(scope, element, attr, ctrls) {
32881         if (ctrls[0]) {
32882           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
32883                                                               $browser, $filter, $parse);
32884         }
32885       }
32886     }
32887   };
32888 }];
32889
32890
32891
32892 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
32893 /**
32894  * @ngdoc directive
32895  * @name ngValue
32896  *
32897  * @description
32898  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
32899  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
32900  * the bound value.
32901  *
32902  * `ngValue` is useful when dynamically generating lists of radio buttons using
32903  * {@link ngRepeat `ngRepeat`}, as shown below.
32904  *
32905  * Likewise, `ngValue` can be used to generate `<option>` elements for
32906  * the {@link select `select`} element. In that case however, only strings are supported
32907  * for the `value `attribute, so the resulting `ngModel` will always be a string.
32908  * Support for `select` models with non-string values is available via `ngOptions`.
32909  *
32910  * @element input
32911  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
32912  *   of the `input` element
32913  *
32914  * @example
32915     <example name="ngValue-directive" module="valueExample">
32916       <file name="index.html">
32917        <script>
32918           angular.module('valueExample', [])
32919             .controller('ExampleController', ['$scope', function($scope) {
32920               $scope.names = ['pizza', 'unicorns', 'robots'];
32921               $scope.my = { favorite: 'unicorns' };
32922             }]);
32923        </script>
32924         <form ng-controller="ExampleController">
32925           <h2>Which is your favorite?</h2>
32926             <label ng-repeat="name in names" for="{{name}}">
32927               {{name}}
32928               <input type="radio"
32929                      ng-model="my.favorite"
32930                      ng-value="name"
32931                      id="{{name}}"
32932                      name="favorite">
32933             </label>
32934           <div>You chose {{my.favorite}}</div>
32935         </form>
32936       </file>
32937       <file name="protractor.js" type="protractor">
32938         var favorite = element(by.binding('my.favorite'));
32939
32940         it('should initialize to model', function() {
32941           expect(favorite.getText()).toContain('unicorns');
32942         });
32943         it('should bind the values to the inputs', function() {
32944           element.all(by.model('my.favorite')).get(0).click();
32945           expect(favorite.getText()).toContain('pizza');
32946         });
32947       </file>
32948     </example>
32949  */
32950 var ngValueDirective = function() {
32951   return {
32952     restrict: 'A',
32953     priority: 100,
32954     compile: function(tpl, tplAttr) {
32955       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
32956         return function ngValueConstantLink(scope, elm, attr) {
32957           attr.$set('value', scope.$eval(attr.ngValue));
32958         };
32959       } else {
32960         return function ngValueLink(scope, elm, attr) {
32961           scope.$watch(attr.ngValue, function valueWatchAction(value) {
32962             attr.$set('value', value);
32963           });
32964         };
32965       }
32966     }
32967   };
32968 };
32969
32970 /**
32971  * @ngdoc directive
32972  * @name ngBind
32973  * @restrict AC
32974  *
32975  * @description
32976  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
32977  * with the value of a given expression, and to update the text content when the value of that
32978  * expression changes.
32979  *
32980  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
32981  * `{{ expression }}` which is similar but less verbose.
32982  *
32983  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
32984  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
32985  * element attribute, it makes the bindings invisible to the user while the page is loading.
32986  *
32987  * An alternative solution to this problem would be using the
32988  * {@link ng.directive:ngCloak ngCloak} directive.
32989  *
32990  *
32991  * @element ANY
32992  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
32993  *
32994  * @example
32995  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
32996    <example module="bindExample">
32997      <file name="index.html">
32998        <script>
32999          angular.module('bindExample', [])
33000            .controller('ExampleController', ['$scope', function($scope) {
33001              $scope.name = 'Whirled';
33002            }]);
33003        </script>
33004        <div ng-controller="ExampleController">
33005          <label>Enter name: <input type="text" ng-model="name"></label><br>
33006          Hello <span ng-bind="name"></span>!
33007        </div>
33008      </file>
33009      <file name="protractor.js" type="protractor">
33010        it('should check ng-bind', function() {
33011          var nameInput = element(by.model('name'));
33012
33013          expect(element(by.binding('name')).getText()).toBe('Whirled');
33014          nameInput.clear();
33015          nameInput.sendKeys('world');
33016          expect(element(by.binding('name')).getText()).toBe('world');
33017        });
33018      </file>
33019    </example>
33020  */
33021 var ngBindDirective = ['$compile', function($compile) {
33022   return {
33023     restrict: 'AC',
33024     compile: function ngBindCompile(templateElement) {
33025       $compile.$$addBindingClass(templateElement);
33026       return function ngBindLink(scope, element, attr) {
33027         $compile.$$addBindingInfo(element, attr.ngBind);
33028         element = element[0];
33029         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
33030           element.textContent = isUndefined(value) ? '' : value;
33031         });
33032       };
33033     }
33034   };
33035 }];
33036
33037
33038 /**
33039  * @ngdoc directive
33040  * @name ngBindTemplate
33041  *
33042  * @description
33043  * The `ngBindTemplate` directive specifies that the element
33044  * text content should be replaced with the interpolation of the template
33045  * in the `ngBindTemplate` attribute.
33046  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
33047  * expressions. This directive is needed since some HTML elements
33048  * (such as TITLE and OPTION) cannot contain SPAN elements.
33049  *
33050  * @element ANY
33051  * @param {string} ngBindTemplate template of form
33052  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
33053  *
33054  * @example
33055  * Try it here: enter text in text box and watch the greeting change.
33056    <example module="bindExample">
33057      <file name="index.html">
33058        <script>
33059          angular.module('bindExample', [])
33060            .controller('ExampleController', ['$scope', function($scope) {
33061              $scope.salutation = 'Hello';
33062              $scope.name = 'World';
33063            }]);
33064        </script>
33065        <div ng-controller="ExampleController">
33066         <label>Salutation: <input type="text" ng-model="salutation"></label><br>
33067         <label>Name: <input type="text" ng-model="name"></label><br>
33068         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
33069        </div>
33070      </file>
33071      <file name="protractor.js" type="protractor">
33072        it('should check ng-bind', function() {
33073          var salutationElem = element(by.binding('salutation'));
33074          var salutationInput = element(by.model('salutation'));
33075          var nameInput = element(by.model('name'));
33076
33077          expect(salutationElem.getText()).toBe('Hello World!');
33078
33079          salutationInput.clear();
33080          salutationInput.sendKeys('Greetings');
33081          nameInput.clear();
33082          nameInput.sendKeys('user');
33083
33084          expect(salutationElem.getText()).toBe('Greetings user!');
33085        });
33086      </file>
33087    </example>
33088  */
33089 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
33090   return {
33091     compile: function ngBindTemplateCompile(templateElement) {
33092       $compile.$$addBindingClass(templateElement);
33093       return function ngBindTemplateLink(scope, element, attr) {
33094         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
33095         $compile.$$addBindingInfo(element, interpolateFn.expressions);
33096         element = element[0];
33097         attr.$observe('ngBindTemplate', function(value) {
33098           element.textContent = isUndefined(value) ? '' : value;
33099         });
33100       };
33101     }
33102   };
33103 }];
33104
33105
33106 /**
33107  * @ngdoc directive
33108  * @name ngBindHtml
33109  *
33110  * @description
33111  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
33112  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
33113  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
33114  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
33115  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
33116  *
33117  * You may also bypass sanitization for values you know are safe. To do so, bind to
33118  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
33119  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
33120  *
33121  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
33122  * will have an exception (instead of an exploit.)
33123  *
33124  * @element ANY
33125  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
33126  *
33127  * @example
33128
33129    <example module="bindHtmlExample" deps="angular-sanitize.js">
33130      <file name="index.html">
33131        <div ng-controller="ExampleController">
33132         <p ng-bind-html="myHTML"></p>
33133        </div>
33134      </file>
33135
33136      <file name="script.js">
33137        angular.module('bindHtmlExample', ['ngSanitize'])
33138          .controller('ExampleController', ['$scope', function($scope) {
33139            $scope.myHTML =
33140               'I am an <code>HTML</code>string with ' +
33141               '<a href="#">links!</a> and other <em>stuff</em>';
33142          }]);
33143      </file>
33144
33145      <file name="protractor.js" type="protractor">
33146        it('should check ng-bind-html', function() {
33147          expect(element(by.binding('myHTML')).getText()).toBe(
33148              'I am an HTMLstring with links! and other stuff');
33149        });
33150      </file>
33151    </example>
33152  */
33153 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
33154   return {
33155     restrict: 'A',
33156     compile: function ngBindHtmlCompile(tElement, tAttrs) {
33157       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
33158       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
33159         return (value || '').toString();
33160       });
33161       $compile.$$addBindingClass(tElement);
33162
33163       return function ngBindHtmlLink(scope, element, attr) {
33164         $compile.$$addBindingInfo(element, attr.ngBindHtml);
33165
33166         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
33167           // we re-evaluate the expr because we want a TrustedValueHolderType
33168           // for $sce, not a string
33169           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
33170         });
33171       };
33172     }
33173   };
33174 }];
33175
33176 /**
33177  * @ngdoc directive
33178  * @name ngChange
33179  *
33180  * @description
33181  * Evaluate the given expression when the user changes the input.
33182  * The expression is evaluated immediately, unlike the JavaScript onchange event
33183  * which only triggers at the end of a change (usually, when the user leaves the
33184  * form element or presses the return key).
33185  *
33186  * The `ngChange` expression is only evaluated when a change in the input value causes
33187  * a new value to be committed to the model.
33188  *
33189  * It will not be evaluated:
33190  * * if the value returned from the `$parsers` transformation pipeline has not changed
33191  * * if the input has continued to be invalid since the model will stay `null`
33192  * * if the model is changed programmatically and not by a change to the input value
33193  *
33194  *
33195  * Note, this directive requires `ngModel` to be present.
33196  *
33197  * @element input
33198  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
33199  * in input value.
33200  *
33201  * @example
33202  * <example name="ngChange-directive" module="changeExample">
33203  *   <file name="index.html">
33204  *     <script>
33205  *       angular.module('changeExample', [])
33206  *         .controller('ExampleController', ['$scope', function($scope) {
33207  *           $scope.counter = 0;
33208  *           $scope.change = function() {
33209  *             $scope.counter++;
33210  *           };
33211  *         }]);
33212  *     </script>
33213  *     <div ng-controller="ExampleController">
33214  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
33215  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
33216  *       <label for="ng-change-example2">Confirmed</label><br />
33217  *       <tt>debug = {{confirmed}}</tt><br/>
33218  *       <tt>counter = {{counter}}</tt><br/>
33219  *     </div>
33220  *   </file>
33221  *   <file name="protractor.js" type="protractor">
33222  *     var counter = element(by.binding('counter'));
33223  *     var debug = element(by.binding('confirmed'));
33224  *
33225  *     it('should evaluate the expression if changing from view', function() {
33226  *       expect(counter.getText()).toContain('0');
33227  *
33228  *       element(by.id('ng-change-example1')).click();
33229  *
33230  *       expect(counter.getText()).toContain('1');
33231  *       expect(debug.getText()).toContain('true');
33232  *     });
33233  *
33234  *     it('should not evaluate the expression if changing from model', function() {
33235  *       element(by.id('ng-change-example2')).click();
33236
33237  *       expect(counter.getText()).toContain('0');
33238  *       expect(debug.getText()).toContain('true');
33239  *     });
33240  *   </file>
33241  * </example>
33242  */
33243 var ngChangeDirective = valueFn({
33244   restrict: 'A',
33245   require: 'ngModel',
33246   link: function(scope, element, attr, ctrl) {
33247     ctrl.$viewChangeListeners.push(function() {
33248       scope.$eval(attr.ngChange);
33249     });
33250   }
33251 });
33252
33253 function classDirective(name, selector) {
33254   name = 'ngClass' + name;
33255   return ['$animate', function($animate) {
33256     return {
33257       restrict: 'AC',
33258       link: function(scope, element, attr) {
33259         var oldVal;
33260
33261         scope.$watch(attr[name], ngClassWatchAction, true);
33262
33263         attr.$observe('class', function(value) {
33264           ngClassWatchAction(scope.$eval(attr[name]));
33265         });
33266
33267
33268         if (name !== 'ngClass') {
33269           scope.$watch('$index', function($index, old$index) {
33270             // jshint bitwise: false
33271             var mod = $index & 1;
33272             if (mod !== (old$index & 1)) {
33273               var classes = arrayClasses(scope.$eval(attr[name]));
33274               mod === selector ?
33275                 addClasses(classes) :
33276                 removeClasses(classes);
33277             }
33278           });
33279         }
33280
33281         function addClasses(classes) {
33282           var newClasses = digestClassCounts(classes, 1);
33283           attr.$addClass(newClasses);
33284         }
33285
33286         function removeClasses(classes) {
33287           var newClasses = digestClassCounts(classes, -1);
33288           attr.$removeClass(newClasses);
33289         }
33290
33291         function digestClassCounts(classes, count) {
33292           // Use createMap() to prevent class assumptions involving property
33293           // names in Object.prototype
33294           var classCounts = element.data('$classCounts') || createMap();
33295           var classesToUpdate = [];
33296           forEach(classes, function(className) {
33297             if (count > 0 || classCounts[className]) {
33298               classCounts[className] = (classCounts[className] || 0) + count;
33299               if (classCounts[className] === +(count > 0)) {
33300                 classesToUpdate.push(className);
33301               }
33302             }
33303           });
33304           element.data('$classCounts', classCounts);
33305           return classesToUpdate.join(' ');
33306         }
33307
33308         function updateClasses(oldClasses, newClasses) {
33309           var toAdd = arrayDifference(newClasses, oldClasses);
33310           var toRemove = arrayDifference(oldClasses, newClasses);
33311           toAdd = digestClassCounts(toAdd, 1);
33312           toRemove = digestClassCounts(toRemove, -1);
33313           if (toAdd && toAdd.length) {
33314             $animate.addClass(element, toAdd);
33315           }
33316           if (toRemove && toRemove.length) {
33317             $animate.removeClass(element, toRemove);
33318           }
33319         }
33320
33321         function ngClassWatchAction(newVal) {
33322           if (selector === true || scope.$index % 2 === selector) {
33323             var newClasses = arrayClasses(newVal || []);
33324             if (!oldVal) {
33325               addClasses(newClasses);
33326             } else if (!equals(newVal,oldVal)) {
33327               var oldClasses = arrayClasses(oldVal);
33328               updateClasses(oldClasses, newClasses);
33329             }
33330           }
33331           if (isArray(newVal)) {
33332             oldVal = newVal.map(function(v) { return shallowCopy(v); });
33333           } else {
33334             oldVal = shallowCopy(newVal);
33335           }
33336         }
33337       }
33338     };
33339
33340     function arrayDifference(tokens1, tokens2) {
33341       var values = [];
33342
33343       outer:
33344       for (var i = 0; i < tokens1.length; i++) {
33345         var token = tokens1[i];
33346         for (var j = 0; j < tokens2.length; j++) {
33347           if (token == tokens2[j]) continue outer;
33348         }
33349         values.push(token);
33350       }
33351       return values;
33352     }
33353
33354     function arrayClasses(classVal) {
33355       var classes = [];
33356       if (isArray(classVal)) {
33357         forEach(classVal, function(v) {
33358           classes = classes.concat(arrayClasses(v));
33359         });
33360         return classes;
33361       } else if (isString(classVal)) {
33362         return classVal.split(' ');
33363       } else if (isObject(classVal)) {
33364         forEach(classVal, function(v, k) {
33365           if (v) {
33366             classes = classes.concat(k.split(' '));
33367           }
33368         });
33369         return classes;
33370       }
33371       return classVal;
33372     }
33373   }];
33374 }
33375
33376 /**
33377  * @ngdoc directive
33378  * @name ngClass
33379  * @restrict AC
33380  *
33381  * @description
33382  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
33383  * an expression that represents all classes to be added.
33384  *
33385  * The directive operates in three different ways, depending on which of three types the expression
33386  * evaluates to:
33387  *
33388  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
33389  * names.
33390  *
33391  * 2. If the expression evaluates to an object, then for each key-value pair of the
33392  * object with a truthy value the corresponding key is used as a class name.
33393  *
33394  * 3. If the expression evaluates to an array, each element of the array should either be a string as in
33395  * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
33396  * to give you more control over what CSS classes appear. See the code below for an example of this.
33397  *
33398  *
33399  * The directive won't add duplicate classes if a particular class was already set.
33400  *
33401  * When the expression changes, the previously added classes are removed and only then are the
33402  * new classes added.
33403  *
33404  * @animations
33405  * | Animation                        | Occurs                              |
33406  * |----------------------------------|-------------------------------------|
33407  * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
33408  * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
33409  *
33410  * @element ANY
33411  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
33412  *   of the evaluation can be a string representing space delimited class
33413  *   names, an array, or a map of class names to boolean values. In the case of a map, the
33414  *   names of the properties whose values are truthy will be added as css classes to the
33415  *   element.
33416  *
33417  * @example Example that demonstrates basic bindings via ngClass directive.
33418    <example>
33419      <file name="index.html">
33420        <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
33421        <label>
33422           <input type="checkbox" ng-model="deleted">
33423           deleted (apply "strike" class)
33424        </label><br>
33425        <label>
33426           <input type="checkbox" ng-model="important">
33427           important (apply "bold" class)
33428        </label><br>
33429        <label>
33430           <input type="checkbox" ng-model="error">
33431           error (apply "has-error" class)
33432        </label>
33433        <hr>
33434        <p ng-class="style">Using String Syntax</p>
33435        <input type="text" ng-model="style"
33436               placeholder="Type: bold strike red" aria-label="Type: bold strike red">
33437        <hr>
33438        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
33439        <input ng-model="style1"
33440               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
33441        <input ng-model="style2"
33442               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
33443        <input ng-model="style3"
33444               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
33445        <hr>
33446        <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
33447        <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
33448        <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
33449      </file>
33450      <file name="style.css">
33451        .strike {
33452            text-decoration: line-through;
33453        }
33454        .bold {
33455            font-weight: bold;
33456        }
33457        .red {
33458            color: red;
33459        }
33460        .has-error {
33461            color: red;
33462            background-color: yellow;
33463        }
33464        .orange {
33465            color: orange;
33466        }
33467      </file>
33468      <file name="protractor.js" type="protractor">
33469        var ps = element.all(by.css('p'));
33470
33471        it('should let you toggle the class', function() {
33472
33473          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
33474          expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
33475
33476          element(by.model('important')).click();
33477          expect(ps.first().getAttribute('class')).toMatch(/bold/);
33478
33479          element(by.model('error')).click();
33480          expect(ps.first().getAttribute('class')).toMatch(/has-error/);
33481        });
33482
33483        it('should let you toggle string example', function() {
33484          expect(ps.get(1).getAttribute('class')).toBe('');
33485          element(by.model('style')).clear();
33486          element(by.model('style')).sendKeys('red');
33487          expect(ps.get(1).getAttribute('class')).toBe('red');
33488        });
33489
33490        it('array example should have 3 classes', function() {
33491          expect(ps.get(2).getAttribute('class')).toBe('');
33492          element(by.model('style1')).sendKeys('bold');
33493          element(by.model('style2')).sendKeys('strike');
33494          element(by.model('style3')).sendKeys('red');
33495          expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
33496        });
33497
33498        it('array with map example should have 2 classes', function() {
33499          expect(ps.last().getAttribute('class')).toBe('');
33500          element(by.model('style4')).sendKeys('bold');
33501          element(by.model('warning')).click();
33502          expect(ps.last().getAttribute('class')).toBe('bold orange');
33503        });
33504      </file>
33505    </example>
33506
33507    ## Animations
33508
33509    The example below demonstrates how to perform animations using ngClass.
33510
33511    <example module="ngAnimate" deps="angular-animate.js" animations="true">
33512      <file name="index.html">
33513       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
33514       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
33515       <br>
33516       <span class="base-class" ng-class="myVar">Sample Text</span>
33517      </file>
33518      <file name="style.css">
33519        .base-class {
33520          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33521        }
33522
33523        .base-class.my-class {
33524          color: red;
33525          font-size:3em;
33526        }
33527      </file>
33528      <file name="protractor.js" type="protractor">
33529        it('should check ng-class', function() {
33530          expect(element(by.css('.base-class')).getAttribute('class')).not.
33531            toMatch(/my-class/);
33532
33533          element(by.id('setbtn')).click();
33534
33535          expect(element(by.css('.base-class')).getAttribute('class')).
33536            toMatch(/my-class/);
33537
33538          element(by.id('clearbtn')).click();
33539
33540          expect(element(by.css('.base-class')).getAttribute('class')).not.
33541            toMatch(/my-class/);
33542        });
33543      </file>
33544    </example>
33545
33546
33547    ## ngClass and pre-existing CSS3 Transitions/Animations
33548    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
33549    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
33550    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
33551    to view the step by step details of {@link $animate#addClass $animate.addClass} and
33552    {@link $animate#removeClass $animate.removeClass}.
33553  */
33554 var ngClassDirective = classDirective('', true);
33555
33556 /**
33557  * @ngdoc directive
33558  * @name ngClassOdd
33559  * @restrict AC
33560  *
33561  * @description
33562  * The `ngClassOdd` and `ngClassEven` directives work exactly as
33563  * {@link ng.directive:ngClass ngClass}, except they work in
33564  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
33565  *
33566  * This directive can be applied only within the scope of an
33567  * {@link ng.directive:ngRepeat ngRepeat}.
33568  *
33569  * @element ANY
33570  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
33571  *   of the evaluation can be a string representing space delimited class names or an array.
33572  *
33573  * @example
33574    <example>
33575      <file name="index.html">
33576         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
33577           <li ng-repeat="name in names">
33578            <span ng-class-odd="'odd'" ng-class-even="'even'">
33579              {{name}}
33580            </span>
33581           </li>
33582         </ol>
33583      </file>
33584      <file name="style.css">
33585        .odd {
33586          color: red;
33587        }
33588        .even {
33589          color: blue;
33590        }
33591      </file>
33592      <file name="protractor.js" type="protractor">
33593        it('should check ng-class-odd and ng-class-even', function() {
33594          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
33595            toMatch(/odd/);
33596          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
33597            toMatch(/even/);
33598        });
33599      </file>
33600    </example>
33601  */
33602 var ngClassOddDirective = classDirective('Odd', 0);
33603
33604 /**
33605  * @ngdoc directive
33606  * @name ngClassEven
33607  * @restrict AC
33608  *
33609  * @description
33610  * The `ngClassOdd` and `ngClassEven` directives work exactly as
33611  * {@link ng.directive:ngClass ngClass}, except they work in
33612  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
33613  *
33614  * This directive can be applied only within the scope of an
33615  * {@link ng.directive:ngRepeat ngRepeat}.
33616  *
33617  * @element ANY
33618  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
33619  *   result of the evaluation can be a string representing space delimited class names or an array.
33620  *
33621  * @example
33622    <example>
33623      <file name="index.html">
33624         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
33625           <li ng-repeat="name in names">
33626            <span ng-class-odd="'odd'" ng-class-even="'even'">
33627              {{name}} &nbsp; &nbsp; &nbsp;
33628            </span>
33629           </li>
33630         </ol>
33631      </file>
33632      <file name="style.css">
33633        .odd {
33634          color: red;
33635        }
33636        .even {
33637          color: blue;
33638        }
33639      </file>
33640      <file name="protractor.js" type="protractor">
33641        it('should check ng-class-odd and ng-class-even', function() {
33642          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
33643            toMatch(/odd/);
33644          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
33645            toMatch(/even/);
33646        });
33647      </file>
33648    </example>
33649  */
33650 var ngClassEvenDirective = classDirective('Even', 1);
33651
33652 /**
33653  * @ngdoc directive
33654  * @name ngCloak
33655  * @restrict AC
33656  *
33657  * @description
33658  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
33659  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
33660  * directive to avoid the undesirable flicker effect caused by the html template display.
33661  *
33662  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
33663  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
33664  * of the browser view.
33665  *
33666  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
33667  * `angular.min.js`.
33668  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
33669  *
33670  * ```css
33671  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
33672  *   display: none !important;
33673  * }
33674  * ```
33675  *
33676  * When this css rule is loaded by the browser, all html elements (including their children) that
33677  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
33678  * during the compilation of the template it deletes the `ngCloak` element attribute, making
33679  * the compiled element visible.
33680  *
33681  * For the best result, the `angular.js` script must be loaded in the head section of the html
33682  * document; alternatively, the css rule above must be included in the external stylesheet of the
33683  * application.
33684  *
33685  * @element ANY
33686  *
33687  * @example
33688    <example>
33689      <file name="index.html">
33690         <div id="template1" ng-cloak>{{ 'hello' }}</div>
33691         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
33692      </file>
33693      <file name="protractor.js" type="protractor">
33694        it('should remove the template directive and css class', function() {
33695          expect($('#template1').getAttribute('ng-cloak')).
33696            toBeNull();
33697          expect($('#template2').getAttribute('ng-cloak')).
33698            toBeNull();
33699        });
33700      </file>
33701    </example>
33702  *
33703  */
33704 var ngCloakDirective = ngDirective({
33705   compile: function(element, attr) {
33706     attr.$set('ngCloak', undefined);
33707     element.removeClass('ng-cloak');
33708   }
33709 });
33710
33711 /**
33712  * @ngdoc directive
33713  * @name ngController
33714  *
33715  * @description
33716  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
33717  * supports the principles behind the Model-View-Controller design pattern.
33718  *
33719  * MVC components in angular:
33720  *
33721  * * Model â€” Models are the properties of a scope; scopes are attached to the DOM where scope properties
33722  *   are accessed through bindings.
33723  * * View â€” The template (HTML with data bindings) that is rendered into the View.
33724  * * Controller â€” The `ngController` directive specifies a Controller class; the class contains business
33725  *   logic behind the application to decorate the scope with functions and values
33726  *
33727  * Note that you can also attach controllers to the DOM by declaring it in a route definition
33728  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
33729  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
33730  * and executed twice.
33731  *
33732  * @element ANY
33733  * @scope
33734  * @priority 500
33735  * @param {expression} ngController Name of a constructor function registered with the current
33736  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
33737  * that on the current scope evaluates to a constructor function.
33738  *
33739  * The controller instance can be published into a scope property by specifying
33740  * `ng-controller="as propertyName"`.
33741  *
33742  * If the current `$controllerProvider` is configured to use globals (via
33743  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
33744  * also be the name of a globally accessible constructor function (not recommended).
33745  *
33746  * @example
33747  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
33748  * greeting are methods declared on the controller (see source tab). These methods can
33749  * easily be called from the angular markup. Any changes to the data are automatically reflected
33750  * in the View without the need for a manual update.
33751  *
33752  * Two different declaration styles are included below:
33753  *
33754  * * one binds methods and properties directly onto the controller using `this`:
33755  * `ng-controller="SettingsController1 as settings"`
33756  * * one injects `$scope` into the controller:
33757  * `ng-controller="SettingsController2"`
33758  *
33759  * The second option is more common in the Angular community, and is generally used in boilerplates
33760  * and in this guide. However, there are advantages to binding properties directly to the controller
33761  * and avoiding scope.
33762  *
33763  * * Using `controller as` makes it obvious which controller you are accessing in the template when
33764  * multiple controllers apply to an element.
33765  * * If you are writing your controllers as classes you have easier access to the properties and
33766  * methods, which will appear on the scope, from inside the controller code.
33767  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
33768  * inheritance masking primitives.
33769  *
33770  * This example demonstrates the `controller as` syntax.
33771  *
33772  * <example name="ngControllerAs" module="controllerAsExample">
33773  *   <file name="index.html">
33774  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
33775  *      <label>Name: <input type="text" ng-model="settings.name"/></label>
33776  *      <button ng-click="settings.greet()">greet</button><br/>
33777  *      Contact:
33778  *      <ul>
33779  *        <li ng-repeat="contact in settings.contacts">
33780  *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
33781  *             <option>phone</option>
33782  *             <option>email</option>
33783  *          </select>
33784  *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
33785  *          <button ng-click="settings.clearContact(contact)">clear</button>
33786  *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
33787  *        </li>
33788  *        <li><button ng-click="settings.addContact()">add</button></li>
33789  *     </ul>
33790  *    </div>
33791  *   </file>
33792  *   <file name="app.js">
33793  *    angular.module('controllerAsExample', [])
33794  *      .controller('SettingsController1', SettingsController1);
33795  *
33796  *    function SettingsController1() {
33797  *      this.name = "John Smith";
33798  *      this.contacts = [
33799  *        {type: 'phone', value: '408 555 1212'},
33800  *        {type: 'email', value: 'john.smith@example.org'} ];
33801  *    }
33802  *
33803  *    SettingsController1.prototype.greet = function() {
33804  *      alert(this.name);
33805  *    };
33806  *
33807  *    SettingsController1.prototype.addContact = function() {
33808  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
33809  *    };
33810  *
33811  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
33812  *     var index = this.contacts.indexOf(contactToRemove);
33813  *      this.contacts.splice(index, 1);
33814  *    };
33815  *
33816  *    SettingsController1.prototype.clearContact = function(contact) {
33817  *      contact.type = 'phone';
33818  *      contact.value = '';
33819  *    };
33820  *   </file>
33821  *   <file name="protractor.js" type="protractor">
33822  *     it('should check controller as', function() {
33823  *       var container = element(by.id('ctrl-as-exmpl'));
33824  *         expect(container.element(by.model('settings.name'))
33825  *           .getAttribute('value')).toBe('John Smith');
33826  *
33827  *       var firstRepeat =
33828  *           container.element(by.repeater('contact in settings.contacts').row(0));
33829  *       var secondRepeat =
33830  *           container.element(by.repeater('contact in settings.contacts').row(1));
33831  *
33832  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33833  *           .toBe('408 555 1212');
33834  *
33835  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
33836  *           .toBe('john.smith@example.org');
33837  *
33838  *       firstRepeat.element(by.buttonText('clear')).click();
33839  *
33840  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33841  *           .toBe('');
33842  *
33843  *       container.element(by.buttonText('add')).click();
33844  *
33845  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
33846  *           .element(by.model('contact.value'))
33847  *           .getAttribute('value'))
33848  *           .toBe('yourname@example.org');
33849  *     });
33850  *   </file>
33851  * </example>
33852  *
33853  * This example demonstrates the "attach to `$scope`" style of controller.
33854  *
33855  * <example name="ngController" module="controllerExample">
33856  *  <file name="index.html">
33857  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
33858  *     <label>Name: <input type="text" ng-model="name"/></label>
33859  *     <button ng-click="greet()">greet</button><br/>
33860  *     Contact:
33861  *     <ul>
33862  *       <li ng-repeat="contact in contacts">
33863  *         <select ng-model="contact.type" id="select_{{$index}}">
33864  *            <option>phone</option>
33865  *            <option>email</option>
33866  *         </select>
33867  *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
33868  *         <button ng-click="clearContact(contact)">clear</button>
33869  *         <button ng-click="removeContact(contact)">X</button>
33870  *       </li>
33871  *       <li>[ <button ng-click="addContact()">add</button> ]</li>
33872  *    </ul>
33873  *   </div>
33874  *  </file>
33875  *  <file name="app.js">
33876  *   angular.module('controllerExample', [])
33877  *     .controller('SettingsController2', ['$scope', SettingsController2]);
33878  *
33879  *   function SettingsController2($scope) {
33880  *     $scope.name = "John Smith";
33881  *     $scope.contacts = [
33882  *       {type:'phone', value:'408 555 1212'},
33883  *       {type:'email', value:'john.smith@example.org'} ];
33884  *
33885  *     $scope.greet = function() {
33886  *       alert($scope.name);
33887  *     };
33888  *
33889  *     $scope.addContact = function() {
33890  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
33891  *     };
33892  *
33893  *     $scope.removeContact = function(contactToRemove) {
33894  *       var index = $scope.contacts.indexOf(contactToRemove);
33895  *       $scope.contacts.splice(index, 1);
33896  *     };
33897  *
33898  *     $scope.clearContact = function(contact) {
33899  *       contact.type = 'phone';
33900  *       contact.value = '';
33901  *     };
33902  *   }
33903  *  </file>
33904  *  <file name="protractor.js" type="protractor">
33905  *    it('should check controller', function() {
33906  *      var container = element(by.id('ctrl-exmpl'));
33907  *
33908  *      expect(container.element(by.model('name'))
33909  *          .getAttribute('value')).toBe('John Smith');
33910  *
33911  *      var firstRepeat =
33912  *          container.element(by.repeater('contact in contacts').row(0));
33913  *      var secondRepeat =
33914  *          container.element(by.repeater('contact in contacts').row(1));
33915  *
33916  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33917  *          .toBe('408 555 1212');
33918  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
33919  *          .toBe('john.smith@example.org');
33920  *
33921  *      firstRepeat.element(by.buttonText('clear')).click();
33922  *
33923  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33924  *          .toBe('');
33925  *
33926  *      container.element(by.buttonText('add')).click();
33927  *
33928  *      expect(container.element(by.repeater('contact in contacts').row(2))
33929  *          .element(by.model('contact.value'))
33930  *          .getAttribute('value'))
33931  *          .toBe('yourname@example.org');
33932  *    });
33933  *  </file>
33934  *</example>
33935
33936  */
33937 var ngControllerDirective = [function() {
33938   return {
33939     restrict: 'A',
33940     scope: true,
33941     controller: '@',
33942     priority: 500
33943   };
33944 }];
33945
33946 /**
33947  * @ngdoc directive
33948  * @name ngCsp
33949  *
33950  * @element html
33951  * @description
33952  *
33953  * Angular has some features that can break certain
33954  * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
33955  *
33956  * If you intend to implement these rules then you must tell Angular not to use these features.
33957  *
33958  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
33959  *
33960  *
33961  * The following rules affect Angular:
33962  *
33963  * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
33964  * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
33965  * increase in the speed of evaluating Angular expressions.
33966  *
33967  * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
33968  * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
33969  * To make these directives work when a CSP rule is blocking inline styles, you must link to the
33970  * `angular-csp.css` in your HTML manually.
33971  *
33972  * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
33973  * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
33974  * however, triggers a CSP error to be logged in the console:
33975  *
33976  * ```
33977  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
33978  * script in the following Content Security Policy directive: "default-src 'self'". Note that
33979  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
33980  * ```
33981  *
33982  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
33983  * directive on an element of the HTML document that appears before the `<script>` tag that loads
33984  * the `angular.js` file.
33985  *
33986  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
33987  *
33988  * You can specify which of the CSP related Angular features should be deactivated by providing
33989  * a value for the `ng-csp` attribute. The options are as follows:
33990  *
33991  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
33992  *
33993  * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
33994  *
33995  * You can use these values in the following combinations:
33996  *
33997  *
33998  * * No declaration means that Angular will assume that you can do inline styles, but it will do
33999  * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
34000  * of Angular.
34001  *
34002  * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
34003  * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
34004  * of Angular.
34005  *
34006  * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
34007  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
34008  *
34009  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
34010  * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
34011  *
34012  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
34013  * styles nor use eval, which is the same as an empty: ng-csp.
34014  * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
34015  *
34016  * @example
34017  * This example shows how to apply the `ngCsp` directive to the `html` tag.
34018    ```html
34019      <!doctype html>
34020      <html ng-app ng-csp>
34021      ...
34022      ...
34023      </html>
34024    ```
34025   * @example
34026       // Note: the suffix `.csp` in the example name triggers
34027       // csp mode in our http server!
34028       <example name="example.csp" module="cspExample" ng-csp="true">
34029         <file name="index.html">
34030           <div ng-controller="MainController as ctrl">
34031             <div>
34032               <button ng-click="ctrl.inc()" id="inc">Increment</button>
34033               <span id="counter">
34034                 {{ctrl.counter}}
34035               </span>
34036             </div>
34037
34038             <div>
34039               <button ng-click="ctrl.evil()" id="evil">Evil</button>
34040               <span id="evilError">
34041                 {{ctrl.evilError}}
34042               </span>
34043             </div>
34044           </div>
34045         </file>
34046         <file name="script.js">
34047            angular.module('cspExample', [])
34048              .controller('MainController', function() {
34049                 this.counter = 0;
34050                 this.inc = function() {
34051                   this.counter++;
34052                 };
34053                 this.evil = function() {
34054                   // jshint evil:true
34055                   try {
34056                     eval('1+2');
34057                   } catch (e) {
34058                     this.evilError = e.message;
34059                   }
34060                 };
34061               });
34062         </file>
34063         <file name="protractor.js" type="protractor">
34064           var util, webdriver;
34065
34066           var incBtn = element(by.id('inc'));
34067           var counter = element(by.id('counter'));
34068           var evilBtn = element(by.id('evil'));
34069           var evilError = element(by.id('evilError'));
34070
34071           function getAndClearSevereErrors() {
34072             return browser.manage().logs().get('browser').then(function(browserLog) {
34073               return browserLog.filter(function(logEntry) {
34074                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
34075               });
34076             });
34077           }
34078
34079           function clearErrors() {
34080             getAndClearSevereErrors();
34081           }
34082
34083           function expectNoErrors() {
34084             getAndClearSevereErrors().then(function(filteredLog) {
34085               expect(filteredLog.length).toEqual(0);
34086               if (filteredLog.length) {
34087                 console.log('browser console errors: ' + util.inspect(filteredLog));
34088               }
34089             });
34090           }
34091
34092           function expectError(regex) {
34093             getAndClearSevereErrors().then(function(filteredLog) {
34094               var found = false;
34095               filteredLog.forEach(function(log) {
34096                 if (log.message.match(regex)) {
34097                   found = true;
34098                 }
34099               });
34100               if (!found) {
34101                 throw new Error('expected an error that matches ' + regex);
34102               }
34103             });
34104           }
34105
34106           beforeEach(function() {
34107             util = require('util');
34108             webdriver = require('protractor/node_modules/selenium-webdriver');
34109           });
34110
34111           // For now, we only test on Chrome,
34112           // as Safari does not load the page with Protractor's injected scripts,
34113           // and Firefox webdriver always disables content security policy (#6358)
34114           if (browser.params.browser !== 'chrome') {
34115             return;
34116           }
34117
34118           it('should not report errors when the page is loaded', function() {
34119             // clear errors so we are not dependent on previous tests
34120             clearErrors();
34121             // Need to reload the page as the page is already loaded when
34122             // we come here
34123             browser.driver.getCurrentUrl().then(function(url) {
34124               browser.get(url);
34125             });
34126             expectNoErrors();
34127           });
34128
34129           it('should evaluate expressions', function() {
34130             expect(counter.getText()).toEqual('0');
34131             incBtn.click();
34132             expect(counter.getText()).toEqual('1');
34133             expectNoErrors();
34134           });
34135
34136           it('should throw and report an error when using "eval"', function() {
34137             evilBtn.click();
34138             expect(evilError.getText()).toMatch(/Content Security Policy/);
34139             expectError(/Content Security Policy/);
34140           });
34141         </file>
34142       </example>
34143   */
34144
34145 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
34146 // bootstrap the system (before $parse is instantiated), for this reason we just have
34147 // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
34148
34149 /**
34150  * @ngdoc directive
34151  * @name ngClick
34152  *
34153  * @description
34154  * The ngClick directive allows you to specify custom behavior when
34155  * an element is clicked.
34156  *
34157  * @element ANY
34158  * @priority 0
34159  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
34160  * click. ({@link guide/expression#-event- Event object is available as `$event`})
34161  *
34162  * @example
34163    <example>
34164      <file name="index.html">
34165       <button ng-click="count = count + 1" ng-init="count=0">
34166         Increment
34167       </button>
34168       <span>
34169         count: {{count}}
34170       </span>
34171      </file>
34172      <file name="protractor.js" type="protractor">
34173        it('should check ng-click', function() {
34174          expect(element(by.binding('count')).getText()).toMatch('0');
34175          element(by.css('button')).click();
34176          expect(element(by.binding('count')).getText()).toMatch('1');
34177        });
34178      </file>
34179    </example>
34180  */
34181 /*
34182  * A collection of directives that allows creation of custom event handlers that are defined as
34183  * angular expressions and are compiled and executed within the current scope.
34184  */
34185 var ngEventDirectives = {};
34186
34187 // For events that might fire synchronously during DOM manipulation
34188 // we need to execute their event handlers asynchronously using $evalAsync,
34189 // so that they are not executed in an inconsistent state.
34190 var forceAsyncEvents = {
34191   'blur': true,
34192   'focus': true
34193 };
34194 forEach(
34195   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
34196   function(eventName) {
34197     var directiveName = directiveNormalize('ng-' + eventName);
34198     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
34199       return {
34200         restrict: 'A',
34201         compile: function($element, attr) {
34202           // We expose the powerful $event object on the scope that provides access to the Window,
34203           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
34204           // checks at the cost of speed since event handler expressions are not executed as
34205           // frequently as regular change detection.
34206           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
34207           return function ngEventHandler(scope, element) {
34208             element.on(eventName, function(event) {
34209               var callback = function() {
34210                 fn(scope, {$event:event});
34211               };
34212               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
34213                 scope.$evalAsync(callback);
34214               } else {
34215                 scope.$apply(callback);
34216               }
34217             });
34218           };
34219         }
34220       };
34221     }];
34222   }
34223 );
34224
34225 /**
34226  * @ngdoc directive
34227  * @name ngDblclick
34228  *
34229  * @description
34230  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
34231  *
34232  * @element ANY
34233  * @priority 0
34234  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
34235  * a dblclick. (The Event object is available as `$event`)
34236  *
34237  * @example
34238    <example>
34239      <file name="index.html">
34240       <button ng-dblclick="count = count + 1" ng-init="count=0">
34241         Increment (on double click)
34242       </button>
34243       count: {{count}}
34244      </file>
34245    </example>
34246  */
34247
34248
34249 /**
34250  * @ngdoc directive
34251  * @name ngMousedown
34252  *
34253  * @description
34254  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
34255  *
34256  * @element ANY
34257  * @priority 0
34258  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
34259  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
34260  *
34261  * @example
34262    <example>
34263      <file name="index.html">
34264       <button ng-mousedown="count = count + 1" ng-init="count=0">
34265         Increment (on mouse down)
34266       </button>
34267       count: {{count}}
34268      </file>
34269    </example>
34270  */
34271
34272
34273 /**
34274  * @ngdoc directive
34275  * @name ngMouseup
34276  *
34277  * @description
34278  * Specify custom behavior on mouseup event.
34279  *
34280  * @element ANY
34281  * @priority 0
34282  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
34283  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
34284  *
34285  * @example
34286    <example>
34287      <file name="index.html">
34288       <button ng-mouseup="count = count + 1" ng-init="count=0">
34289         Increment (on mouse up)
34290       </button>
34291       count: {{count}}
34292      </file>
34293    </example>
34294  */
34295
34296 /**
34297  * @ngdoc directive
34298  * @name ngMouseover
34299  *
34300  * @description
34301  * Specify custom behavior on mouseover event.
34302  *
34303  * @element ANY
34304  * @priority 0
34305  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
34306  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
34307  *
34308  * @example
34309    <example>
34310      <file name="index.html">
34311       <button ng-mouseover="count = count + 1" ng-init="count=0">
34312         Increment (when mouse is over)
34313       </button>
34314       count: {{count}}
34315      </file>
34316    </example>
34317  */
34318
34319
34320 /**
34321  * @ngdoc directive
34322  * @name ngMouseenter
34323  *
34324  * @description
34325  * Specify custom behavior on mouseenter event.
34326  *
34327  * @element ANY
34328  * @priority 0
34329  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
34330  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
34331  *
34332  * @example
34333    <example>
34334      <file name="index.html">
34335       <button ng-mouseenter="count = count + 1" ng-init="count=0">
34336         Increment (when mouse enters)
34337       </button>
34338       count: {{count}}
34339      </file>
34340    </example>
34341  */
34342
34343
34344 /**
34345  * @ngdoc directive
34346  * @name ngMouseleave
34347  *
34348  * @description
34349  * Specify custom behavior on mouseleave event.
34350  *
34351  * @element ANY
34352  * @priority 0
34353  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
34354  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
34355  *
34356  * @example
34357    <example>
34358      <file name="index.html">
34359       <button ng-mouseleave="count = count + 1" ng-init="count=0">
34360         Increment (when mouse leaves)
34361       </button>
34362       count: {{count}}
34363      </file>
34364    </example>
34365  */
34366
34367
34368 /**
34369  * @ngdoc directive
34370  * @name ngMousemove
34371  *
34372  * @description
34373  * Specify custom behavior on mousemove event.
34374  *
34375  * @element ANY
34376  * @priority 0
34377  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
34378  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
34379  *
34380  * @example
34381    <example>
34382      <file name="index.html">
34383       <button ng-mousemove="count = count + 1" ng-init="count=0">
34384         Increment (when mouse moves)
34385       </button>
34386       count: {{count}}
34387      </file>
34388    </example>
34389  */
34390
34391
34392 /**
34393  * @ngdoc directive
34394  * @name ngKeydown
34395  *
34396  * @description
34397  * Specify custom behavior on keydown event.
34398  *
34399  * @element ANY
34400  * @priority 0
34401  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
34402  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
34403  *
34404  * @example
34405    <example>
34406      <file name="index.html">
34407       <input ng-keydown="count = count + 1" ng-init="count=0">
34408       key down count: {{count}}
34409      </file>
34410    </example>
34411  */
34412
34413
34414 /**
34415  * @ngdoc directive
34416  * @name ngKeyup
34417  *
34418  * @description
34419  * Specify custom behavior on keyup event.
34420  *
34421  * @element ANY
34422  * @priority 0
34423  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
34424  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
34425  *
34426  * @example
34427    <example>
34428      <file name="index.html">
34429        <p>Typing in the input box below updates the key count</p>
34430        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
34431
34432        <p>Typing in the input box below updates the keycode</p>
34433        <input ng-keyup="event=$event">
34434        <p>event keyCode: {{ event.keyCode }}</p>
34435        <p>event altKey: {{ event.altKey }}</p>
34436      </file>
34437    </example>
34438  */
34439
34440
34441 /**
34442  * @ngdoc directive
34443  * @name ngKeypress
34444  *
34445  * @description
34446  * Specify custom behavior on keypress event.
34447  *
34448  * @element ANY
34449  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
34450  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
34451  * and can be interrogated for keyCode, altKey, etc.)
34452  *
34453  * @example
34454    <example>
34455      <file name="index.html">
34456       <input ng-keypress="count = count + 1" ng-init="count=0">
34457       key press count: {{count}}
34458      </file>
34459    </example>
34460  */
34461
34462
34463 /**
34464  * @ngdoc directive
34465  * @name ngSubmit
34466  *
34467  * @description
34468  * Enables binding angular expressions to onsubmit events.
34469  *
34470  * Additionally it prevents the default action (which for form means sending the request to the
34471  * server and reloading the current page), but only if the form does not contain `action`,
34472  * `data-action`, or `x-action` attributes.
34473  *
34474  * <div class="alert alert-warning">
34475  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
34476  * `ngSubmit` handlers together. See the
34477  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
34478  * for a detailed discussion of when `ngSubmit` may be triggered.
34479  * </div>
34480  *
34481  * @element form
34482  * @priority 0
34483  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
34484  * ({@link guide/expression#-event- Event object is available as `$event`})
34485  *
34486  * @example
34487    <example module="submitExample">
34488      <file name="index.html">
34489       <script>
34490         angular.module('submitExample', [])
34491           .controller('ExampleController', ['$scope', function($scope) {
34492             $scope.list = [];
34493             $scope.text = 'hello';
34494             $scope.submit = function() {
34495               if ($scope.text) {
34496                 $scope.list.push(this.text);
34497                 $scope.text = '';
34498               }
34499             };
34500           }]);
34501       </script>
34502       <form ng-submit="submit()" ng-controller="ExampleController">
34503         Enter text and hit enter:
34504         <input type="text" ng-model="text" name="text" />
34505         <input type="submit" id="submit" value="Submit" />
34506         <pre>list={{list}}</pre>
34507       </form>
34508      </file>
34509      <file name="protractor.js" type="protractor">
34510        it('should check ng-submit', function() {
34511          expect(element(by.binding('list')).getText()).toBe('list=[]');
34512          element(by.css('#submit')).click();
34513          expect(element(by.binding('list')).getText()).toContain('hello');
34514          expect(element(by.model('text')).getAttribute('value')).toBe('');
34515        });
34516        it('should ignore empty strings', function() {
34517          expect(element(by.binding('list')).getText()).toBe('list=[]');
34518          element(by.css('#submit')).click();
34519          element(by.css('#submit')).click();
34520          expect(element(by.binding('list')).getText()).toContain('hello');
34521         });
34522      </file>
34523    </example>
34524  */
34525
34526 /**
34527  * @ngdoc directive
34528  * @name ngFocus
34529  *
34530  * @description
34531  * Specify custom behavior on focus event.
34532  *
34533  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
34534  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
34535  * during an `$apply` to ensure a consistent state.
34536  *
34537  * @element window, input, select, textarea, a
34538  * @priority 0
34539  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
34540  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
34541  *
34542  * @example
34543  * See {@link ng.directive:ngClick ngClick}
34544  */
34545
34546 /**
34547  * @ngdoc directive
34548  * @name ngBlur
34549  *
34550  * @description
34551  * Specify custom behavior on blur event.
34552  *
34553  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
34554  * an element has lost focus.
34555  *
34556  * Note: As the `blur` event is executed synchronously also during DOM manipulations
34557  * (e.g. removing a focussed input),
34558  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
34559  * during an `$apply` to ensure a consistent state.
34560  *
34561  * @element window, input, select, textarea, a
34562  * @priority 0
34563  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
34564  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
34565  *
34566  * @example
34567  * See {@link ng.directive:ngClick ngClick}
34568  */
34569
34570 /**
34571  * @ngdoc directive
34572  * @name ngCopy
34573  *
34574  * @description
34575  * Specify custom behavior on copy event.
34576  *
34577  * @element window, input, select, textarea, a
34578  * @priority 0
34579  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
34580  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
34581  *
34582  * @example
34583    <example>
34584      <file name="index.html">
34585       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
34586       copied: {{copied}}
34587      </file>
34588    </example>
34589  */
34590
34591 /**
34592  * @ngdoc directive
34593  * @name ngCut
34594  *
34595  * @description
34596  * Specify custom behavior on cut event.
34597  *
34598  * @element window, input, select, textarea, a
34599  * @priority 0
34600  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
34601  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
34602  *
34603  * @example
34604    <example>
34605      <file name="index.html">
34606       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
34607       cut: {{cut}}
34608      </file>
34609    </example>
34610  */
34611
34612 /**
34613  * @ngdoc directive
34614  * @name ngPaste
34615  *
34616  * @description
34617  * Specify custom behavior on paste event.
34618  *
34619  * @element window, input, select, textarea, a
34620  * @priority 0
34621  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
34622  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
34623  *
34624  * @example
34625    <example>
34626      <file name="index.html">
34627       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
34628       pasted: {{paste}}
34629      </file>
34630    </example>
34631  */
34632
34633 /**
34634  * @ngdoc directive
34635  * @name ngIf
34636  * @restrict A
34637  * @multiElement
34638  *
34639  * @description
34640  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
34641  * {expression}. If the expression assigned to `ngIf` evaluates to a false
34642  * value then the element is removed from the DOM, otherwise a clone of the
34643  * element is reinserted into the DOM.
34644  *
34645  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
34646  * element in the DOM rather than changing its visibility via the `display` css property.  A common
34647  * case when this difference is significant is when using css selectors that rely on an element's
34648  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
34649  *
34650  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
34651  * is created when the element is restored.  The scope created within `ngIf` inherits from
34652  * its parent scope using
34653  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
34654  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
34655  * a javascript primitive defined in the parent scope. In this case any modifications made to the
34656  * variable within the child scope will override (hide) the value in the parent scope.
34657  *
34658  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
34659  * is if an element's class attribute is directly modified after it's compiled, using something like
34660  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
34661  * the added class will be lost because the original compiled state is used to regenerate the element.
34662  *
34663  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
34664  * and `leave` effects.
34665  *
34666  * @animations
34667  * | Animation                        | Occurs                               |
34668  * |----------------------------------|-------------------------------------|
34669  * | {@link ng.$animate#enter enter}  | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
34670  * | {@link ng.$animate#leave leave}  | just before the `ngIf` contents are removed from the DOM |
34671  *
34672  * @element ANY
34673  * @scope
34674  * @priority 600
34675  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
34676  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
34677  *     element is added to the DOM tree.
34678  *
34679  * @example
34680   <example module="ngAnimate" deps="angular-animate.js" animations="true">
34681     <file name="index.html">
34682       <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
34683       Show when checked:
34684       <span ng-if="checked" class="animate-if">
34685         This is removed when the checkbox is unchecked.
34686       </span>
34687     </file>
34688     <file name="animations.css">
34689       .animate-if {
34690         background:white;
34691         border:1px solid black;
34692         padding:10px;
34693       }
34694
34695       .animate-if.ng-enter, .animate-if.ng-leave {
34696         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34697       }
34698
34699       .animate-if.ng-enter,
34700       .animate-if.ng-leave.ng-leave-active {
34701         opacity:0;
34702       }
34703
34704       .animate-if.ng-leave,
34705       .animate-if.ng-enter.ng-enter-active {
34706         opacity:1;
34707       }
34708     </file>
34709   </example>
34710  */
34711 var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
34712   return {
34713     multiElement: true,
34714     transclude: 'element',
34715     priority: 600,
34716     terminal: true,
34717     restrict: 'A',
34718     $$tlb: true,
34719     link: function($scope, $element, $attr, ctrl, $transclude) {
34720         var block, childScope, previousElements;
34721         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
34722
34723           if (value) {
34724             if (!childScope) {
34725               $transclude(function(clone, newScope) {
34726                 childScope = newScope;
34727                 clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
34728                 // Note: We only need the first/last node of the cloned nodes.
34729                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
34730                 // by a directive with templateUrl when its template arrives.
34731                 block = {
34732                   clone: clone
34733                 };
34734                 $animate.enter(clone, $element.parent(), $element);
34735               });
34736             }
34737           } else {
34738             if (previousElements) {
34739               previousElements.remove();
34740               previousElements = null;
34741             }
34742             if (childScope) {
34743               childScope.$destroy();
34744               childScope = null;
34745             }
34746             if (block) {
34747               previousElements = getBlockNodes(block.clone);
34748               $animate.leave(previousElements).then(function() {
34749                 previousElements = null;
34750               });
34751               block = null;
34752             }
34753           }
34754         });
34755     }
34756   };
34757 }];
34758
34759 /**
34760  * @ngdoc directive
34761  * @name ngInclude
34762  * @restrict ECA
34763  *
34764  * @description
34765  * Fetches, compiles and includes an external HTML fragment.
34766  *
34767  * By default, the template URL is restricted to the same domain and protocol as the
34768  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
34769  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
34770  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
34771  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
34772  * ng.$sce Strict Contextual Escaping}.
34773  *
34774  * In addition, the browser's
34775  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
34776  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
34777  * policy may further restrict whether the template is successfully loaded.
34778  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
34779  * access on some browsers.
34780  *
34781  * @animations
34782  * | Animation                        | Occurs                              |
34783  * |----------------------------------|-------------------------------------|
34784  * | {@link ng.$animate#enter enter}  | when the expression changes, on the new include |
34785  * | {@link ng.$animate#leave leave}  | when the expression changes, on the old include |
34786  *
34787  * The enter and leave animation occur concurrently.
34788  *
34789  * @scope
34790  * @priority 400
34791  *
34792  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
34793  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
34794  * @param {string=} onload Expression to evaluate when a new partial is loaded.
34795  *                  <div class="alert alert-warning">
34796  *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
34797  *                  a function with the name on the window element, which will usually throw a
34798  *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
34799  *                  different form that {@link guide/directive#normalization matches} `onload`.
34800  *                  </div>
34801    *
34802  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
34803  *                  $anchorScroll} to scroll the viewport after the content is loaded.
34804  *
34805  *                  - If the attribute is not set, disable scrolling.
34806  *                  - If the attribute is set without value, enable scrolling.
34807  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
34808  *
34809  * @example
34810   <example module="includeExample" deps="angular-animate.js" animations="true">
34811     <file name="index.html">
34812      <div ng-controller="ExampleController">
34813        <select ng-model="template" ng-options="t.name for t in templates">
34814         <option value="">(blank)</option>
34815        </select>
34816        url of the template: <code>{{template.url}}</code>
34817        <hr/>
34818        <div class="slide-animate-container">
34819          <div class="slide-animate" ng-include="template.url"></div>
34820        </div>
34821      </div>
34822     </file>
34823     <file name="script.js">
34824       angular.module('includeExample', ['ngAnimate'])
34825         .controller('ExampleController', ['$scope', function($scope) {
34826           $scope.templates =
34827             [ { name: 'template1.html', url: 'template1.html'},
34828               { name: 'template2.html', url: 'template2.html'} ];
34829           $scope.template = $scope.templates[0];
34830         }]);
34831      </file>
34832     <file name="template1.html">
34833       Content of template1.html
34834     </file>
34835     <file name="template2.html">
34836       Content of template2.html
34837     </file>
34838     <file name="animations.css">
34839       .slide-animate-container {
34840         position:relative;
34841         background:white;
34842         border:1px solid black;
34843         height:40px;
34844         overflow:hidden;
34845       }
34846
34847       .slide-animate {
34848         padding:10px;
34849       }
34850
34851       .slide-animate.ng-enter, .slide-animate.ng-leave {
34852         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34853
34854         position:absolute;
34855         top:0;
34856         left:0;
34857         right:0;
34858         bottom:0;
34859         display:block;
34860         padding:10px;
34861       }
34862
34863       .slide-animate.ng-enter {
34864         top:-50px;
34865       }
34866       .slide-animate.ng-enter.ng-enter-active {
34867         top:0;
34868       }
34869
34870       .slide-animate.ng-leave {
34871         top:0;
34872       }
34873       .slide-animate.ng-leave.ng-leave-active {
34874         top:50px;
34875       }
34876     </file>
34877     <file name="protractor.js" type="protractor">
34878       var templateSelect = element(by.model('template'));
34879       var includeElem = element(by.css('[ng-include]'));
34880
34881       it('should load template1.html', function() {
34882         expect(includeElem.getText()).toMatch(/Content of template1.html/);
34883       });
34884
34885       it('should load template2.html', function() {
34886         if (browser.params.browser == 'firefox') {
34887           // Firefox can't handle using selects
34888           // See https://github.com/angular/protractor/issues/480
34889           return;
34890         }
34891         templateSelect.click();
34892         templateSelect.all(by.css('option')).get(2).click();
34893         expect(includeElem.getText()).toMatch(/Content of template2.html/);
34894       });
34895
34896       it('should change to blank', function() {
34897         if (browser.params.browser == 'firefox') {
34898           // Firefox can't handle using selects
34899           return;
34900         }
34901         templateSelect.click();
34902         templateSelect.all(by.css('option')).get(0).click();
34903         expect(includeElem.isPresent()).toBe(false);
34904       });
34905     </file>
34906   </example>
34907  */
34908
34909
34910 /**
34911  * @ngdoc event
34912  * @name ngInclude#$includeContentRequested
34913  * @eventType emit on the scope ngInclude was declared in
34914  * @description
34915  * Emitted every time the ngInclude content is requested.
34916  *
34917  * @param {Object} angularEvent Synthetic event object.
34918  * @param {String} src URL of content to load.
34919  */
34920
34921
34922 /**
34923  * @ngdoc event
34924  * @name ngInclude#$includeContentLoaded
34925  * @eventType emit on the current ngInclude scope
34926  * @description
34927  * Emitted every time the ngInclude content is reloaded.
34928  *
34929  * @param {Object} angularEvent Synthetic event object.
34930  * @param {String} src URL of content to load.
34931  */
34932
34933
34934 /**
34935  * @ngdoc event
34936  * @name ngInclude#$includeContentError
34937  * @eventType emit on the scope ngInclude was declared in
34938  * @description
34939  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
34940  *
34941  * @param {Object} angularEvent Synthetic event object.
34942  * @param {String} src URL of content to load.
34943  */
34944 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
34945                   function($templateRequest,   $anchorScroll,   $animate) {
34946   return {
34947     restrict: 'ECA',
34948     priority: 400,
34949     terminal: true,
34950     transclude: 'element',
34951     controller: angular.noop,
34952     compile: function(element, attr) {
34953       var srcExp = attr.ngInclude || attr.src,
34954           onloadExp = attr.onload || '',
34955           autoScrollExp = attr.autoscroll;
34956
34957       return function(scope, $element, $attr, ctrl, $transclude) {
34958         var changeCounter = 0,
34959             currentScope,
34960             previousElement,
34961             currentElement;
34962
34963         var cleanupLastIncludeContent = function() {
34964           if (previousElement) {
34965             previousElement.remove();
34966             previousElement = null;
34967           }
34968           if (currentScope) {
34969             currentScope.$destroy();
34970             currentScope = null;
34971           }
34972           if (currentElement) {
34973             $animate.leave(currentElement).then(function() {
34974               previousElement = null;
34975             });
34976             previousElement = currentElement;
34977             currentElement = null;
34978           }
34979         };
34980
34981         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
34982           var afterAnimation = function() {
34983             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
34984               $anchorScroll();
34985             }
34986           };
34987           var thisChangeId = ++changeCounter;
34988
34989           if (src) {
34990             //set the 2nd param to true to ignore the template request error so that the inner
34991             //contents and scope can be cleaned up.
34992             $templateRequest(src, true).then(function(response) {
34993               if (scope.$$destroyed) return;
34994
34995               if (thisChangeId !== changeCounter) return;
34996               var newScope = scope.$new();
34997               ctrl.template = response;
34998
34999               // Note: This will also link all children of ng-include that were contained in the original
35000               // html. If that content contains controllers, ... they could pollute/change the scope.
35001               // However, using ng-include on an element with additional content does not make sense...
35002               // Note: We can't remove them in the cloneAttchFn of $transclude as that
35003               // function is called before linking the content, which would apply child
35004               // directives to non existing elements.
35005               var clone = $transclude(newScope, function(clone) {
35006                 cleanupLastIncludeContent();
35007                 $animate.enter(clone, null, $element).then(afterAnimation);
35008               });
35009
35010               currentScope = newScope;
35011               currentElement = clone;
35012
35013               currentScope.$emit('$includeContentLoaded', src);
35014               scope.$eval(onloadExp);
35015             }, function() {
35016               if (scope.$$destroyed) return;
35017
35018               if (thisChangeId === changeCounter) {
35019                 cleanupLastIncludeContent();
35020                 scope.$emit('$includeContentError', src);
35021               }
35022             });
35023             scope.$emit('$includeContentRequested', src);
35024           } else {
35025             cleanupLastIncludeContent();
35026             ctrl.template = null;
35027           }
35028         });
35029       };
35030     }
35031   };
35032 }];
35033
35034 // This directive is called during the $transclude call of the first `ngInclude` directive.
35035 // It will replace and compile the content of the element with the loaded template.
35036 // We need this directive so that the element content is already filled when
35037 // the link function of another directive on the same element as ngInclude
35038 // is called.
35039 var ngIncludeFillContentDirective = ['$compile',
35040   function($compile) {
35041     return {
35042       restrict: 'ECA',
35043       priority: -400,
35044       require: 'ngInclude',
35045       link: function(scope, $element, $attr, ctrl) {
35046         if (toString.call($element[0]).match(/SVG/)) {
35047           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
35048           // support innerHTML, so detect this here and try to generate the contents
35049           // specially.
35050           $element.empty();
35051           $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
35052               function namespaceAdaptedClone(clone) {
35053             $element.append(clone);
35054           }, {futureParentElement: $element});
35055           return;
35056         }
35057
35058         $element.html(ctrl.template);
35059         $compile($element.contents())(scope);
35060       }
35061     };
35062   }];
35063
35064 /**
35065  * @ngdoc directive
35066  * @name ngInit
35067  * @restrict AC
35068  *
35069  * @description
35070  * The `ngInit` directive allows you to evaluate an expression in the
35071  * current scope.
35072  *
35073  * <div class="alert alert-danger">
35074  * This directive can be abused to add unnecessary amounts of logic into your templates.
35075  * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
35076  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
35077  * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
35078  * rather than `ngInit` to initialize values on a scope.
35079  * </div>
35080  *
35081  * <div class="alert alert-warning">
35082  * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
35083  * sure you have parentheses to ensure correct operator precedence:
35084  * <pre class="prettyprint">
35085  * `<div ng-init="test1 = ($index | toString)"></div>`
35086  * </pre>
35087  * </div>
35088  *
35089  * @priority 450
35090  *
35091  * @element ANY
35092  * @param {expression} ngInit {@link guide/expression Expression} to eval.
35093  *
35094  * @example
35095    <example module="initExample">
35096      <file name="index.html">
35097    <script>
35098      angular.module('initExample', [])
35099        .controller('ExampleController', ['$scope', function($scope) {
35100          $scope.list = [['a', 'b'], ['c', 'd']];
35101        }]);
35102    </script>
35103    <div ng-controller="ExampleController">
35104      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
35105        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
35106           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
35107        </div>
35108      </div>
35109    </div>
35110      </file>
35111      <file name="protractor.js" type="protractor">
35112        it('should alias index positions', function() {
35113          var elements = element.all(by.css('.example-init'));
35114          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
35115          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
35116          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
35117          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
35118        });
35119      </file>
35120    </example>
35121  */
35122 var ngInitDirective = ngDirective({
35123   priority: 450,
35124   compile: function() {
35125     return {
35126       pre: function(scope, element, attrs) {
35127         scope.$eval(attrs.ngInit);
35128       }
35129     };
35130   }
35131 });
35132
35133 /**
35134  * @ngdoc directive
35135  * @name ngList
35136  *
35137  * @description
35138  * Text input that converts between a delimited string and an array of strings. The default
35139  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
35140  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
35141  *
35142  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
35143  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
35144  *   list item is respected. This implies that the user of the directive is responsible for
35145  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
35146  *   tab or newline character.
35147  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
35148  *   when joining the list items back together) and whitespace around each list item is stripped
35149  *   before it is added to the model.
35150  *
35151  * ### Example with Validation
35152  *
35153  * <example name="ngList-directive" module="listExample">
35154  *   <file name="app.js">
35155  *      angular.module('listExample', [])
35156  *        .controller('ExampleController', ['$scope', function($scope) {
35157  *          $scope.names = ['morpheus', 'neo', 'trinity'];
35158  *        }]);
35159  *   </file>
35160  *   <file name="index.html">
35161  *    <form name="myForm" ng-controller="ExampleController">
35162  *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
35163  *      <span role="alert">
35164  *        <span class="error" ng-show="myForm.namesInput.$error.required">
35165  *        Required!</span>
35166  *      </span>
35167  *      <br>
35168  *      <tt>names = {{names}}</tt><br/>
35169  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
35170  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
35171  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
35172  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
35173  *     </form>
35174  *   </file>
35175  *   <file name="protractor.js" type="protractor">
35176  *     var listInput = element(by.model('names'));
35177  *     var names = element(by.exactBinding('names'));
35178  *     var valid = element(by.binding('myForm.namesInput.$valid'));
35179  *     var error = element(by.css('span.error'));
35180  *
35181  *     it('should initialize to model', function() {
35182  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
35183  *       expect(valid.getText()).toContain('true');
35184  *       expect(error.getCssValue('display')).toBe('none');
35185  *     });
35186  *
35187  *     it('should be invalid if empty', function() {
35188  *       listInput.clear();
35189  *       listInput.sendKeys('');
35190  *
35191  *       expect(names.getText()).toContain('');
35192  *       expect(valid.getText()).toContain('false');
35193  *       expect(error.getCssValue('display')).not.toBe('none');
35194  *     });
35195  *   </file>
35196  * </example>
35197  *
35198  * ### Example - splitting on newline
35199  * <example name="ngList-directive-newlines">
35200  *   <file name="index.html">
35201  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
35202  *    <pre>{{ list | json }}</pre>
35203  *   </file>
35204  *   <file name="protractor.js" type="protractor">
35205  *     it("should split the text by newlines", function() {
35206  *       var listInput = element(by.model('list'));
35207  *       var output = element(by.binding('list | json'));
35208  *       listInput.sendKeys('abc\ndef\nghi');
35209  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
35210  *     });
35211  *   </file>
35212  * </example>
35213  *
35214  * @element input
35215  * @param {string=} ngList optional delimiter that should be used to split the value.
35216  */
35217 var ngListDirective = function() {
35218   return {
35219     restrict: 'A',
35220     priority: 100,
35221     require: 'ngModel',
35222     link: function(scope, element, attr, ctrl) {
35223       // We want to control whitespace trimming so we use this convoluted approach
35224       // to access the ngList attribute, which doesn't pre-trim the attribute
35225       var ngList = element.attr(attr.$attr.ngList) || ', ';
35226       var trimValues = attr.ngTrim !== 'false';
35227       var separator = trimValues ? trim(ngList) : ngList;
35228
35229       var parse = function(viewValue) {
35230         // If the viewValue is invalid (say required but empty) it will be `undefined`
35231         if (isUndefined(viewValue)) return;
35232
35233         var list = [];
35234
35235         if (viewValue) {
35236           forEach(viewValue.split(separator), function(value) {
35237             if (value) list.push(trimValues ? trim(value) : value);
35238           });
35239         }
35240
35241         return list;
35242       };
35243
35244       ctrl.$parsers.push(parse);
35245       ctrl.$formatters.push(function(value) {
35246         if (isArray(value)) {
35247           return value.join(ngList);
35248         }
35249
35250         return undefined;
35251       });
35252
35253       // Override the standard $isEmpty because an empty array means the input is empty.
35254       ctrl.$isEmpty = function(value) {
35255         return !value || !value.length;
35256       };
35257     }
35258   };
35259 };
35260
35261 /* global VALID_CLASS: true,
35262   INVALID_CLASS: true,
35263   PRISTINE_CLASS: true,
35264   DIRTY_CLASS: true,
35265   UNTOUCHED_CLASS: true,
35266   TOUCHED_CLASS: true,
35267 */
35268
35269 var VALID_CLASS = 'ng-valid',
35270     INVALID_CLASS = 'ng-invalid',
35271     PRISTINE_CLASS = 'ng-pristine',
35272     DIRTY_CLASS = 'ng-dirty',
35273     UNTOUCHED_CLASS = 'ng-untouched',
35274     TOUCHED_CLASS = 'ng-touched',
35275     PENDING_CLASS = 'ng-pending',
35276     EMPTY_CLASS = 'ng-empty',
35277     NOT_EMPTY_CLASS = 'ng-not-empty';
35278
35279 var ngModelMinErr = minErr('ngModel');
35280
35281 /**
35282  * @ngdoc type
35283  * @name ngModel.NgModelController
35284  *
35285  * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
35286  * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
35287  * is set.
35288  * @property {*} $modelValue The value in the model that the control is bound to.
35289  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
35290        the control reads value from the DOM. The functions are called in array order, each passing
35291        its return value through to the next. The last return value is forwarded to the
35292        {@link ngModel.NgModelController#$validators `$validators`} collection.
35293
35294 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
35295 `$viewValue`}.
35296
35297 Returning `undefined` from a parser means a parse error occurred. In that case,
35298 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
35299 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
35300 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
35301
35302  *
35303  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
35304        the model value changes. The functions are called in reverse array order, each passing the value through to the
35305        next. The last return value is used as the actual DOM value.
35306        Used to format / convert values for display in the control.
35307  * ```js
35308  * function formatter(value) {
35309  *   if (value) {
35310  *     return value.toUpperCase();
35311  *   }
35312  * }
35313  * ngModel.$formatters.push(formatter);
35314  * ```
35315  *
35316  * @property {Object.<string, function>} $validators A collection of validators that are applied
35317  *      whenever the model value changes. The key value within the object refers to the name of the
35318  *      validator while the function refers to the validation operation. The validation operation is
35319  *      provided with the model value as an argument and must return a true or false value depending
35320  *      on the response of that validation.
35321  *
35322  * ```js
35323  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
35324  *   var value = modelValue || viewValue;
35325  *   return /[0-9]+/.test(value) &&
35326  *          /[a-z]+/.test(value) &&
35327  *          /[A-Z]+/.test(value) &&
35328  *          /\W+/.test(value);
35329  * };
35330  * ```
35331  *
35332  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
35333  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
35334  *      is expected to return a promise when it is run during the model validation process. Once the promise
35335  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
35336  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
35337  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
35338  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
35339  *      will only run once all synchronous validators have passed.
35340  *
35341  * Please note that if $http is used then it is important that the server returns a success HTTP response code
35342  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
35343  *
35344  * ```js
35345  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
35346  *   var value = modelValue || viewValue;
35347  *
35348  *   // Lookup user by username
35349  *   return $http.get('/api/users/' + value).
35350  *      then(function resolved() {
35351  *        //username exists, this means validation fails
35352  *        return $q.reject('exists');
35353  *      }, function rejected() {
35354  *        //username does not exist, therefore this validation passes
35355  *        return true;
35356  *      });
35357  * };
35358  * ```
35359  *
35360  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
35361  *     view value has changed. It is called with no arguments, and its return value is ignored.
35362  *     This can be used in place of additional $watches against the model value.
35363  *
35364  * @property {Object} $error An object hash with all failing validator ids as keys.
35365  * @property {Object} $pending An object hash with all pending validator ids as keys.
35366  *
35367  * @property {boolean} $untouched True if control has not lost focus yet.
35368  * @property {boolean} $touched True if control has lost focus.
35369  * @property {boolean} $pristine True if user has not interacted with the control yet.
35370  * @property {boolean} $dirty True if user has already interacted with the control.
35371  * @property {boolean} $valid True if there is no error.
35372  * @property {boolean} $invalid True if at least one error on the control.
35373  * @property {string} $name The name attribute of the control.
35374  *
35375  * @description
35376  *
35377  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
35378  * The controller contains services for data-binding, validation, CSS updates, and value formatting
35379  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
35380  * listening to DOM events.
35381  * Such DOM related logic should be provided by other directives which make use of
35382  * `NgModelController` for data-binding to control elements.
35383  * Angular provides this DOM logic for most {@link input `input`} elements.
35384  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
35385  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
35386  *
35387  * @example
35388  * ### Custom Control Example
35389  * This example shows how to use `NgModelController` with a custom control to achieve
35390  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
35391  * collaborate together to achieve the desired result.
35392  *
35393  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
35394  * contents be edited in place by the user.
35395  *
35396  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
35397  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
35398  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
35399  * that content using the `$sce` service.
35400  *
35401  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
35402     <file name="style.css">
35403       [contenteditable] {
35404         border: 1px solid black;
35405         background-color: white;
35406         min-height: 20px;
35407       }
35408
35409       .ng-invalid {
35410         border: 1px solid red;
35411       }
35412
35413     </file>
35414     <file name="script.js">
35415       angular.module('customControl', ['ngSanitize']).
35416         directive('contenteditable', ['$sce', function($sce) {
35417           return {
35418             restrict: 'A', // only activate on element attribute
35419             require: '?ngModel', // get a hold of NgModelController
35420             link: function(scope, element, attrs, ngModel) {
35421               if (!ngModel) return; // do nothing if no ng-model
35422
35423               // Specify how UI should be updated
35424               ngModel.$render = function() {
35425                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
35426               };
35427
35428               // Listen for change events to enable binding
35429               element.on('blur keyup change', function() {
35430                 scope.$evalAsync(read);
35431               });
35432               read(); // initialize
35433
35434               // Write data to the model
35435               function read() {
35436                 var html = element.html();
35437                 // When we clear the content editable the browser leaves a <br> behind
35438                 // If strip-br attribute is provided then we strip this out
35439                 if ( attrs.stripBr && html == '<br>' ) {
35440                   html = '';
35441                 }
35442                 ngModel.$setViewValue(html);
35443               }
35444             }
35445           };
35446         }]);
35447     </file>
35448     <file name="index.html">
35449       <form name="myForm">
35450        <div contenteditable
35451             name="myWidget" ng-model="userContent"
35452             strip-br="true"
35453             required>Change me!</div>
35454         <span ng-show="myForm.myWidget.$error.required">Required!</span>
35455        <hr>
35456        <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
35457       </form>
35458     </file>
35459     <file name="protractor.js" type="protractor">
35460     it('should data-bind and become invalid', function() {
35461       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
35462         // SafariDriver can't handle contenteditable
35463         // and Firefox driver can't clear contenteditables very well
35464         return;
35465       }
35466       var contentEditable = element(by.css('[contenteditable]'));
35467       var content = 'Change me!';
35468
35469       expect(contentEditable.getText()).toEqual(content);
35470
35471       contentEditable.clear();
35472       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
35473       expect(contentEditable.getText()).toEqual('');
35474       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
35475     });
35476     </file>
35477  * </example>
35478  *
35479  *
35480  */
35481 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
35482     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
35483   this.$viewValue = Number.NaN;
35484   this.$modelValue = Number.NaN;
35485   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
35486   this.$validators = {};
35487   this.$asyncValidators = {};
35488   this.$parsers = [];
35489   this.$formatters = [];
35490   this.$viewChangeListeners = [];
35491   this.$untouched = true;
35492   this.$touched = false;
35493   this.$pristine = true;
35494   this.$dirty = false;
35495   this.$valid = true;
35496   this.$invalid = false;
35497   this.$error = {}; // keep invalid keys here
35498   this.$$success = {}; // keep valid keys here
35499   this.$pending = undefined; // keep pending keys here
35500   this.$name = $interpolate($attr.name || '', false)($scope);
35501   this.$$parentForm = nullFormCtrl;
35502
35503   var parsedNgModel = $parse($attr.ngModel),
35504       parsedNgModelAssign = parsedNgModel.assign,
35505       ngModelGet = parsedNgModel,
35506       ngModelSet = parsedNgModelAssign,
35507       pendingDebounce = null,
35508       parserValid,
35509       ctrl = this;
35510
35511   this.$$setOptions = function(options) {
35512     ctrl.$options = options;
35513     if (options && options.getterSetter) {
35514       var invokeModelGetter = $parse($attr.ngModel + '()'),
35515           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
35516
35517       ngModelGet = function($scope) {
35518         var modelValue = parsedNgModel($scope);
35519         if (isFunction(modelValue)) {
35520           modelValue = invokeModelGetter($scope);
35521         }
35522         return modelValue;
35523       };
35524       ngModelSet = function($scope, newValue) {
35525         if (isFunction(parsedNgModel($scope))) {
35526           invokeModelSetter($scope, {$$$p: newValue});
35527         } else {
35528           parsedNgModelAssign($scope, newValue);
35529         }
35530       };
35531     } else if (!parsedNgModel.assign) {
35532       throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
35533           $attr.ngModel, startingTag($element));
35534     }
35535   };
35536
35537   /**
35538    * @ngdoc method
35539    * @name ngModel.NgModelController#$render
35540    *
35541    * @description
35542    * Called when the view needs to be updated. It is expected that the user of the ng-model
35543    * directive will implement this method.
35544    *
35545    * The `$render()` method is invoked in the following situations:
35546    *
35547    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
35548    *   committed value then `$render()` is called to update the input control.
35549    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
35550    *   the `$viewValue` are different from last time.
35551    *
35552    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
35553    * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
35554    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
35555    * invoked if you only change a property on the objects.
35556    */
35557   this.$render = noop;
35558
35559   /**
35560    * @ngdoc method
35561    * @name ngModel.NgModelController#$isEmpty
35562    *
35563    * @description
35564    * This is called when we need to determine if the value of an input is empty.
35565    *
35566    * For instance, the required directive does this to work out if the input has data or not.
35567    *
35568    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
35569    *
35570    * You can override this for input directives whose concept of being empty is different from the
35571    * default. The `checkboxInputType` directive does this because in its case a value of `false`
35572    * implies empty.
35573    *
35574    * @param {*} value The value of the input to check for emptiness.
35575    * @returns {boolean} True if `value` is "empty".
35576    */
35577   this.$isEmpty = function(value) {
35578     return isUndefined(value) || value === '' || value === null || value !== value;
35579   };
35580
35581   this.$$updateEmptyClasses = function(value) {
35582     if (ctrl.$isEmpty(value)) {
35583       $animate.removeClass($element, NOT_EMPTY_CLASS);
35584       $animate.addClass($element, EMPTY_CLASS);
35585     } else {
35586       $animate.removeClass($element, EMPTY_CLASS);
35587       $animate.addClass($element, NOT_EMPTY_CLASS);
35588     }
35589   };
35590
35591
35592   var currentValidationRunId = 0;
35593
35594   /**
35595    * @ngdoc method
35596    * @name ngModel.NgModelController#$setValidity
35597    *
35598    * @description
35599    * Change the validity state, and notify the form.
35600    *
35601    * This method can be called within $parsers/$formatters or a custom validation implementation.
35602    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
35603    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
35604    *
35605    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
35606    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
35607    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
35608    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
35609    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
35610    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
35611    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
35612    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
35613    *                          Skipped is used by Angular when validators do not run because of parse errors and
35614    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
35615    */
35616   addSetValidityMethod({
35617     ctrl: this,
35618     $element: $element,
35619     set: function(object, property) {
35620       object[property] = true;
35621     },
35622     unset: function(object, property) {
35623       delete object[property];
35624     },
35625     $animate: $animate
35626   });
35627
35628   /**
35629    * @ngdoc method
35630    * @name ngModel.NgModelController#$setPristine
35631    *
35632    * @description
35633    * Sets the control to its pristine state.
35634    *
35635    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
35636    * state (`ng-pristine` class). A model is considered to be pristine when the control
35637    * has not been changed from when first compiled.
35638    */
35639   this.$setPristine = function() {
35640     ctrl.$dirty = false;
35641     ctrl.$pristine = true;
35642     $animate.removeClass($element, DIRTY_CLASS);
35643     $animate.addClass($element, PRISTINE_CLASS);
35644   };
35645
35646   /**
35647    * @ngdoc method
35648    * @name ngModel.NgModelController#$setDirty
35649    *
35650    * @description
35651    * Sets the control to its dirty state.
35652    *
35653    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
35654    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
35655    * from when first compiled.
35656    */
35657   this.$setDirty = function() {
35658     ctrl.$dirty = true;
35659     ctrl.$pristine = false;
35660     $animate.removeClass($element, PRISTINE_CLASS);
35661     $animate.addClass($element, DIRTY_CLASS);
35662     ctrl.$$parentForm.$setDirty();
35663   };
35664
35665   /**
35666    * @ngdoc method
35667    * @name ngModel.NgModelController#$setUntouched
35668    *
35669    * @description
35670    * Sets the control to its untouched state.
35671    *
35672    * This method can be called to remove the `ng-touched` class and set the control to its
35673    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
35674    * by default, however this function can be used to restore that state if the model has
35675    * already been touched by the user.
35676    */
35677   this.$setUntouched = function() {
35678     ctrl.$touched = false;
35679     ctrl.$untouched = true;
35680     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
35681   };
35682
35683   /**
35684    * @ngdoc method
35685    * @name ngModel.NgModelController#$setTouched
35686    *
35687    * @description
35688    * Sets the control to its touched state.
35689    *
35690    * This method can be called to remove the `ng-untouched` class and set the control to its
35691    * touched state (`ng-touched` class). A model is considered to be touched when the user has
35692    * first focused the control element and then shifted focus away from the control (blur event).
35693    */
35694   this.$setTouched = function() {
35695     ctrl.$touched = true;
35696     ctrl.$untouched = false;
35697     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
35698   };
35699
35700   /**
35701    * @ngdoc method
35702    * @name ngModel.NgModelController#$rollbackViewValue
35703    *
35704    * @description
35705    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
35706    * which may be caused by a pending debounced event or because the input is waiting for a some
35707    * future event.
35708    *
35709    * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
35710    * depend on special events such as blur, you can have a situation where there is a period when
35711    * the `$viewValue` is out of sync with the ngModel's `$modelValue`.
35712    *
35713    * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
35714    * and reset the input to the last committed view value.
35715    *
35716    * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
35717    * programmatically before these debounced/future events have resolved/occurred, because Angular's
35718    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
35719    *
35720    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
35721    * input which may have such events pending. This is important in order to make sure that the
35722    * input field will be updated with the new model value and any pending operations are cancelled.
35723    *
35724    * <example name="ng-model-cancel-update" module="cancel-update-example">
35725    *   <file name="app.js">
35726    *     angular.module('cancel-update-example', [])
35727    *
35728    *     .controller('CancelUpdateController', ['$scope', function($scope) {
35729    *       $scope.model = {};
35730    *
35731    *       $scope.setEmpty = function(e, value, rollback) {
35732    *         if (e.keyCode == 27) {
35733    *           e.preventDefault();
35734    *           if (rollback) {
35735    *             $scope.myForm[value].$rollbackViewValue();
35736    *           }
35737    *           $scope.model[value] = '';
35738    *         }
35739    *       };
35740    *     }]);
35741    *   </file>
35742    *   <file name="index.html">
35743    *     <div ng-controller="CancelUpdateController">
35744    *        <p>Both of these inputs are only updated if they are blurred. Hitting escape should
35745    *        empty them. Follow these steps and observe the difference:</p>
35746    *       <ol>
35747    *         <li>Type something in the input. You will see that the model is not yet updated</li>
35748    *         <li>Press the Escape key.
35749    *           <ol>
35750    *             <li> In the first example, nothing happens, because the model is already '', and no
35751    *             update is detected. If you blur the input, the model will be set to the current view.
35752    *             </li>
35753    *             <li> In the second example, the pending update is cancelled, and the input is set back
35754    *             to the last committed view value (''). Blurring the input does nothing.
35755    *             </li>
35756    *           </ol>
35757    *         </li>
35758    *       </ol>
35759    *
35760    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
35761    *         <div>
35762    *        <p id="inputDescription1">Without $rollbackViewValue():</p>
35763    *         <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
35764    *                ng-keydown="setEmpty($event, 'value1')">
35765    *         value1: "{{ model.value1 }}"
35766    *         </div>
35767    *
35768    *         <div>
35769    *        <p id="inputDescription2">With $rollbackViewValue():</p>
35770    *         <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
35771    *                ng-keydown="setEmpty($event, 'value2', true)">
35772    *         value2: "{{ model.value2 }}"
35773    *         </div>
35774    *       </form>
35775    *     </div>
35776    *   </file>
35777        <file name="style.css">
35778           div {
35779             display: table-cell;
35780           }
35781           div:nth-child(1) {
35782             padding-right: 30px;
35783           }
35784
35785         </file>
35786    * </example>
35787    */
35788   this.$rollbackViewValue = function() {
35789     $timeout.cancel(pendingDebounce);
35790     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
35791     ctrl.$render();
35792   };
35793
35794   /**
35795    * @ngdoc method
35796    * @name ngModel.NgModelController#$validate
35797    *
35798    * @description
35799    * Runs each of the registered validators (first synchronous validators and then
35800    * asynchronous validators).
35801    * If the validity changes to invalid, the model will be set to `undefined`,
35802    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
35803    * If the validity changes to valid, it will set the model to the last available valid
35804    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
35805    */
35806   this.$validate = function() {
35807     // ignore $validate before model is initialized
35808     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
35809       return;
35810     }
35811
35812     var viewValue = ctrl.$$lastCommittedViewValue;
35813     // Note: we use the $$rawModelValue as $modelValue might have been
35814     // set to undefined during a view -> model update that found validation
35815     // errors. We can't parse the view here, since that could change
35816     // the model although neither viewValue nor the model on the scope changed
35817     var modelValue = ctrl.$$rawModelValue;
35818
35819     var prevValid = ctrl.$valid;
35820     var prevModelValue = ctrl.$modelValue;
35821
35822     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
35823
35824     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
35825       // If there was no change in validity, don't update the model
35826       // This prevents changing an invalid modelValue to undefined
35827       if (!allowInvalid && prevValid !== allValid) {
35828         // Note: Don't check ctrl.$valid here, as we could have
35829         // external validators (e.g. calculated on the server),
35830         // that just call $setValidity and need the model value
35831         // to calculate their validity.
35832         ctrl.$modelValue = allValid ? modelValue : undefined;
35833
35834         if (ctrl.$modelValue !== prevModelValue) {
35835           ctrl.$$writeModelToScope();
35836         }
35837       }
35838     });
35839
35840   };
35841
35842   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
35843     currentValidationRunId++;
35844     var localValidationRunId = currentValidationRunId;
35845
35846     // check parser error
35847     if (!processParseErrors()) {
35848       validationDone(false);
35849       return;
35850     }
35851     if (!processSyncValidators()) {
35852       validationDone(false);
35853       return;
35854     }
35855     processAsyncValidators();
35856
35857     function processParseErrors() {
35858       var errorKey = ctrl.$$parserName || 'parse';
35859       if (isUndefined(parserValid)) {
35860         setValidity(errorKey, null);
35861       } else {
35862         if (!parserValid) {
35863           forEach(ctrl.$validators, function(v, name) {
35864             setValidity(name, null);
35865           });
35866           forEach(ctrl.$asyncValidators, function(v, name) {
35867             setValidity(name, null);
35868           });
35869         }
35870         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
35871         setValidity(errorKey, parserValid);
35872         return parserValid;
35873       }
35874       return true;
35875     }
35876
35877     function processSyncValidators() {
35878       var syncValidatorsValid = true;
35879       forEach(ctrl.$validators, function(validator, name) {
35880         var result = validator(modelValue, viewValue);
35881         syncValidatorsValid = syncValidatorsValid && result;
35882         setValidity(name, result);
35883       });
35884       if (!syncValidatorsValid) {
35885         forEach(ctrl.$asyncValidators, function(v, name) {
35886           setValidity(name, null);
35887         });
35888         return false;
35889       }
35890       return true;
35891     }
35892
35893     function processAsyncValidators() {
35894       var validatorPromises = [];
35895       var allValid = true;
35896       forEach(ctrl.$asyncValidators, function(validator, name) {
35897         var promise = validator(modelValue, viewValue);
35898         if (!isPromiseLike(promise)) {
35899           throw ngModelMinErr('nopromise',
35900             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
35901         }
35902         setValidity(name, undefined);
35903         validatorPromises.push(promise.then(function() {
35904           setValidity(name, true);
35905         }, function() {
35906           allValid = false;
35907           setValidity(name, false);
35908         }));
35909       });
35910       if (!validatorPromises.length) {
35911         validationDone(true);
35912       } else {
35913         $q.all(validatorPromises).then(function() {
35914           validationDone(allValid);
35915         }, noop);
35916       }
35917     }
35918
35919     function setValidity(name, isValid) {
35920       if (localValidationRunId === currentValidationRunId) {
35921         ctrl.$setValidity(name, isValid);
35922       }
35923     }
35924
35925     function validationDone(allValid) {
35926       if (localValidationRunId === currentValidationRunId) {
35927
35928         doneCallback(allValid);
35929       }
35930     }
35931   };
35932
35933   /**
35934    * @ngdoc method
35935    * @name ngModel.NgModelController#$commitViewValue
35936    *
35937    * @description
35938    * Commit a pending update to the `$modelValue`.
35939    *
35940    * Updates may be pending by a debounced event or because the input is waiting for a some future
35941    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
35942    * usually handles calling this in response to input events.
35943    */
35944   this.$commitViewValue = function() {
35945     var viewValue = ctrl.$viewValue;
35946
35947     $timeout.cancel(pendingDebounce);
35948
35949     // If the view value has not changed then we should just exit, except in the case where there is
35950     // a native validator on the element. In this case the validation state may have changed even though
35951     // the viewValue has stayed empty.
35952     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
35953       return;
35954     }
35955     ctrl.$$updateEmptyClasses(viewValue);
35956     ctrl.$$lastCommittedViewValue = viewValue;
35957
35958     // change to dirty
35959     if (ctrl.$pristine) {
35960       this.$setDirty();
35961     }
35962     this.$$parseAndValidate();
35963   };
35964
35965   this.$$parseAndValidate = function() {
35966     var viewValue = ctrl.$$lastCommittedViewValue;
35967     var modelValue = viewValue;
35968     parserValid = isUndefined(modelValue) ? undefined : true;
35969
35970     if (parserValid) {
35971       for (var i = 0; i < ctrl.$parsers.length; i++) {
35972         modelValue = ctrl.$parsers[i](modelValue);
35973         if (isUndefined(modelValue)) {
35974           parserValid = false;
35975           break;
35976         }
35977       }
35978     }
35979     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
35980       // ctrl.$modelValue has not been touched yet...
35981       ctrl.$modelValue = ngModelGet($scope);
35982     }
35983     var prevModelValue = ctrl.$modelValue;
35984     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
35985     ctrl.$$rawModelValue = modelValue;
35986
35987     if (allowInvalid) {
35988       ctrl.$modelValue = modelValue;
35989       writeToModelIfNeeded();
35990     }
35991
35992     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
35993     // This can happen if e.g. $setViewValue is called from inside a parser
35994     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
35995       if (!allowInvalid) {
35996         // Note: Don't check ctrl.$valid here, as we could have
35997         // external validators (e.g. calculated on the server),
35998         // that just call $setValidity and need the model value
35999         // to calculate their validity.
36000         ctrl.$modelValue = allValid ? modelValue : undefined;
36001         writeToModelIfNeeded();
36002       }
36003     });
36004
36005     function writeToModelIfNeeded() {
36006       if (ctrl.$modelValue !== prevModelValue) {
36007         ctrl.$$writeModelToScope();
36008       }
36009     }
36010   };
36011
36012   this.$$writeModelToScope = function() {
36013     ngModelSet($scope, ctrl.$modelValue);
36014     forEach(ctrl.$viewChangeListeners, function(listener) {
36015       try {
36016         listener();
36017       } catch (e) {
36018         $exceptionHandler(e);
36019       }
36020     });
36021   };
36022
36023   /**
36024    * @ngdoc method
36025    * @name ngModel.NgModelController#$setViewValue
36026    *
36027    * @description
36028    * Update the view value.
36029    *
36030    * This method should be called when a control wants to change the view value; typically,
36031    * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
36032    * directive calls it when the value of the input changes and {@link ng.directive:select select}
36033    * calls it when an option is selected.
36034    *
36035    * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
36036    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
36037    * value sent directly for processing, finally to be applied to `$modelValue` and then the
36038    * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
36039    * in the `$viewChangeListeners` list, are called.
36040    *
36041    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
36042    * and the `default` trigger is not listed, all those actions will remain pending until one of the
36043    * `updateOn` events is triggered on the DOM element.
36044    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
36045    * directive is used with a custom debounce for this particular event.
36046    * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
36047    * is specified, once the timer runs out.
36048    *
36049    * When used with standard inputs, the view value will always be a string (which is in some cases
36050    * parsed into another type, such as a `Date` object for `input[date]`.)
36051    * However, custom controls might also pass objects to this method. In this case, we should make
36052    * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
36053    * perform a deep watch of objects, it only looks for a change of identity. If you only change
36054    * the property of the object then ngModel will not realize that the object has changed and
36055    * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
36056    * not change properties of the copy once it has been passed to `$setViewValue`.
36057    * Otherwise you may cause the model value on the scope to change incorrectly.
36058    *
36059    * <div class="alert alert-info">
36060    * In any case, the value passed to the method should always reflect the current value
36061    * of the control. For example, if you are calling `$setViewValue` for an input element,
36062    * you should pass the input DOM value. Otherwise, the control and the scope model become
36063    * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
36064    * the control's DOM value in any way. If we want to change the control's DOM value
36065    * programmatically, we should update the `ngModel` scope expression. Its new value will be
36066    * picked up by the model controller, which will run it through the `$formatters`, `$render` it
36067    * to update the DOM, and finally call `$validate` on it.
36068    * </div>
36069    *
36070    * @param {*} value value from the view.
36071    * @param {string} trigger Event that triggered the update.
36072    */
36073   this.$setViewValue = function(value, trigger) {
36074     ctrl.$viewValue = value;
36075     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
36076       ctrl.$$debounceViewValueCommit(trigger);
36077     }
36078   };
36079
36080   this.$$debounceViewValueCommit = function(trigger) {
36081     var debounceDelay = 0,
36082         options = ctrl.$options,
36083         debounce;
36084
36085     if (options && isDefined(options.debounce)) {
36086       debounce = options.debounce;
36087       if (isNumber(debounce)) {
36088         debounceDelay = debounce;
36089       } else if (isNumber(debounce[trigger])) {
36090         debounceDelay = debounce[trigger];
36091       } else if (isNumber(debounce['default'])) {
36092         debounceDelay = debounce['default'];
36093       }
36094     }
36095
36096     $timeout.cancel(pendingDebounce);
36097     if (debounceDelay) {
36098       pendingDebounce = $timeout(function() {
36099         ctrl.$commitViewValue();
36100       }, debounceDelay);
36101     } else if ($rootScope.$$phase) {
36102       ctrl.$commitViewValue();
36103     } else {
36104       $scope.$apply(function() {
36105         ctrl.$commitViewValue();
36106       });
36107     }
36108   };
36109
36110   // model -> value
36111   // Note: we cannot use a normal scope.$watch as we want to detect the following:
36112   // 1. scope value is 'a'
36113   // 2. user enters 'b'
36114   // 3. ng-change kicks in and reverts scope value to 'a'
36115   //    -> scope value did not change since the last digest as
36116   //       ng-change executes in apply phase
36117   // 4. view should be changed back to 'a'
36118   $scope.$watch(function ngModelWatch() {
36119     var modelValue = ngModelGet($scope);
36120
36121     // if scope model value and ngModel value are out of sync
36122     // TODO(perf): why not move this to the action fn?
36123     if (modelValue !== ctrl.$modelValue &&
36124        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
36125        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
36126     ) {
36127       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
36128       parserValid = undefined;
36129
36130       var formatters = ctrl.$formatters,
36131           idx = formatters.length;
36132
36133       var viewValue = modelValue;
36134       while (idx--) {
36135         viewValue = formatters[idx](viewValue);
36136       }
36137       if (ctrl.$viewValue !== viewValue) {
36138         ctrl.$$updateEmptyClasses(viewValue);
36139         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
36140         ctrl.$render();
36141
36142         ctrl.$$runValidators(modelValue, viewValue, noop);
36143       }
36144     }
36145
36146     return modelValue;
36147   });
36148 }];
36149
36150
36151 /**
36152  * @ngdoc directive
36153  * @name ngModel
36154  *
36155  * @element input
36156  * @priority 1
36157  *
36158  * @description
36159  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
36160  * property on the scope using {@link ngModel.NgModelController NgModelController},
36161  * which is created and exposed by this directive.
36162  *
36163  * `ngModel` is responsible for:
36164  *
36165  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
36166  *   require.
36167  * - Providing validation behavior (i.e. required, number, email, url).
36168  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
36169  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
36170  *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
36171  * - Registering the control with its parent {@link ng.directive:form form}.
36172  *
36173  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
36174  * current scope. If the property doesn't already exist on this scope, it will be created
36175  * implicitly and added to the scope.
36176  *
36177  * For best practices on using `ngModel`, see:
36178  *
36179  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
36180  *
36181  * For basic examples, how to use `ngModel`, see:
36182  *
36183  *  - {@link ng.directive:input input}
36184  *    - {@link input[text] text}
36185  *    - {@link input[checkbox] checkbox}
36186  *    - {@link input[radio] radio}
36187  *    - {@link input[number] number}
36188  *    - {@link input[email] email}
36189  *    - {@link input[url] url}
36190  *    - {@link input[date] date}
36191  *    - {@link input[datetime-local] datetime-local}
36192  *    - {@link input[time] time}
36193  *    - {@link input[month] month}
36194  *    - {@link input[week] week}
36195  *  - {@link ng.directive:select select}
36196  *  - {@link ng.directive:textarea textarea}
36197  *
36198  * # Complex Models (objects or collections)
36199  *
36200  * By default, `ngModel` watches the model by reference, not value. This is important to know when
36201  * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
36202  * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
36203  *
36204  * The model must be assigned an entirely new object or collection before a re-rendering will occur.
36205  *
36206  * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
36207  * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
36208  * if the select is given the `multiple` attribute.
36209  *
36210  * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
36211  * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
36212  * not trigger a re-rendering of the model.
36213  *
36214  * # CSS classes
36215  * The following CSS classes are added and removed on the associated input/select/textarea element
36216  * depending on the validity of the model.
36217  *
36218  *  - `ng-valid`: the model is valid
36219  *  - `ng-invalid`: the model is invalid
36220  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
36221  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
36222  *  - `ng-pristine`: the control hasn't been interacted with yet
36223  *  - `ng-dirty`: the control has been interacted with
36224  *  - `ng-touched`: the control has been blurred
36225  *  - `ng-untouched`: the control hasn't been blurred
36226  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
36227  *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
36228  *     by the {@link ngModel.NgModelController#$isEmpty} method
36229  *  - `ng-not-empty`: the view contains a non-empty value
36230  *
36231  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
36232  *
36233  * ## Animation Hooks
36234  *
36235  * Animations within models are triggered when any of the associated CSS classes are added and removed
36236  * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
36237  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
36238  * The animations that are triggered within ngModel are similar to how they work in ngClass and
36239  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
36240  *
36241  * The following example shows a simple way to utilize CSS transitions to style an input element
36242  * that has been rendered as invalid after it has been validated:
36243  *
36244  * <pre>
36245  * //be sure to include ngAnimate as a module to hook into more
36246  * //advanced animations
36247  * .my-input {
36248  *   transition:0.5s linear all;
36249  *   background: white;
36250  * }
36251  * .my-input.ng-invalid {
36252  *   background: red;
36253  *   color:white;
36254  * }
36255  * </pre>
36256  *
36257  * @example
36258  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
36259      <file name="index.html">
36260        <script>
36261         angular.module('inputExample', [])
36262           .controller('ExampleController', ['$scope', function($scope) {
36263             $scope.val = '1';
36264           }]);
36265        </script>
36266        <style>
36267          .my-input {
36268            transition:all linear 0.5s;
36269            background: transparent;
36270          }
36271          .my-input.ng-invalid {
36272            color:white;
36273            background: red;
36274          }
36275        </style>
36276        <p id="inputDescription">
36277         Update input to see transitions when valid/invalid.
36278         Integer is a valid value.
36279        </p>
36280        <form name="testForm" ng-controller="ExampleController">
36281          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
36282                 aria-describedby="inputDescription" />
36283        </form>
36284      </file>
36285  * </example>
36286  *
36287  * ## Binding to a getter/setter
36288  *
36289  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
36290  * function that returns a representation of the model when called with zero arguments, and sets
36291  * the internal state of a model when called with an argument. It's sometimes useful to use this
36292  * for models that have an internal representation that's different from what the model exposes
36293  * to the view.
36294  *
36295  * <div class="alert alert-success">
36296  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
36297  * frequently than other parts of your code.
36298  * </div>
36299  *
36300  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
36301  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
36302  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
36303  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
36304  *
36305  * The following example shows how to use `ngModel` with a getter/setter:
36306  *
36307  * @example
36308  * <example name="ngModel-getter-setter" module="getterSetterExample">
36309      <file name="index.html">
36310        <div ng-controller="ExampleController">
36311          <form name="userForm">
36312            <label>Name:
36313              <input type="text" name="userName"
36314                     ng-model="user.name"
36315                     ng-model-options="{ getterSetter: true }" />
36316            </label>
36317          </form>
36318          <pre>user.name = <span ng-bind="user.name()"></span></pre>
36319        </div>
36320      </file>
36321      <file name="app.js">
36322        angular.module('getterSetterExample', [])
36323          .controller('ExampleController', ['$scope', function($scope) {
36324            var _name = 'Brian';
36325            $scope.user = {
36326              name: function(newName) {
36327               // Note that newName can be undefined for two reasons:
36328               // 1. Because it is called as a getter and thus called with no arguments
36329               // 2. Because the property should actually be set to undefined. This happens e.g. if the
36330               //    input is invalid
36331               return arguments.length ? (_name = newName) : _name;
36332              }
36333            };
36334          }]);
36335      </file>
36336  * </example>
36337  */
36338 var ngModelDirective = ['$rootScope', function($rootScope) {
36339   return {
36340     restrict: 'A',
36341     require: ['ngModel', '^?form', '^?ngModelOptions'],
36342     controller: NgModelController,
36343     // Prelink needs to run before any input directive
36344     // so that we can set the NgModelOptions in NgModelController
36345     // before anyone else uses it.
36346     priority: 1,
36347     compile: function ngModelCompile(element) {
36348       // Setup initial state of the control
36349       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
36350
36351       return {
36352         pre: function ngModelPreLink(scope, element, attr, ctrls) {
36353           var modelCtrl = ctrls[0],
36354               formCtrl = ctrls[1] || modelCtrl.$$parentForm;
36355
36356           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
36357
36358           // notify others, especially parent forms
36359           formCtrl.$addControl(modelCtrl);
36360
36361           attr.$observe('name', function(newValue) {
36362             if (modelCtrl.$name !== newValue) {
36363               modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
36364             }
36365           });
36366
36367           scope.$on('$destroy', function() {
36368             modelCtrl.$$parentForm.$removeControl(modelCtrl);
36369           });
36370         },
36371         post: function ngModelPostLink(scope, element, attr, ctrls) {
36372           var modelCtrl = ctrls[0];
36373           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
36374             element.on(modelCtrl.$options.updateOn, function(ev) {
36375               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
36376             });
36377           }
36378
36379           element.on('blur', function() {
36380             if (modelCtrl.$touched) return;
36381
36382             if ($rootScope.$$phase) {
36383               scope.$evalAsync(modelCtrl.$setTouched);
36384             } else {
36385               scope.$apply(modelCtrl.$setTouched);
36386             }
36387           });
36388         }
36389       };
36390     }
36391   };
36392 }];
36393
36394 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
36395
36396 /**
36397  * @ngdoc directive
36398  * @name ngModelOptions
36399  *
36400  * @description
36401  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
36402  * events that will trigger a model update and/or a debouncing delay so that the actual update only
36403  * takes place when a timer expires; this timer will be reset after another change takes place.
36404  *
36405  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
36406  * be different from the value in the actual model. This means that if you update the model you
36407  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
36408  * order to make sure it is synchronized with the model and that any debounced action is canceled.
36409  *
36410  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
36411  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
36412  * important because `form` controllers are published to the related scope under the name in their
36413  * `name` attribute.
36414  *
36415  * Any pending changes will take place immediately when an enclosing form is submitted via the
36416  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
36417  * to have access to the updated model.
36418  *
36419  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
36420  *
36421  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
36422  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
36423  *     events using an space delimited list. There is a special event called `default` that
36424  *     matches the default events belonging of the control.
36425  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
36426  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
36427  *     custom value for each event. For example:
36428  *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
36429  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
36430  *     not validate correctly instead of the default behavior of setting the model to undefined.
36431  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
36432        `ngModel` as getters/setters.
36433  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
36434  *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
36435  *     continental US time zone abbreviations, but for general use, use a time zone offset, for
36436  *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
36437  *     If not specified, the timezone of the browser will be used.
36438  *
36439  * @example
36440
36441   The following example shows how to override immediate updates. Changes on the inputs within the
36442   form will update the model only when the control loses focus (blur event). If `escape` key is
36443   pressed while the input field is focused, the value is reset to the value in the current model.
36444
36445   <example name="ngModelOptions-directive-blur" module="optionsExample">
36446     <file name="index.html">
36447       <div ng-controller="ExampleController">
36448         <form name="userForm">
36449           <label>Name:
36450             <input type="text" name="userName"
36451                    ng-model="user.name"
36452                    ng-model-options="{ updateOn: 'blur' }"
36453                    ng-keyup="cancel($event)" />
36454           </label><br />
36455           <label>Other data:
36456             <input type="text" ng-model="user.data" />
36457           </label><br />
36458         </form>
36459         <pre>user.name = <span ng-bind="user.name"></span></pre>
36460         <pre>user.data = <span ng-bind="user.data"></span></pre>
36461       </div>
36462     </file>
36463     <file name="app.js">
36464       angular.module('optionsExample', [])
36465         .controller('ExampleController', ['$scope', function($scope) {
36466           $scope.user = { name: 'John', data: '' };
36467
36468           $scope.cancel = function(e) {
36469             if (e.keyCode == 27) {
36470               $scope.userForm.userName.$rollbackViewValue();
36471             }
36472           };
36473         }]);
36474     </file>
36475     <file name="protractor.js" type="protractor">
36476       var model = element(by.binding('user.name'));
36477       var input = element(by.model('user.name'));
36478       var other = element(by.model('user.data'));
36479
36480       it('should allow custom events', function() {
36481         input.sendKeys(' Doe');
36482         input.click();
36483         expect(model.getText()).toEqual('John');
36484         other.click();
36485         expect(model.getText()).toEqual('John Doe');
36486       });
36487
36488       it('should $rollbackViewValue when model changes', function() {
36489         input.sendKeys(' Doe');
36490         expect(input.getAttribute('value')).toEqual('John Doe');
36491         input.sendKeys(protractor.Key.ESCAPE);
36492         expect(input.getAttribute('value')).toEqual('John');
36493         other.click();
36494         expect(model.getText()).toEqual('John');
36495       });
36496     </file>
36497   </example>
36498
36499   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
36500   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
36501
36502   <example name="ngModelOptions-directive-debounce" module="optionsExample">
36503     <file name="index.html">
36504       <div ng-controller="ExampleController">
36505         <form name="userForm">
36506           <label>Name:
36507             <input type="text" name="userName"
36508                    ng-model="user.name"
36509                    ng-model-options="{ debounce: 1000 }" />
36510           </label>
36511           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
36512           <br />
36513         </form>
36514         <pre>user.name = <span ng-bind="user.name"></span></pre>
36515       </div>
36516     </file>
36517     <file name="app.js">
36518       angular.module('optionsExample', [])
36519         .controller('ExampleController', ['$scope', function($scope) {
36520           $scope.user = { name: 'Igor' };
36521         }]);
36522     </file>
36523   </example>
36524
36525   This one shows how to bind to getter/setters:
36526
36527   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
36528     <file name="index.html">
36529       <div ng-controller="ExampleController">
36530         <form name="userForm">
36531           <label>Name:
36532             <input type="text" name="userName"
36533                    ng-model="user.name"
36534                    ng-model-options="{ getterSetter: true }" />
36535           </label>
36536         </form>
36537         <pre>user.name = <span ng-bind="user.name()"></span></pre>
36538       </div>
36539     </file>
36540     <file name="app.js">
36541       angular.module('getterSetterExample', [])
36542         .controller('ExampleController', ['$scope', function($scope) {
36543           var _name = 'Brian';
36544           $scope.user = {
36545             name: function(newName) {
36546               // Note that newName can be undefined for two reasons:
36547               // 1. Because it is called as a getter and thus called with no arguments
36548               // 2. Because the property should actually be set to undefined. This happens e.g. if the
36549               //    input is invalid
36550               return arguments.length ? (_name = newName) : _name;
36551             }
36552           };
36553         }]);
36554     </file>
36555   </example>
36556  */
36557 var ngModelOptionsDirective = function() {
36558   return {
36559     restrict: 'A',
36560     controller: ['$scope', '$attrs', function($scope, $attrs) {
36561       var that = this;
36562       this.$options = copy($scope.$eval($attrs.ngModelOptions));
36563       // Allow adding/overriding bound events
36564       if (isDefined(this.$options.updateOn)) {
36565         this.$options.updateOnDefault = false;
36566         // extract "default" pseudo-event from list of events that can trigger a model update
36567         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
36568           that.$options.updateOnDefault = true;
36569           return ' ';
36570         }));
36571       } else {
36572         this.$options.updateOnDefault = true;
36573       }
36574     }]
36575   };
36576 };
36577
36578
36579
36580 // helper methods
36581 function addSetValidityMethod(context) {
36582   var ctrl = context.ctrl,
36583       $element = context.$element,
36584       classCache = {},
36585       set = context.set,
36586       unset = context.unset,
36587       $animate = context.$animate;
36588
36589   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
36590
36591   ctrl.$setValidity = setValidity;
36592
36593   function setValidity(validationErrorKey, state, controller) {
36594     if (isUndefined(state)) {
36595       createAndSet('$pending', validationErrorKey, controller);
36596     } else {
36597       unsetAndCleanup('$pending', validationErrorKey, controller);
36598     }
36599     if (!isBoolean(state)) {
36600       unset(ctrl.$error, validationErrorKey, controller);
36601       unset(ctrl.$$success, validationErrorKey, controller);
36602     } else {
36603       if (state) {
36604         unset(ctrl.$error, validationErrorKey, controller);
36605         set(ctrl.$$success, validationErrorKey, controller);
36606       } else {
36607         set(ctrl.$error, validationErrorKey, controller);
36608         unset(ctrl.$$success, validationErrorKey, controller);
36609       }
36610     }
36611     if (ctrl.$pending) {
36612       cachedToggleClass(PENDING_CLASS, true);
36613       ctrl.$valid = ctrl.$invalid = undefined;
36614       toggleValidationCss('', null);
36615     } else {
36616       cachedToggleClass(PENDING_CLASS, false);
36617       ctrl.$valid = isObjectEmpty(ctrl.$error);
36618       ctrl.$invalid = !ctrl.$valid;
36619       toggleValidationCss('', ctrl.$valid);
36620     }
36621
36622     // re-read the state as the set/unset methods could have
36623     // combined state in ctrl.$error[validationError] (used for forms),
36624     // where setting/unsetting only increments/decrements the value,
36625     // and does not replace it.
36626     var combinedState;
36627     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
36628       combinedState = undefined;
36629     } else if (ctrl.$error[validationErrorKey]) {
36630       combinedState = false;
36631     } else if (ctrl.$$success[validationErrorKey]) {
36632       combinedState = true;
36633     } else {
36634       combinedState = null;
36635     }
36636
36637     toggleValidationCss(validationErrorKey, combinedState);
36638     ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
36639   }
36640
36641   function createAndSet(name, value, controller) {
36642     if (!ctrl[name]) {
36643       ctrl[name] = {};
36644     }
36645     set(ctrl[name], value, controller);
36646   }
36647
36648   function unsetAndCleanup(name, value, controller) {
36649     if (ctrl[name]) {
36650       unset(ctrl[name], value, controller);
36651     }
36652     if (isObjectEmpty(ctrl[name])) {
36653       ctrl[name] = undefined;
36654     }
36655   }
36656
36657   function cachedToggleClass(className, switchValue) {
36658     if (switchValue && !classCache[className]) {
36659       $animate.addClass($element, className);
36660       classCache[className] = true;
36661     } else if (!switchValue && classCache[className]) {
36662       $animate.removeClass($element, className);
36663       classCache[className] = false;
36664     }
36665   }
36666
36667   function toggleValidationCss(validationErrorKey, isValid) {
36668     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
36669
36670     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
36671     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
36672   }
36673 }
36674
36675 function isObjectEmpty(obj) {
36676   if (obj) {
36677     for (var prop in obj) {
36678       if (obj.hasOwnProperty(prop)) {
36679         return false;
36680       }
36681     }
36682   }
36683   return true;
36684 }
36685
36686 /**
36687  * @ngdoc directive
36688  * @name ngNonBindable
36689  * @restrict AC
36690  * @priority 1000
36691  *
36692  * @description
36693  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
36694  * DOM element. This is useful if the element contains what appears to be Angular directives and
36695  * bindings but which should be ignored by Angular. This could be the case if you have a site that
36696  * displays snippets of code, for instance.
36697  *
36698  * @element ANY
36699  *
36700  * @example
36701  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
36702  * but the one wrapped in `ngNonBindable` is left alone.
36703  *
36704  * @example
36705     <example>
36706       <file name="index.html">
36707         <div>Normal: {{1 + 2}}</div>
36708         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
36709       </file>
36710       <file name="protractor.js" type="protractor">
36711        it('should check ng-non-bindable', function() {
36712          expect(element(by.binding('1 + 2')).getText()).toContain('3');
36713          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
36714        });
36715       </file>
36716     </example>
36717  */
36718 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
36719
36720 /* global jqLiteRemove */
36721
36722 var ngOptionsMinErr = minErr('ngOptions');
36723
36724 /**
36725  * @ngdoc directive
36726  * @name ngOptions
36727  * @restrict A
36728  *
36729  * @description
36730  *
36731  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
36732  * elements for the `<select>` element using the array or object obtained by evaluating the
36733  * `ngOptions` comprehension expression.
36734  *
36735  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
36736  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
36737  * increasing speed by not creating a new scope for each repeated instance, as well as providing
36738  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
36739  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
36740  *  to a non-string value. This is because an option element can only be bound to string values at
36741  * present.
36742  *
36743  * When an item in the `<select>` menu is selected, the array element or object property
36744  * represented by the selected option will be bound to the model identified by the `ngModel`
36745  * directive.
36746  *
36747  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
36748  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
36749  * option. See example below for demonstration.
36750  *
36751  * ## Complex Models (objects or collections)
36752  *
36753  * By default, `ngModel` watches the model by reference, not value. This is important to know when
36754  * binding the select to a model that is an object or a collection.
36755  *
36756  * One issue occurs if you want to preselect an option. For example, if you set
36757  * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
36758  * because the objects are not identical. So by default, you should always reference the item in your collection
36759  * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
36760  *
36761  * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
36762  * of the item not by reference, but by the result of the `track by` expression. For example, if your
36763  * collection items have an id property, you would `track by item.id`.
36764  *
36765  * A different issue with objects or collections is that ngModel won't detect if an object property or
36766  * a collection item changes. For that reason, `ngOptions` additionally watches the model using
36767  * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
36768  * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
36769  * has not changed identity, but only a property on the object or an item in the collection changes.
36770  *
36771  * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
36772  * if the model is an array). This means that changing a property deeper than the first level inside the
36773  * object/collection will not trigger a re-rendering.
36774  *
36775  * ## `select` **`as`**
36776  *
36777  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
36778  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
36779  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
36780  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
36781  *
36782  *
36783  * ### `select` **`as`** and **`track by`**
36784  *
36785  * <div class="alert alert-warning">
36786  * Be careful when using `select` **`as`** and **`track by`** in the same expression.
36787  * </div>
36788  *
36789  * Given this array of items on the $scope:
36790  *
36791  * ```js
36792  * $scope.items = [{
36793  *   id: 1,
36794  *   label: 'aLabel',
36795  *   subItem: { name: 'aSubItem' }
36796  * }, {
36797  *   id: 2,
36798  *   label: 'bLabel',
36799  *   subItem: { name: 'bSubItem' }
36800  * }];
36801  * ```
36802  *
36803  * This will work:
36804  *
36805  * ```html
36806  * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
36807  * ```
36808  * ```js
36809  * $scope.selected = $scope.items[0];
36810  * ```
36811  *
36812  * but this will not work:
36813  *
36814  * ```html
36815  * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
36816  * ```
36817  * ```js
36818  * $scope.selected = $scope.items[0].subItem;
36819  * ```
36820  *
36821  * In both examples, the **`track by`** expression is applied successfully to each `item` in the
36822  * `items` array. Because the selected option has been set programmatically in the controller, the
36823  * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
36824  * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
36825  * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
36826  * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
36827  * is not matched against any `<option>` and the `<select>` appears as having no selected value.
36828  *
36829  *
36830  * @param {string} ngModel Assignable angular expression to data-bind to.
36831  * @param {string=} name Property name of the form under which the control is published.
36832  * @param {string=} required The control is considered valid only if value is entered.
36833  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
36834  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
36835  *    `required` when you want to data-bind to the `required` attribute.
36836  * @param {comprehension_expression=} ngOptions in one of the following forms:
36837  *
36838  *   * for array data sources:
36839  *     * `label` **`for`** `value` **`in`** `array`
36840  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
36841  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
36842  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
36843  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
36844  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
36845  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
36846  *        (for including a filter with `track by`)
36847  *   * for object data sources:
36848  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
36849  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
36850  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
36851  *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
36852  *     * `select` **`as`** `label` **`group by`** `group`
36853  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
36854  *     * `select` **`as`** `label` **`disable when`** `disable`
36855  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
36856  *
36857  * Where:
36858  *
36859  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
36860  *   * `value`: local variable which will refer to each item in the `array` or each property value
36861  *      of `object` during iteration.
36862  *   * `key`: local variable which will refer to a property name in `object` during iteration.
36863  *   * `label`: The result of this expression will be the label for `<option>` element. The
36864  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
36865  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
36866  *      element. If not specified, `select` expression will default to `value`.
36867  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
36868  *      DOM element.
36869  *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
36870  *      element. Return `true` to disable.
36871  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
36872  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
36873  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
36874  *      even when the options are recreated (e.g. reloaded from the server).
36875  *
36876  * @example
36877     <example module="selectExample">
36878       <file name="index.html">
36879         <script>
36880         angular.module('selectExample', [])
36881           .controller('ExampleController', ['$scope', function($scope) {
36882             $scope.colors = [
36883               {name:'black', shade:'dark'},
36884               {name:'white', shade:'light', notAnOption: true},
36885               {name:'red', shade:'dark'},
36886               {name:'blue', shade:'dark', notAnOption: true},
36887               {name:'yellow', shade:'light', notAnOption: false}
36888             ];
36889             $scope.myColor = $scope.colors[2]; // red
36890           }]);
36891         </script>
36892         <div ng-controller="ExampleController">
36893           <ul>
36894             <li ng-repeat="color in colors">
36895               <label>Name: <input ng-model="color.name"></label>
36896               <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
36897               <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
36898             </li>
36899             <li>
36900               <button ng-click="colors.push({})">add</button>
36901             </li>
36902           </ul>
36903           <hr/>
36904           <label>Color (null not allowed):
36905             <select ng-model="myColor" ng-options="color.name for color in colors"></select>
36906           </label><br/>
36907           <label>Color (null allowed):
36908           <span  class="nullable">
36909             <select ng-model="myColor" ng-options="color.name for color in colors">
36910               <option value="">-- choose color --</option>
36911             </select>
36912           </span></label><br/>
36913
36914           <label>Color grouped by shade:
36915             <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
36916             </select>
36917           </label><br/>
36918
36919           <label>Color grouped by shade, with some disabled:
36920             <select ng-model="myColor"
36921                   ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
36922             </select>
36923           </label><br/>
36924
36925
36926
36927           Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
36928           <br/>
36929           <hr/>
36930           Currently selected: {{ {selected_color:myColor} }}
36931           <div style="border:solid 1px black; height:20px"
36932                ng-style="{'background-color':myColor.name}">
36933           </div>
36934         </div>
36935       </file>
36936       <file name="protractor.js" type="protractor">
36937          it('should check ng-options', function() {
36938            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
36939            element.all(by.model('myColor')).first().click();
36940            element.all(by.css('select[ng-model="myColor"] option')).first().click();
36941            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
36942            element(by.css('.nullable select[ng-model="myColor"]')).click();
36943            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
36944            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
36945          });
36946       </file>
36947     </example>
36948  */
36949
36950 // jshint maxlen: false
36951 //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
36952 var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
36953                         // 1: value expression (valueFn)
36954                         // 2: label expression (displayFn)
36955                         // 3: group by expression (groupByFn)
36956                         // 4: disable when expression (disableWhenFn)
36957                         // 5: array item variable name
36958                         // 6: object item key variable name
36959                         // 7: object item value variable name
36960                         // 8: collection expression
36961                         // 9: track by expression
36962 // jshint maxlen: 100
36963
36964
36965 var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
36966
36967   function parseOptionsExpression(optionsExp, selectElement, scope) {
36968
36969     var match = optionsExp.match(NG_OPTIONS_REGEXP);
36970     if (!(match)) {
36971       throw ngOptionsMinErr('iexp',
36972         "Expected expression in form of " +
36973         "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
36974         " but got '{0}'. Element: {1}",
36975         optionsExp, startingTag(selectElement));
36976     }
36977
36978     // Extract the parts from the ngOptions expression
36979
36980     // The variable name for the value of the item in the collection
36981     var valueName = match[5] || match[7];
36982     // The variable name for the key of the item in the collection
36983     var keyName = match[6];
36984
36985     // An expression that generates the viewValue for an option if there is a label expression
36986     var selectAs = / as /.test(match[0]) && match[1];
36987     // An expression that is used to track the id of each object in the options collection
36988     var trackBy = match[9];
36989     // An expression that generates the viewValue for an option if there is no label expression
36990     var valueFn = $parse(match[2] ? match[1] : valueName);
36991     var selectAsFn = selectAs && $parse(selectAs);
36992     var viewValueFn = selectAsFn || valueFn;
36993     var trackByFn = trackBy && $parse(trackBy);
36994
36995     // Get the value by which we are going to track the option
36996     // if we have a trackFn then use that (passing scope and locals)
36997     // otherwise just hash the given viewValue
36998     var getTrackByValueFn = trackBy ?
36999                               function(value, locals) { return trackByFn(scope, locals); } :
37000                               function getHashOfValue(value) { return hashKey(value); };
37001     var getTrackByValue = function(value, key) {
37002       return getTrackByValueFn(value, getLocals(value, key));
37003     };
37004
37005     var displayFn = $parse(match[2] || match[1]);
37006     var groupByFn = $parse(match[3] || '');
37007     var disableWhenFn = $parse(match[4] || '');
37008     var valuesFn = $parse(match[8]);
37009
37010     var locals = {};
37011     var getLocals = keyName ? function(value, key) {
37012       locals[keyName] = key;
37013       locals[valueName] = value;
37014       return locals;
37015     } : function(value) {
37016       locals[valueName] = value;
37017       return locals;
37018     };
37019
37020
37021     function Option(selectValue, viewValue, label, group, disabled) {
37022       this.selectValue = selectValue;
37023       this.viewValue = viewValue;
37024       this.label = label;
37025       this.group = group;
37026       this.disabled = disabled;
37027     }
37028
37029     function getOptionValuesKeys(optionValues) {
37030       var optionValuesKeys;
37031
37032       if (!keyName && isArrayLike(optionValues)) {
37033         optionValuesKeys = optionValues;
37034       } else {
37035         // if object, extract keys, in enumeration order, unsorted
37036         optionValuesKeys = [];
37037         for (var itemKey in optionValues) {
37038           if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
37039             optionValuesKeys.push(itemKey);
37040           }
37041         }
37042       }
37043       return optionValuesKeys;
37044     }
37045
37046     return {
37047       trackBy: trackBy,
37048       getTrackByValue: getTrackByValue,
37049       getWatchables: $parse(valuesFn, function(optionValues) {
37050         // Create a collection of things that we would like to watch (watchedArray)
37051         // so that they can all be watched using a single $watchCollection
37052         // that only runs the handler once if anything changes
37053         var watchedArray = [];
37054         optionValues = optionValues || [];
37055
37056         var optionValuesKeys = getOptionValuesKeys(optionValues);
37057         var optionValuesLength = optionValuesKeys.length;
37058         for (var index = 0; index < optionValuesLength; index++) {
37059           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
37060           var value = optionValues[key];
37061
37062           var locals = getLocals(value, key);
37063           var selectValue = getTrackByValueFn(value, locals);
37064           watchedArray.push(selectValue);
37065
37066           // Only need to watch the displayFn if there is a specific label expression
37067           if (match[2] || match[1]) {
37068             var label = displayFn(scope, locals);
37069             watchedArray.push(label);
37070           }
37071
37072           // Only need to watch the disableWhenFn if there is a specific disable expression
37073           if (match[4]) {
37074             var disableWhen = disableWhenFn(scope, locals);
37075             watchedArray.push(disableWhen);
37076           }
37077         }
37078         return watchedArray;
37079       }),
37080
37081       getOptions: function() {
37082
37083         var optionItems = [];
37084         var selectValueMap = {};
37085
37086         // The option values were already computed in the `getWatchables` fn,
37087         // which must have been called to trigger `getOptions`
37088         var optionValues = valuesFn(scope) || [];
37089         var optionValuesKeys = getOptionValuesKeys(optionValues);
37090         var optionValuesLength = optionValuesKeys.length;
37091
37092         for (var index = 0; index < optionValuesLength; index++) {
37093           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
37094           var value = optionValues[key];
37095           var locals = getLocals(value, key);
37096           var viewValue = viewValueFn(scope, locals);
37097           var selectValue = getTrackByValueFn(viewValue, locals);
37098           var label = displayFn(scope, locals);
37099           var group = groupByFn(scope, locals);
37100           var disabled = disableWhenFn(scope, locals);
37101           var optionItem = new Option(selectValue, viewValue, label, group, disabled);
37102
37103           optionItems.push(optionItem);
37104           selectValueMap[selectValue] = optionItem;
37105         }
37106
37107         return {
37108           items: optionItems,
37109           selectValueMap: selectValueMap,
37110           getOptionFromViewValue: function(value) {
37111             return selectValueMap[getTrackByValue(value)];
37112           },
37113           getViewValueFromOption: function(option) {
37114             // If the viewValue could be an object that may be mutated by the application,
37115             // we need to make a copy and not return the reference to the value on the option.
37116             return trackBy ? angular.copy(option.viewValue) : option.viewValue;
37117           }
37118         };
37119       }
37120     };
37121   }
37122
37123
37124   // we can't just jqLite('<option>') since jqLite is not smart enough
37125   // to create it in <select> and IE barfs otherwise.
37126   var optionTemplate = window.document.createElement('option'),
37127       optGroupTemplate = window.document.createElement('optgroup');
37128
37129     function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
37130
37131       var selectCtrl = ctrls[0];
37132       var ngModelCtrl = ctrls[1];
37133       var multiple = attr.multiple;
37134
37135       // The emptyOption allows the application developer to provide their own custom "empty"
37136       // option when the viewValue does not match any of the option values.
37137       var emptyOption;
37138       for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
37139         if (children[i].value === '') {
37140           emptyOption = children.eq(i);
37141           break;
37142         }
37143       }
37144
37145       var providedEmptyOption = !!emptyOption;
37146
37147       var unknownOption = jqLite(optionTemplate.cloneNode(false));
37148       unknownOption.val('?');
37149
37150       var options;
37151       var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
37152       // This stores the newly created options before they are appended to the select.
37153       // Since the contents are removed from the fragment when it is appended,
37154       // we only need to create it once.
37155       var listFragment = $document[0].createDocumentFragment();
37156
37157       var renderEmptyOption = function() {
37158         if (!providedEmptyOption) {
37159           selectElement.prepend(emptyOption);
37160         }
37161         selectElement.val('');
37162         emptyOption.prop('selected', true); // needed for IE
37163         emptyOption.attr('selected', true);
37164       };
37165
37166       var removeEmptyOption = function() {
37167         if (!providedEmptyOption) {
37168           emptyOption.remove();
37169         }
37170       };
37171
37172
37173       var renderUnknownOption = function() {
37174         selectElement.prepend(unknownOption);
37175         selectElement.val('?');
37176         unknownOption.prop('selected', true); // needed for IE
37177         unknownOption.attr('selected', true);
37178       };
37179
37180       var removeUnknownOption = function() {
37181         unknownOption.remove();
37182       };
37183
37184       // Update the controller methods for multiple selectable options
37185       if (!multiple) {
37186
37187         selectCtrl.writeValue = function writeNgOptionsValue(value) {
37188           var option = options.getOptionFromViewValue(value);
37189
37190           if (option) {
37191             // Don't update the option when it is already selected.
37192             // For example, the browser will select the first option by default. In that case,
37193             // most properties are set automatically - except the `selected` attribute, which we
37194             // set always
37195
37196             if (selectElement[0].value !== option.selectValue) {
37197               removeUnknownOption();
37198               removeEmptyOption();
37199
37200               selectElement[0].value = option.selectValue;
37201               option.element.selected = true;
37202             }
37203
37204             option.element.setAttribute('selected', 'selected');
37205           } else {
37206             if (value === null || providedEmptyOption) {
37207               removeUnknownOption();
37208               renderEmptyOption();
37209             } else {
37210               removeEmptyOption();
37211               renderUnknownOption();
37212             }
37213           }
37214         };
37215
37216         selectCtrl.readValue = function readNgOptionsValue() {
37217
37218           var selectedOption = options.selectValueMap[selectElement.val()];
37219
37220           if (selectedOption && !selectedOption.disabled) {
37221             removeEmptyOption();
37222             removeUnknownOption();
37223             return options.getViewValueFromOption(selectedOption);
37224           }
37225           return null;
37226         };
37227
37228         // If we are using `track by` then we must watch the tracked value on the model
37229         // since ngModel only watches for object identity change
37230         if (ngOptions.trackBy) {
37231           scope.$watch(
37232             function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
37233             function() { ngModelCtrl.$render(); }
37234           );
37235         }
37236
37237       } else {
37238
37239         ngModelCtrl.$isEmpty = function(value) {
37240           return !value || value.length === 0;
37241         };
37242
37243
37244         selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
37245           options.items.forEach(function(option) {
37246             option.element.selected = false;
37247           });
37248
37249           if (value) {
37250             value.forEach(function(item) {
37251               var option = options.getOptionFromViewValue(item);
37252               if (option) option.element.selected = true;
37253             });
37254           }
37255         };
37256
37257
37258         selectCtrl.readValue = function readNgOptionsMultiple() {
37259           var selectedValues = selectElement.val() || [],
37260               selections = [];
37261
37262           forEach(selectedValues, function(value) {
37263             var option = options.selectValueMap[value];
37264             if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
37265           });
37266
37267           return selections;
37268         };
37269
37270         // If we are using `track by` then we must watch these tracked values on the model
37271         // since ngModel only watches for object identity change
37272         if (ngOptions.trackBy) {
37273
37274           scope.$watchCollection(function() {
37275             if (isArray(ngModelCtrl.$viewValue)) {
37276               return ngModelCtrl.$viewValue.map(function(value) {
37277                 return ngOptions.getTrackByValue(value);
37278               });
37279             }
37280           }, function() {
37281             ngModelCtrl.$render();
37282           });
37283
37284         }
37285       }
37286
37287
37288       if (providedEmptyOption) {
37289
37290         // we need to remove it before calling selectElement.empty() because otherwise IE will
37291         // remove the label from the element. wtf?
37292         emptyOption.remove();
37293
37294         // compile the element since there might be bindings in it
37295         $compile(emptyOption)(scope);
37296
37297         // remove the class, which is added automatically because we recompile the element and it
37298         // becomes the compilation root
37299         emptyOption.removeClass('ng-scope');
37300       } else {
37301         emptyOption = jqLite(optionTemplate.cloneNode(false));
37302       }
37303
37304       selectElement.empty();
37305
37306       // We need to do this here to ensure that the options object is defined
37307       // when we first hit it in writeNgOptionsValue
37308       updateOptions();
37309
37310       // We will re-render the option elements if the option values or labels change
37311       scope.$watchCollection(ngOptions.getWatchables, updateOptions);
37312
37313       // ------------------------------------------------------------------ //
37314
37315       function addOptionElement(option, parent) {
37316         var optionElement = optionTemplate.cloneNode(false);
37317         parent.appendChild(optionElement);
37318         updateOptionElement(option, optionElement);
37319       }
37320
37321
37322       function updateOptionElement(option, element) {
37323         option.element = element;
37324         element.disabled = option.disabled;
37325         // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
37326         // selects in certain circumstances when multiple selects are next to each other and display
37327         // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
37328         // See https://github.com/angular/angular.js/issues/11314 for more info.
37329         // This is unfortunately untestable with unit / e2e tests
37330         if (option.label !== element.label) {
37331           element.label = option.label;
37332           element.textContent = option.label;
37333         }
37334         if (option.value !== element.value) element.value = option.selectValue;
37335       }
37336
37337       function updateOptions() {
37338         var previousValue = options && selectCtrl.readValue();
37339
37340         // We must remove all current options, but cannot simply set innerHTML = null
37341         // since the providedEmptyOption might have an ngIf on it that inserts comments which we
37342         // must preserve.
37343         // Instead, iterate over the current option elements and remove them or their optgroup
37344         // parents
37345         if (options) {
37346
37347           for (var i = options.items.length - 1; i >= 0; i--) {
37348             var option = options.items[i];
37349             if (option.group) {
37350               jqLiteRemove(option.element.parentNode);
37351             } else {
37352               jqLiteRemove(option.element);
37353             }
37354           }
37355         }
37356
37357         options = ngOptions.getOptions();
37358
37359         var groupElementMap = {};
37360
37361         // Ensure that the empty option is always there if it was explicitly provided
37362         if (providedEmptyOption) {
37363           selectElement.prepend(emptyOption);
37364         }
37365
37366         options.items.forEach(function addOption(option) {
37367           var groupElement;
37368
37369           if (isDefined(option.group)) {
37370
37371             // This option is to live in a group
37372             // See if we have already created this group
37373             groupElement = groupElementMap[option.group];
37374
37375             if (!groupElement) {
37376
37377               groupElement = optGroupTemplate.cloneNode(false);
37378               listFragment.appendChild(groupElement);
37379
37380               // Update the label on the group element
37381               groupElement.label = option.group;
37382
37383               // Store it for use later
37384               groupElementMap[option.group] = groupElement;
37385             }
37386
37387             addOptionElement(option, groupElement);
37388
37389           } else {
37390
37391             // This option is not in a group
37392             addOptionElement(option, listFragment);
37393           }
37394         });
37395
37396         selectElement[0].appendChild(listFragment);
37397
37398         ngModelCtrl.$render();
37399
37400         // Check to see if the value has changed due to the update to the options
37401         if (!ngModelCtrl.$isEmpty(previousValue)) {
37402           var nextValue = selectCtrl.readValue();
37403           var isNotPrimitive = ngOptions.trackBy || multiple;
37404           if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
37405             ngModelCtrl.$setViewValue(nextValue);
37406             ngModelCtrl.$render();
37407           }
37408         }
37409
37410       }
37411   }
37412
37413   return {
37414     restrict: 'A',
37415     terminal: true,
37416     require: ['select', 'ngModel'],
37417     link: {
37418       pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
37419         // Deactivate the SelectController.register method to prevent
37420         // option directives from accidentally registering themselves
37421         // (and unwanted $destroy handlers etc.)
37422         ctrls[0].registerOption = noop;
37423       },
37424       post: ngOptionsPostLink
37425     }
37426   };
37427 }];
37428
37429 /**
37430  * @ngdoc directive
37431  * @name ngPluralize
37432  * @restrict EA
37433  *
37434  * @description
37435  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
37436  * These rules are bundled with angular.js, but can be overridden
37437  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
37438  * by specifying the mappings between
37439  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
37440  * and the strings to be displayed.
37441  *
37442  * # Plural categories and explicit number rules
37443  * There are two
37444  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
37445  * in Angular's default en-US locale: "one" and "other".
37446  *
37447  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
37448  * any number that is not 1), an explicit number rule can only match one number. For example, the
37449  * explicit number rule for "3" matches the number 3. There are examples of plural categories
37450  * and explicit number rules throughout the rest of this documentation.
37451  *
37452  * # Configuring ngPluralize
37453  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
37454  * You can also provide an optional attribute, `offset`.
37455  *
37456  * The value of the `count` attribute can be either a string or an {@link guide/expression
37457  * Angular expression}; these are evaluated on the current scope for its bound value.
37458  *
37459  * The `when` attribute specifies the mappings between plural categories and the actual
37460  * string to be displayed. The value of the attribute should be a JSON object.
37461  *
37462  * The following example shows how to configure ngPluralize:
37463  *
37464  * ```html
37465  * <ng-pluralize count="personCount"
37466                  when="{'0': 'Nobody is viewing.',
37467  *                      'one': '1 person is viewing.',
37468  *                      'other': '{} people are viewing.'}">
37469  * </ng-pluralize>
37470  *```
37471  *
37472  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
37473  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
37474  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
37475  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
37476  * show "a dozen people are viewing".
37477  *
37478  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
37479  * into pluralized strings. In the previous example, Angular will replace `{}` with
37480  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
37481  * for <span ng-non-bindable>{{numberExpression}}</span>.
37482  *
37483  * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
37484  * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
37485  *
37486  * # Configuring ngPluralize with offset
37487  * The `offset` attribute allows further customization of pluralized text, which can result in
37488  * a better user experience. For example, instead of the message "4 people are viewing this document",
37489  * you might display "John, Kate and 2 others are viewing this document".
37490  * The offset attribute allows you to offset a number by any desired value.
37491  * Let's take a look at an example:
37492  *
37493  * ```html
37494  * <ng-pluralize count="personCount" offset=2
37495  *               when="{'0': 'Nobody is viewing.',
37496  *                      '1': '{{person1}} is viewing.',
37497  *                      '2': '{{person1}} and {{person2}} are viewing.',
37498  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
37499  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
37500  * </ng-pluralize>
37501  * ```
37502  *
37503  * Notice that we are still using two plural categories(one, other), but we added
37504  * three explicit number rules 0, 1 and 2.
37505  * When one person, perhaps John, views the document, "John is viewing" will be shown.
37506  * When three people view the document, no explicit number rule is found, so
37507  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
37508  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
37509  * is shown.
37510  *
37511  * Note that when you specify offsets, you must provide explicit number rules for
37512  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
37513  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
37514  * plural categories "one" and "other".
37515  *
37516  * @param {string|expression} count The variable to be bound to.
37517  * @param {string} when The mapping between plural category to its corresponding strings.
37518  * @param {number=} offset Offset to deduct from the total number.
37519  *
37520  * @example
37521     <example module="pluralizeExample">
37522       <file name="index.html">
37523         <script>
37524           angular.module('pluralizeExample', [])
37525             .controller('ExampleController', ['$scope', function($scope) {
37526               $scope.person1 = 'Igor';
37527               $scope.person2 = 'Misko';
37528               $scope.personCount = 1;
37529             }]);
37530         </script>
37531         <div ng-controller="ExampleController">
37532           <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
37533           <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
37534           <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
37535
37536           <!--- Example with simple pluralization rules for en locale --->
37537           Without Offset:
37538           <ng-pluralize count="personCount"
37539                         when="{'0': 'Nobody is viewing.',
37540                                'one': '1 person is viewing.',
37541                                'other': '{} people are viewing.'}">
37542           </ng-pluralize><br>
37543
37544           <!--- Example with offset --->
37545           With Offset(2):
37546           <ng-pluralize count="personCount" offset=2
37547                         when="{'0': 'Nobody is viewing.',
37548                                '1': '{{person1}} is viewing.',
37549                                '2': '{{person1}} and {{person2}} are viewing.',
37550                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
37551                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
37552           </ng-pluralize>
37553         </div>
37554       </file>
37555       <file name="protractor.js" type="protractor">
37556         it('should show correct pluralized string', function() {
37557           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
37558           var withOffset = element.all(by.css('ng-pluralize')).get(1);
37559           var countInput = element(by.model('personCount'));
37560
37561           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
37562           expect(withOffset.getText()).toEqual('Igor is viewing.');
37563
37564           countInput.clear();
37565           countInput.sendKeys('0');
37566
37567           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
37568           expect(withOffset.getText()).toEqual('Nobody is viewing.');
37569
37570           countInput.clear();
37571           countInput.sendKeys('2');
37572
37573           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
37574           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
37575
37576           countInput.clear();
37577           countInput.sendKeys('3');
37578
37579           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
37580           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
37581
37582           countInput.clear();
37583           countInput.sendKeys('4');
37584
37585           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
37586           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
37587         });
37588         it('should show data-bound names', function() {
37589           var withOffset = element.all(by.css('ng-pluralize')).get(1);
37590           var personCount = element(by.model('personCount'));
37591           var person1 = element(by.model('person1'));
37592           var person2 = element(by.model('person2'));
37593           personCount.clear();
37594           personCount.sendKeys('4');
37595           person1.clear();
37596           person1.sendKeys('Di');
37597           person2.clear();
37598           person2.sendKeys('Vojta');
37599           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
37600         });
37601       </file>
37602     </example>
37603  */
37604 var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
37605   var BRACE = /{}/g,
37606       IS_WHEN = /^when(Minus)?(.+)$/;
37607
37608   return {
37609     link: function(scope, element, attr) {
37610       var numberExp = attr.count,
37611           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
37612           offset = attr.offset || 0,
37613           whens = scope.$eval(whenExp) || {},
37614           whensExpFns = {},
37615           startSymbol = $interpolate.startSymbol(),
37616           endSymbol = $interpolate.endSymbol(),
37617           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
37618           watchRemover = angular.noop,
37619           lastCount;
37620
37621       forEach(attr, function(expression, attributeName) {
37622         var tmpMatch = IS_WHEN.exec(attributeName);
37623         if (tmpMatch) {
37624           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
37625           whens[whenKey] = element.attr(attr.$attr[attributeName]);
37626         }
37627       });
37628       forEach(whens, function(expression, key) {
37629         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
37630
37631       });
37632
37633       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
37634         var count = parseFloat(newVal);
37635         var countIsNaN = isNaN(count);
37636
37637         if (!countIsNaN && !(count in whens)) {
37638           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
37639           // Otherwise, check it against pluralization rules in $locale service.
37640           count = $locale.pluralCat(count - offset);
37641         }
37642
37643         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
37644         // In JS `NaN !== NaN`, so we have to explicitly check.
37645         if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
37646           watchRemover();
37647           var whenExpFn = whensExpFns[count];
37648           if (isUndefined(whenExpFn)) {
37649             if (newVal != null) {
37650               $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
37651             }
37652             watchRemover = noop;
37653             updateElementText();
37654           } else {
37655             watchRemover = scope.$watch(whenExpFn, updateElementText);
37656           }
37657           lastCount = count;
37658         }
37659       });
37660
37661       function updateElementText(newText) {
37662         element.text(newText || '');
37663       }
37664     }
37665   };
37666 }];
37667
37668 /**
37669  * @ngdoc directive
37670  * @name ngRepeat
37671  * @multiElement
37672  *
37673  * @description
37674  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
37675  * instance gets its own scope, where the given loop variable is set to the current collection item,
37676  * and `$index` is set to the item index or key.
37677  *
37678  * Special properties are exposed on the local scope of each template instance, including:
37679  *
37680  * | Variable  | Type            | Details                                                                     |
37681  * |-----------|-----------------|-----------------------------------------------------------------------------|
37682  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
37683  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
37684  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
37685  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
37686  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
37687  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
37688  *
37689  * <div class="alert alert-info">
37690  *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
37691  *   This may be useful when, for instance, nesting ngRepeats.
37692  * </div>
37693  *
37694  *
37695  * # Iterating over object properties
37696  *
37697  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
37698  * syntax:
37699  *
37700  * ```js
37701  * <div ng-repeat="(key, value) in myObj"> ... </div>
37702  * ```
37703  *
37704  * However, there are a limitations compared to array iteration:
37705  *
37706  * - The JavaScript specification does not define the order of keys
37707  *   returned for an object, so Angular relies on the order returned by the browser
37708  *   when running `for key in myObj`. Browsers generally follow the strategy of providing
37709  *   keys in the order in which they were defined, although there are exceptions when keys are deleted
37710  *   and reinstated. See the
37711  *   [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
37712  *
37713  * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
37714  *   it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
37715  *
37716  * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
37717  *   objects, and will throw if used with one.
37718  *
37719  * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
37720  * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
37721  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
37722  * or implement a `$watch` on the object yourself.
37723  *
37724  *
37725  * # Tracking and Duplicates
37726  *
37727  * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
37728  * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
37729  *
37730  * * When an item is added, a new instance of the template is added to the DOM.
37731  * * When an item is removed, its template instance is removed from the DOM.
37732  * * When items are reordered, their respective templates are reordered in the DOM.
37733  *
37734  * To minimize creation of DOM elements, `ngRepeat` uses a function
37735  * to "keep track" of all items in the collection and their corresponding DOM elements.
37736  * For example, if an item is added to the collection, ngRepeat will know that all other items
37737  * already have DOM elements, and will not re-render them.
37738  *
37739  * The default tracking function (which tracks items by their identity) does not allow
37740  * duplicate items in arrays. This is because when there are duplicates, it is not possible
37741  * to maintain a one-to-one mapping between collection items and DOM elements.
37742  *
37743  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
37744  * with your own using the `track by` expression.
37745  *
37746  * For example, you may track items by the index of each item in the collection, using the
37747  * special scope property `$index`:
37748  * ```html
37749  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
37750  *      {{n}}
37751  *    </div>
37752  * ```
37753  *
37754  * You may also use arbitrary expressions in `track by`, including references to custom functions
37755  * on the scope:
37756  * ```html
37757  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
37758  *      {{n}}
37759  *    </div>
37760  * ```
37761  *
37762  * <div class="alert alert-success">
37763  * If you are working with objects that have an identifier property, you should track
37764  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
37765  * will not have to rebuild the DOM elements for items it has already rendered, even if the
37766  * JavaScript objects in the collection have been substituted for new ones. For large collections,
37767  * this significantly improves rendering performance. If you don't have a unique identifier,
37768  * `track by $index` can also provide a performance boost.
37769  * </div>
37770  * ```html
37771  *    <div ng-repeat="model in collection track by model.id">
37772  *      {{model.name}}
37773  *    </div>
37774  * ```
37775  *
37776  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
37777  * `$id` function, which tracks items by their identity:
37778  * ```html
37779  *    <div ng-repeat="obj in collection track by $id(obj)">
37780  *      {{obj.prop}}
37781  *    </div>
37782  * ```
37783  *
37784  * <div class="alert alert-warning">
37785  * **Note:** `track by` must always be the last expression:
37786  * </div>
37787  * ```
37788  * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
37789  *     {{model.name}}
37790  * </div>
37791  * ```
37792  *
37793  * # Special repeat start and end points
37794  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
37795  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
37796  * 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)
37797  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
37798  *
37799  * The example below makes use of this feature:
37800  * ```html
37801  *   <header ng-repeat-start="item in items">
37802  *     Header {{ item }}
37803  *   </header>
37804  *   <div class="body">
37805  *     Body {{ item }}
37806  *   </div>
37807  *   <footer ng-repeat-end>
37808  *     Footer {{ item }}
37809  *   </footer>
37810  * ```
37811  *
37812  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
37813  * ```html
37814  *   <header>
37815  *     Header A
37816  *   </header>
37817  *   <div class="body">
37818  *     Body A
37819  *   </div>
37820  *   <footer>
37821  *     Footer A
37822  *   </footer>
37823  *   <header>
37824  *     Header B
37825  *   </header>
37826  *   <div class="body">
37827  *     Body B
37828  *   </div>
37829  *   <footer>
37830  *     Footer B
37831  *   </footer>
37832  * ```
37833  *
37834  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
37835  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
37836  *
37837  * @animations
37838  * | Animation                        | Occurs                              |
37839  * |----------------------------------|-------------------------------------|
37840  * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
37841  * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
37842  * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
37843  *
37844  * See the example below for defining CSS animations with ngRepeat.
37845  *
37846  * @element ANY
37847  * @scope
37848  * @priority 1000
37849  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
37850  *   formats are currently supported:
37851  *
37852  *   * `variable in expression` â€“ where variable is the user defined loop variable and `expression`
37853  *     is a scope expression giving the collection to enumerate.
37854  *
37855  *     For example: `album in artist.albums`.
37856  *
37857  *   * `(key, value) in expression` â€“ where `key` and `value` can be any user defined identifiers,
37858  *     and `expression` is the scope expression giving the collection to enumerate.
37859  *
37860  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
37861  *
37862  *   * `variable in expression track by tracking_expression` â€“ You can also provide an optional tracking expression
37863  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
37864  *     is specified, ng-repeat associates elements by identity. It is an error to have
37865  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
37866  *     mapped to the same DOM element, which is not possible.)
37867  *
37868  *     Note that the tracking expression must come last, after any filters, and the alias expression.
37869  *
37870  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
37871  *     will be associated by item identity in the array.
37872  *
37873  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
37874  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
37875  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
37876  *     element in the same way in the DOM.
37877  *
37878  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
37879  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
37880  *     property is same.
37881  *
37882  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
37883  *     to items in conjunction with a tracking expression.
37884  *
37885  *   * `variable in expression as alias_expression` â€“ You can also provide an optional alias expression which will then store the
37886  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
37887  *     when a filter is active on the repeater, but the filtered result set is empty.
37888  *
37889  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
37890  *     the items have been processed through the filter.
37891  *
37892  *     Please note that `as [variable name] is not an operator but rather a part of ngRepeat micro-syntax so it can be used only at the end
37893  *     (and not as operator, inside an expression).
37894  *
37895  *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
37896  *
37897  * @example
37898  * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
37899  * results by name. New (entering) and removed (leaving) items are animated.
37900   <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
37901     <file name="index.html">
37902       <div ng-controller="repeatController">
37903         I have {{friends.length}} friends. They are:
37904         <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
37905         <ul class="example-animate-container">
37906           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
37907             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
37908           </li>
37909           <li class="animate-repeat" ng-if="results.length == 0">
37910             <strong>No results found...</strong>
37911           </li>
37912         </ul>
37913       </div>
37914     </file>
37915     <file name="script.js">
37916       angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
37917         $scope.friends = [
37918           {name:'John', age:25, gender:'boy'},
37919           {name:'Jessie', age:30, gender:'girl'},
37920           {name:'Johanna', age:28, gender:'girl'},
37921           {name:'Joy', age:15, gender:'girl'},
37922           {name:'Mary', age:28, gender:'girl'},
37923           {name:'Peter', age:95, gender:'boy'},
37924           {name:'Sebastian', age:50, gender:'boy'},
37925           {name:'Erika', age:27, gender:'girl'},
37926           {name:'Patrick', age:40, gender:'boy'},
37927           {name:'Samantha', age:60, gender:'girl'}
37928         ];
37929       });
37930     </file>
37931     <file name="animations.css">
37932       .example-animate-container {
37933         background:white;
37934         border:1px solid black;
37935         list-style:none;
37936         margin:0;
37937         padding:0 10px;
37938       }
37939
37940       .animate-repeat {
37941         line-height:30px;
37942         list-style:none;
37943         box-sizing:border-box;
37944       }
37945
37946       .animate-repeat.ng-move,
37947       .animate-repeat.ng-enter,
37948       .animate-repeat.ng-leave {
37949         transition:all linear 0.5s;
37950       }
37951
37952       .animate-repeat.ng-leave.ng-leave-active,
37953       .animate-repeat.ng-move,
37954       .animate-repeat.ng-enter {
37955         opacity:0;
37956         max-height:0;
37957       }
37958
37959       .animate-repeat.ng-leave,
37960       .animate-repeat.ng-move.ng-move-active,
37961       .animate-repeat.ng-enter.ng-enter-active {
37962         opacity:1;
37963         max-height:30px;
37964       }
37965     </file>
37966     <file name="protractor.js" type="protractor">
37967       var friends = element.all(by.repeater('friend in friends'));
37968
37969       it('should render initial data set', function() {
37970         expect(friends.count()).toBe(10);
37971         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
37972         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
37973         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
37974         expect(element(by.binding('friends.length')).getText())
37975             .toMatch("I have 10 friends. They are:");
37976       });
37977
37978        it('should update repeater when filter predicate changes', function() {
37979          expect(friends.count()).toBe(10);
37980
37981          element(by.model('q')).sendKeys('ma');
37982
37983          expect(friends.count()).toBe(2);
37984          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
37985          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
37986        });
37987       </file>
37988     </example>
37989  */
37990 var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
37991   var NG_REMOVED = '$$NG_REMOVED';
37992   var ngRepeatMinErr = minErr('ngRepeat');
37993
37994   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
37995     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
37996     scope[valueIdentifier] = value;
37997     if (keyIdentifier) scope[keyIdentifier] = key;
37998     scope.$index = index;
37999     scope.$first = (index === 0);
38000     scope.$last = (index === (arrayLength - 1));
38001     scope.$middle = !(scope.$first || scope.$last);
38002     // jshint bitwise: false
38003     scope.$odd = !(scope.$even = (index&1) === 0);
38004     // jshint bitwise: true
38005   };
38006
38007   var getBlockStart = function(block) {
38008     return block.clone[0];
38009   };
38010
38011   var getBlockEnd = function(block) {
38012     return block.clone[block.clone.length - 1];
38013   };
38014
38015
38016   return {
38017     restrict: 'A',
38018     multiElement: true,
38019     transclude: 'element',
38020     priority: 1000,
38021     terminal: true,
38022     $$tlb: true,
38023     compile: function ngRepeatCompile($element, $attr) {
38024       var expression = $attr.ngRepeat;
38025       var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
38026
38027       var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
38028
38029       if (!match) {
38030         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
38031             expression);
38032       }
38033
38034       var lhs = match[1];
38035       var rhs = match[2];
38036       var aliasAs = match[3];
38037       var trackByExp = match[4];
38038
38039       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
38040
38041       if (!match) {
38042         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
38043             lhs);
38044       }
38045       var valueIdentifier = match[3] || match[1];
38046       var keyIdentifier = match[2];
38047
38048       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
38049           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
38050         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
38051           aliasAs);
38052       }
38053
38054       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
38055       var hashFnLocals = {$id: hashKey};
38056
38057       if (trackByExp) {
38058         trackByExpGetter = $parse(trackByExp);
38059       } else {
38060         trackByIdArrayFn = function(key, value) {
38061           return hashKey(value);
38062         };
38063         trackByIdObjFn = function(key) {
38064           return key;
38065         };
38066       }
38067
38068       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
38069
38070         if (trackByExpGetter) {
38071           trackByIdExpFn = function(key, value, index) {
38072             // assign key, value, and $index to the locals so that they can be used in hash functions
38073             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
38074             hashFnLocals[valueIdentifier] = value;
38075             hashFnLocals.$index = index;
38076             return trackByExpGetter($scope, hashFnLocals);
38077           };
38078         }
38079
38080         // Store a list of elements from previous run. This is a hash where key is the item from the
38081         // iterator, and the value is objects with following properties.
38082         //   - scope: bound scope
38083         //   - element: previous element.
38084         //   - index: position
38085         //
38086         // We are using no-proto object so that we don't need to guard against inherited props via
38087         // hasOwnProperty.
38088         var lastBlockMap = createMap();
38089
38090         //watch props
38091         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
38092           var index, length,
38093               previousNode = $element[0],     // node that cloned nodes should be inserted after
38094                                               // initialized to the comment node anchor
38095               nextNode,
38096               // Same as lastBlockMap but it has the current state. It will become the
38097               // lastBlockMap on the next iteration.
38098               nextBlockMap = createMap(),
38099               collectionLength,
38100               key, value, // key/value of iteration
38101               trackById,
38102               trackByIdFn,
38103               collectionKeys,
38104               block,       // last object information {scope, element, id}
38105               nextBlockOrder,
38106               elementsToRemove;
38107
38108           if (aliasAs) {
38109             $scope[aliasAs] = collection;
38110           }
38111
38112           if (isArrayLike(collection)) {
38113             collectionKeys = collection;
38114             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
38115           } else {
38116             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
38117             // if object, extract keys, in enumeration order, unsorted
38118             collectionKeys = [];
38119             for (var itemKey in collection) {
38120               if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
38121                 collectionKeys.push(itemKey);
38122               }
38123             }
38124           }
38125
38126           collectionLength = collectionKeys.length;
38127           nextBlockOrder = new Array(collectionLength);
38128
38129           // locate existing items
38130           for (index = 0; index < collectionLength; index++) {
38131             key = (collection === collectionKeys) ? index : collectionKeys[index];
38132             value = collection[key];
38133             trackById = trackByIdFn(key, value, index);
38134             if (lastBlockMap[trackById]) {
38135               // found previously seen block
38136               block = lastBlockMap[trackById];
38137               delete lastBlockMap[trackById];
38138               nextBlockMap[trackById] = block;
38139               nextBlockOrder[index] = block;
38140             } else if (nextBlockMap[trackById]) {
38141               // if collision detected. restore lastBlockMap and throw an error
38142               forEach(nextBlockOrder, function(block) {
38143                 if (block && block.scope) lastBlockMap[block.id] = block;
38144               });
38145               throw ngRepeatMinErr('dupes',
38146                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
38147                   expression, trackById, value);
38148             } else {
38149               // new never before seen block
38150               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
38151               nextBlockMap[trackById] = true;
38152             }
38153           }
38154
38155           // remove leftover items
38156           for (var blockKey in lastBlockMap) {
38157             block = lastBlockMap[blockKey];
38158             elementsToRemove = getBlockNodes(block.clone);
38159             $animate.leave(elementsToRemove);
38160             if (elementsToRemove[0].parentNode) {
38161               // if the element was not removed yet because of pending animation, mark it as deleted
38162               // so that we can ignore it later
38163               for (index = 0, length = elementsToRemove.length; index < length; index++) {
38164                 elementsToRemove[index][NG_REMOVED] = true;
38165               }
38166             }
38167             block.scope.$destroy();
38168           }
38169
38170           // we are not using forEach for perf reasons (trying to avoid #call)
38171           for (index = 0; index < collectionLength; index++) {
38172             key = (collection === collectionKeys) ? index : collectionKeys[index];
38173             value = collection[key];
38174             block = nextBlockOrder[index];
38175
38176             if (block.scope) {
38177               // if we have already seen this object, then we need to reuse the
38178               // associated scope/element
38179
38180               nextNode = previousNode;
38181
38182               // skip nodes that are already pending removal via leave animation
38183               do {
38184                 nextNode = nextNode.nextSibling;
38185               } while (nextNode && nextNode[NG_REMOVED]);
38186
38187               if (getBlockStart(block) != nextNode) {
38188                 // existing item which got moved
38189                 $animate.move(getBlockNodes(block.clone), null, previousNode);
38190               }
38191               previousNode = getBlockEnd(block);
38192               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
38193             } else {
38194               // new item which we don't know about
38195               $transclude(function ngRepeatTransclude(clone, scope) {
38196                 block.scope = scope;
38197                 // http://jsperf.com/clone-vs-createcomment
38198                 var endNode = ngRepeatEndComment.cloneNode(false);
38199                 clone[clone.length++] = endNode;
38200
38201                 $animate.enter(clone, null, previousNode);
38202                 previousNode = endNode;
38203                 // Note: We only need the first/last node of the cloned nodes.
38204                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
38205                 // by a directive with templateUrl when its template arrives.
38206                 block.clone = clone;
38207                 nextBlockMap[block.id] = block;
38208                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
38209               });
38210             }
38211           }
38212           lastBlockMap = nextBlockMap;
38213         });
38214       };
38215     }
38216   };
38217 }];
38218
38219 var NG_HIDE_CLASS = 'ng-hide';
38220 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
38221 /**
38222  * @ngdoc directive
38223  * @name ngShow
38224  * @multiElement
38225  *
38226  * @description
38227  * The `ngShow` directive shows or hides the given HTML element based on the expression
38228  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
38229  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
38230  * in AngularJS and sets the display style to none (using an !important flag).
38231  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
38232  *
38233  * ```html
38234  * <!-- when $scope.myValue is truthy (element is visible) -->
38235  * <div ng-show="myValue"></div>
38236  *
38237  * <!-- when $scope.myValue is falsy (element is hidden) -->
38238  * <div ng-show="myValue" class="ng-hide"></div>
38239  * ```
38240  *
38241  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
38242  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
38243  * from the element causing the element not to appear hidden.
38244  *
38245  * ## Why is !important used?
38246  *
38247  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
38248  * can be easily overridden by heavier selectors. For example, something as simple
38249  * as changing the display style on a HTML list item would make hidden elements appear visible.
38250  * This also becomes a bigger issue when dealing with CSS frameworks.
38251  *
38252  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
38253  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
38254  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
38255  *
38256  * ### Overriding `.ng-hide`
38257  *
38258  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
38259  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
38260  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
38261  * with extra animation classes that can be added.
38262  *
38263  * ```css
38264  * .ng-hide:not(.ng-hide-animate) {
38265  *   /&#42; this is just another form of hiding an element &#42;/
38266  *   display: block!important;
38267  *   position: absolute;
38268  *   top: -9999px;
38269  *   left: -9999px;
38270  * }
38271  * ```
38272  *
38273  * By default you don't need to override in CSS anything and the animations will work around the display style.
38274  *
38275  * ## A note about animations with `ngShow`
38276  *
38277  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
38278  * is true and false. This system works like the animation system present with ngClass except that
38279  * you must also include the !important flag to override the display property
38280  * so that you can perform an animation when the element is hidden during the time of the animation.
38281  *
38282  * ```css
38283  * //
38284  * //a working example can be found at the bottom of this page
38285  * //
38286  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
38287  *   /&#42; this is required as of 1.3x to properly
38288  *      apply all styling in a show/hide animation &#42;/
38289  *   transition: 0s linear all;
38290  * }
38291  *
38292  * .my-element.ng-hide-add-active,
38293  * .my-element.ng-hide-remove-active {
38294  *   /&#42; the transition is defined in the active class &#42;/
38295  *   transition: 1s linear all;
38296  * }
38297  *
38298  * .my-element.ng-hide-add { ... }
38299  * .my-element.ng-hide-add.ng-hide-add-active { ... }
38300  * .my-element.ng-hide-remove { ... }
38301  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
38302  * ```
38303  *
38304  * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
38305  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
38306  *
38307  * @animations
38308  * | Animation                        | Occurs                              |
38309  * |----------------------------------|-------------------------------------|
38310  * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden |
38311  * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngShow` expression evaluates to a truthy value and just before contents are set to visible |
38312  *
38313  * @element ANY
38314  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
38315  *     then the element is shown or hidden respectively.
38316  *
38317  * @example
38318   <example module="ngAnimate" deps="angular-animate.js" animations="true">
38319     <file name="index.html">
38320       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
38321       <div>
38322         Show:
38323         <div class="check-element animate-show" ng-show="checked">
38324           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
38325         </div>
38326       </div>
38327       <div>
38328         Hide:
38329         <div class="check-element animate-show" ng-hide="checked">
38330           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
38331         </div>
38332       </div>
38333     </file>
38334     <file name="glyphicons.css">
38335       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
38336     </file>
38337     <file name="animations.css">
38338       .animate-show {
38339         line-height: 20px;
38340         opacity: 1;
38341         padding: 10px;
38342         border: 1px solid black;
38343         background: white;
38344       }
38345
38346       .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
38347         transition: all linear 0.5s;
38348       }
38349
38350       .animate-show.ng-hide {
38351         line-height: 0;
38352         opacity: 0;
38353         padding: 0 10px;
38354       }
38355
38356       .check-element {
38357         padding: 10px;
38358         border: 1px solid black;
38359         background: white;
38360       }
38361     </file>
38362     <file name="protractor.js" type="protractor">
38363       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
38364       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
38365
38366       it('should check ng-show / ng-hide', function() {
38367         expect(thumbsUp.isDisplayed()).toBeFalsy();
38368         expect(thumbsDown.isDisplayed()).toBeTruthy();
38369
38370         element(by.model('checked')).click();
38371
38372         expect(thumbsUp.isDisplayed()).toBeTruthy();
38373         expect(thumbsDown.isDisplayed()).toBeFalsy();
38374       });
38375     </file>
38376   </example>
38377  */
38378 var ngShowDirective = ['$animate', function($animate) {
38379   return {
38380     restrict: 'A',
38381     multiElement: true,
38382     link: function(scope, element, attr) {
38383       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
38384         // we're adding a temporary, animation-specific class for ng-hide since this way
38385         // we can control when the element is actually displayed on screen without having
38386         // to have a global/greedy CSS selector that breaks when other animations are run.
38387         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
38388         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
38389           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
38390         });
38391       });
38392     }
38393   };
38394 }];
38395
38396
38397 /**
38398  * @ngdoc directive
38399  * @name ngHide
38400  * @multiElement
38401  *
38402  * @description
38403  * The `ngHide` directive shows or hides the given HTML element based on the expression
38404  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
38405  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
38406  * in AngularJS and sets the display style to none (using an !important flag).
38407  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
38408  *
38409  * ```html
38410  * <!-- when $scope.myValue is truthy (element is hidden) -->
38411  * <div ng-hide="myValue" class="ng-hide"></div>
38412  *
38413  * <!-- when $scope.myValue is falsy (element is visible) -->
38414  * <div ng-hide="myValue"></div>
38415  * ```
38416  *
38417  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
38418  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
38419  * from the element causing the element not to appear hidden.
38420  *
38421  * ## Why is !important used?
38422  *
38423  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
38424  * can be easily overridden by heavier selectors. For example, something as simple
38425  * as changing the display style on a HTML list item would make hidden elements appear visible.
38426  * This also becomes a bigger issue when dealing with CSS frameworks.
38427  *
38428  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
38429  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
38430  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
38431  *
38432  * ### Overriding `.ng-hide`
38433  *
38434  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
38435  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
38436  * class in CSS:
38437  *
38438  * ```css
38439  * .ng-hide {
38440  *   /&#42; this is just another form of hiding an element &#42;/
38441  *   display: block!important;
38442  *   position: absolute;
38443  *   top: -9999px;
38444  *   left: -9999px;
38445  * }
38446  * ```
38447  *
38448  * By default you don't need to override in CSS anything and the animations will work around the display style.
38449  *
38450  * ## A note about animations with `ngHide`
38451  *
38452  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
38453  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
38454  * CSS class is added and removed for you instead of your own CSS class.
38455  *
38456  * ```css
38457  * //
38458  * //a working example can be found at the bottom of this page
38459  * //
38460  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
38461  *   transition: 0.5s linear all;
38462  * }
38463  *
38464  * .my-element.ng-hide-add { ... }
38465  * .my-element.ng-hide-add.ng-hide-add-active { ... }
38466  * .my-element.ng-hide-remove { ... }
38467  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
38468  * ```
38469  *
38470  * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display
38471  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
38472  *
38473  * @animations
38474  * | Animation                        | Occurs                              |
38475  * |----------------------------------|-------------------------------------|
38476  * | {@link $animate#addClass addClass} `.ng-hide`  | after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden |
38477  * | {@link $animate#removeClass removeClass}  `.ng-hide`  | after the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible |
38478  *
38479  *
38480  * @element ANY
38481  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
38482  *     the element is shown or hidden respectively.
38483  *
38484  * @example
38485   <example module="ngAnimate" deps="angular-animate.js" animations="true">
38486     <file name="index.html">
38487       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
38488       <div>
38489         Show:
38490         <div class="check-element animate-hide" ng-show="checked">
38491           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
38492         </div>
38493       </div>
38494       <div>
38495         Hide:
38496         <div class="check-element animate-hide" ng-hide="checked">
38497           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
38498         </div>
38499       </div>
38500     </file>
38501     <file name="glyphicons.css">
38502       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
38503     </file>
38504     <file name="animations.css">
38505       .animate-hide {
38506         transition: all linear 0.5s;
38507         line-height: 20px;
38508         opacity: 1;
38509         padding: 10px;
38510         border: 1px solid black;
38511         background: white;
38512       }
38513
38514       .animate-hide.ng-hide {
38515         line-height: 0;
38516         opacity: 0;
38517         padding: 0 10px;
38518       }
38519
38520       .check-element {
38521         padding: 10px;
38522         border: 1px solid black;
38523         background: white;
38524       }
38525     </file>
38526     <file name="protractor.js" type="protractor">
38527       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
38528       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
38529
38530       it('should check ng-show / ng-hide', function() {
38531         expect(thumbsUp.isDisplayed()).toBeFalsy();
38532         expect(thumbsDown.isDisplayed()).toBeTruthy();
38533
38534         element(by.model('checked')).click();
38535
38536         expect(thumbsUp.isDisplayed()).toBeTruthy();
38537         expect(thumbsDown.isDisplayed()).toBeFalsy();
38538       });
38539     </file>
38540   </example>
38541  */
38542 var ngHideDirective = ['$animate', function($animate) {
38543   return {
38544     restrict: 'A',
38545     multiElement: true,
38546     link: function(scope, element, attr) {
38547       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
38548         // The comment inside of the ngShowDirective explains why we add and
38549         // remove a temporary class for the show/hide animation
38550         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
38551           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
38552         });
38553       });
38554     }
38555   };
38556 }];
38557
38558 /**
38559  * @ngdoc directive
38560  * @name ngStyle
38561  * @restrict AC
38562  *
38563  * @description
38564  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
38565  *
38566  * @element ANY
38567  * @param {expression} ngStyle
38568  *
38569  * {@link guide/expression Expression} which evals to an
38570  * object whose keys are CSS style names and values are corresponding values for those CSS
38571  * keys.
38572  *
38573  * Since some CSS style names are not valid keys for an object, they must be quoted.
38574  * See the 'background-color' style in the example below.
38575  *
38576  * @example
38577    <example>
38578      <file name="index.html">
38579         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
38580         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
38581         <input type="button" value="clear" ng-click="myStyle={}">
38582         <br/>
38583         <span ng-style="myStyle">Sample Text</span>
38584         <pre>myStyle={{myStyle}}</pre>
38585      </file>
38586      <file name="style.css">
38587        span {
38588          color: black;
38589        }
38590      </file>
38591      <file name="protractor.js" type="protractor">
38592        var colorSpan = element(by.css('span'));
38593
38594        it('should check ng-style', function() {
38595          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
38596          element(by.css('input[value=\'set color\']')).click();
38597          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
38598          element(by.css('input[value=clear]')).click();
38599          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
38600        });
38601      </file>
38602    </example>
38603  */
38604 var ngStyleDirective = ngDirective(function(scope, element, attr) {
38605   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
38606     if (oldStyles && (newStyles !== oldStyles)) {
38607       forEach(oldStyles, function(val, style) { element.css(style, '');});
38608     }
38609     if (newStyles) element.css(newStyles);
38610   }, true);
38611 });
38612
38613 /**
38614  * @ngdoc directive
38615  * @name ngSwitch
38616  * @restrict EA
38617  *
38618  * @description
38619  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
38620  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
38621  * as specified in the template.
38622  *
38623  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
38624  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
38625  * matches the value obtained from the evaluated expression. In other words, you define a container element
38626  * (where you place the directive), place an expression on the **`on="..."` attribute**
38627  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
38628  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
38629  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
38630  * attribute is displayed.
38631  *
38632  * <div class="alert alert-info">
38633  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
38634  * as literal string values to match against.
38635  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
38636  * value of the expression `$scope.someVal`.
38637  * </div>
38638
38639  * @animations
38640  * | Animation                        | Occurs                              |
38641  * |----------------------------------|-------------------------------------|
38642  * | {@link ng.$animate#enter enter}  | after the ngSwitch contents change and the matched child element is placed inside the container |
38643  * | {@link ng.$animate#leave leave}  | after the ngSwitch contents change and just before the former contents are removed from the DOM |
38644  *
38645  * @usage
38646  *
38647  * ```
38648  * <ANY ng-switch="expression">
38649  *   <ANY ng-switch-when="matchValue1">...</ANY>
38650  *   <ANY ng-switch-when="matchValue2">...</ANY>
38651  *   <ANY ng-switch-default>...</ANY>
38652  * </ANY>
38653  * ```
38654  *
38655  *
38656  * @scope
38657  * @priority 1200
38658  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
38659  * On child elements add:
38660  *
38661  * * `ngSwitchWhen`: the case statement to match against. If match then this
38662  *   case will be displayed. If the same match appears multiple times, all the
38663  *   elements will be displayed.
38664  * * `ngSwitchDefault`: the default case when no other case match. If there
38665  *   are multiple default cases, all of them will be displayed when no other
38666  *   case match.
38667  *
38668  *
38669  * @example
38670   <example module="switchExample" deps="angular-animate.js" animations="true">
38671     <file name="index.html">
38672       <div ng-controller="ExampleController">
38673         <select ng-model="selection" ng-options="item for item in items">
38674         </select>
38675         <code>selection={{selection}}</code>
38676         <hr/>
38677         <div class="animate-switch-container"
38678           ng-switch on="selection">
38679             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
38680             <div class="animate-switch" ng-switch-when="home">Home Span</div>
38681             <div class="animate-switch" ng-switch-default>default</div>
38682         </div>
38683       </div>
38684     </file>
38685     <file name="script.js">
38686       angular.module('switchExample', ['ngAnimate'])
38687         .controller('ExampleController', ['$scope', function($scope) {
38688           $scope.items = ['settings', 'home', 'other'];
38689           $scope.selection = $scope.items[0];
38690         }]);
38691     </file>
38692     <file name="animations.css">
38693       .animate-switch-container {
38694         position:relative;
38695         background:white;
38696         border:1px solid black;
38697         height:40px;
38698         overflow:hidden;
38699       }
38700
38701       .animate-switch {
38702         padding:10px;
38703       }
38704
38705       .animate-switch.ng-animate {
38706         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
38707
38708         position:absolute;
38709         top:0;
38710         left:0;
38711         right:0;
38712         bottom:0;
38713       }
38714
38715       .animate-switch.ng-leave.ng-leave-active,
38716       .animate-switch.ng-enter {
38717         top:-50px;
38718       }
38719       .animate-switch.ng-leave,
38720       .animate-switch.ng-enter.ng-enter-active {
38721         top:0;
38722       }
38723     </file>
38724     <file name="protractor.js" type="protractor">
38725       var switchElem = element(by.css('[ng-switch]'));
38726       var select = element(by.model('selection'));
38727
38728       it('should start in settings', function() {
38729         expect(switchElem.getText()).toMatch(/Settings Div/);
38730       });
38731       it('should change to home', function() {
38732         select.all(by.css('option')).get(1).click();
38733         expect(switchElem.getText()).toMatch(/Home Span/);
38734       });
38735       it('should select default', function() {
38736         select.all(by.css('option')).get(2).click();
38737         expect(switchElem.getText()).toMatch(/default/);
38738       });
38739     </file>
38740   </example>
38741  */
38742 var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
38743   return {
38744     require: 'ngSwitch',
38745
38746     // asks for $scope to fool the BC controller module
38747     controller: ['$scope', function ngSwitchController() {
38748      this.cases = {};
38749     }],
38750     link: function(scope, element, attr, ngSwitchController) {
38751       var watchExpr = attr.ngSwitch || attr.on,
38752           selectedTranscludes = [],
38753           selectedElements = [],
38754           previousLeaveAnimations = [],
38755           selectedScopes = [];
38756
38757       var spliceFactory = function(array, index) {
38758           return function() { array.splice(index, 1); };
38759       };
38760
38761       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
38762         var i, ii;
38763         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
38764           $animate.cancel(previousLeaveAnimations[i]);
38765         }
38766         previousLeaveAnimations.length = 0;
38767
38768         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
38769           var selected = getBlockNodes(selectedElements[i].clone);
38770           selectedScopes[i].$destroy();
38771           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
38772           promise.then(spliceFactory(previousLeaveAnimations, i));
38773         }
38774
38775         selectedElements.length = 0;
38776         selectedScopes.length = 0;
38777
38778         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
38779           forEach(selectedTranscludes, function(selectedTransclude) {
38780             selectedTransclude.transclude(function(caseElement, selectedScope) {
38781               selectedScopes.push(selectedScope);
38782               var anchor = selectedTransclude.element;
38783               caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
38784               var block = { clone: caseElement };
38785
38786               selectedElements.push(block);
38787               $animate.enter(caseElement, anchor.parent(), anchor);
38788             });
38789           });
38790         }
38791       });
38792     }
38793   };
38794 }];
38795
38796 var ngSwitchWhenDirective = ngDirective({
38797   transclude: 'element',
38798   priority: 1200,
38799   require: '^ngSwitch',
38800   multiElement: true,
38801   link: function(scope, element, attrs, ctrl, $transclude) {
38802     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
38803     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
38804   }
38805 });
38806
38807 var ngSwitchDefaultDirective = ngDirective({
38808   transclude: 'element',
38809   priority: 1200,
38810   require: '^ngSwitch',
38811   multiElement: true,
38812   link: function(scope, element, attr, ctrl, $transclude) {
38813     ctrl.cases['?'] = (ctrl.cases['?'] || []);
38814     ctrl.cases['?'].push({ transclude: $transclude, element: element });
38815    }
38816 });
38817
38818 /**
38819  * @ngdoc directive
38820  * @name ngTransclude
38821  * @restrict EAC
38822  *
38823  * @description
38824  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
38825  *
38826  * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
38827  * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
38828  *
38829  * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
38830  * content of this element will be removed before the transcluded content is inserted.
38831  * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
38832  * that no transcluded content is provided.
38833  *
38834  * @element ANY
38835  *
38836  * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
38837  *                                               or its value is the same as the name of the attribute then the default slot is used.
38838  *
38839  * @example
38840  * ### Basic transclusion
38841  * This example demonstrates basic transclusion of content into a component directive.
38842  * <example name="simpleTranscludeExample" module="transcludeExample">
38843  *   <file name="index.html">
38844  *     <script>
38845  *       angular.module('transcludeExample', [])
38846  *        .directive('pane', function(){
38847  *           return {
38848  *             restrict: 'E',
38849  *             transclude: true,
38850  *             scope: { title:'@' },
38851  *             template: '<div style="border: 1px solid black;">' +
38852  *                         '<div style="background-color: gray">{{title}}</div>' +
38853  *                         '<ng-transclude></ng-transclude>' +
38854  *                       '</div>'
38855  *           };
38856  *       })
38857  *       .controller('ExampleController', ['$scope', function($scope) {
38858  *         $scope.title = 'Lorem Ipsum';
38859  *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38860  *       }]);
38861  *     </script>
38862  *     <div ng-controller="ExampleController">
38863  *       <input ng-model="title" aria-label="title"> <br/>
38864  *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
38865  *       <pane title="{{title}}">{{text}}</pane>
38866  *     </div>
38867  *   </file>
38868  *   <file name="protractor.js" type="protractor">
38869  *      it('should have transcluded', function() {
38870  *        var titleElement = element(by.model('title'));
38871  *        titleElement.clear();
38872  *        titleElement.sendKeys('TITLE');
38873  *        var textElement = element(by.model('text'));
38874  *        textElement.clear();
38875  *        textElement.sendKeys('TEXT');
38876  *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
38877  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
38878  *      });
38879  *   </file>
38880  * </example>
38881  *
38882  * @example
38883  * ### Transclude fallback content
38884  * This example shows how to use `NgTransclude` with fallback content, that
38885  * is displayed if no transcluded content is provided.
38886  *
38887  * <example module="transcludeFallbackContentExample">
38888  * <file name="index.html">
38889  * <script>
38890  * angular.module('transcludeFallbackContentExample', [])
38891  * .directive('myButton', function(){
38892  *             return {
38893  *               restrict: 'E',
38894  *               transclude: true,
38895  *               scope: true,
38896  *               template: '<button style="cursor: pointer;">' +
38897  *                           '<ng-transclude>' +
38898  *                             '<b style="color: red;">Button1</b>' +
38899  *                           '</ng-transclude>' +
38900  *                         '</button>'
38901  *             };
38902  *         });
38903  * </script>
38904  * <!-- fallback button content -->
38905  * <my-button id="fallback"></my-button>
38906  * <!-- modified button content -->
38907  * <my-button id="modified">
38908  *   <i style="color: green;">Button2</i>
38909  * </my-button>
38910  * </file>
38911  * <file name="protractor.js" type="protractor">
38912  * it('should have different transclude element content', function() {
38913  *          expect(element(by.id('fallback')).getText()).toBe('Button1');
38914  *          expect(element(by.id('modified')).getText()).toBe('Button2');
38915  *        });
38916  * </file>
38917  * </example>
38918  *
38919  * @example
38920  * ### Multi-slot transclusion
38921  * This example demonstrates using multi-slot transclusion in a component directive.
38922  * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
38923  *   <file name="index.html">
38924  *    <style>
38925  *      .title, .footer {
38926  *        background-color: gray
38927  *      }
38928  *    </style>
38929  *    <div ng-controller="ExampleController">
38930  *      <input ng-model="title" aria-label="title"> <br/>
38931  *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
38932  *      <pane>
38933  *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
38934  *        <pane-body><p>{{text}}</p></pane-body>
38935  *      </pane>
38936  *    </div>
38937  *   </file>
38938  *   <file name="app.js">
38939  *    angular.module('multiSlotTranscludeExample', [])
38940  *     .directive('pane', function(){
38941  *        return {
38942  *          restrict: 'E',
38943  *          transclude: {
38944  *            'title': '?paneTitle',
38945  *            'body': 'paneBody',
38946  *            'footer': '?paneFooter'
38947  *          },
38948  *          template: '<div style="border: 1px solid black;">' +
38949  *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
38950  *                      '<div ng-transclude="body"></div>' +
38951  *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
38952  *                    '</div>'
38953  *        };
38954  *    })
38955  *    .controller('ExampleController', ['$scope', function($scope) {
38956  *      $scope.title = 'Lorem Ipsum';
38957  *      $scope.link = "https://google.com";
38958  *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38959  *    }]);
38960  *   </file>
38961  *   <file name="protractor.js" type="protractor">
38962  *      it('should have transcluded the title and the body', function() {
38963  *        var titleElement = element(by.model('title'));
38964  *        titleElement.clear();
38965  *        titleElement.sendKeys('TITLE');
38966  *        var textElement = element(by.model('text'));
38967  *        textElement.clear();
38968  *        textElement.sendKeys('TEXT');
38969  *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
38970  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
38971  *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
38972  *      });
38973  *   </file>
38974  * </example>
38975  */
38976 var ngTranscludeMinErr = minErr('ngTransclude');
38977 var ngTranscludeDirective = ngDirective({
38978   restrict: 'EAC',
38979   link: function($scope, $element, $attrs, controller, $transclude) {
38980
38981     if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
38982       // If the attribute is of the form: `ng-transclude="ng-transclude"`
38983       // then treat it like the default
38984       $attrs.ngTransclude = '';
38985     }
38986
38987     function ngTranscludeCloneAttachFn(clone) {
38988       if (clone.length) {
38989         $element.empty();
38990         $element.append(clone);
38991       }
38992     }
38993
38994     if (!$transclude) {
38995       throw ngTranscludeMinErr('orphan',
38996        'Illegal use of ngTransclude directive in the template! ' +
38997        'No parent directive that requires a transclusion found. ' +
38998        'Element: {0}',
38999        startingTag($element));
39000     }
39001
39002     // If there is no slot name defined or the slot name is not optional
39003     // then transclude the slot
39004     var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
39005     $transclude(ngTranscludeCloneAttachFn, null, slotName);
39006   }
39007 });
39008
39009 /**
39010  * @ngdoc directive
39011  * @name script
39012  * @restrict E
39013  *
39014  * @description
39015  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
39016  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
39017  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
39018  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
39019  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
39020  *
39021  * @param {string} type Must be set to `'text/ng-template'`.
39022  * @param {string} id Cache name of the template.
39023  *
39024  * @example
39025   <example>
39026     <file name="index.html">
39027       <script type="text/ng-template" id="/tpl.html">
39028         Content of the template.
39029       </script>
39030
39031       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
39032       <div id="tpl-content" ng-include src="currentTpl"></div>
39033     </file>
39034     <file name="protractor.js" type="protractor">
39035       it('should load template defined inside script tag', function() {
39036         element(by.css('#tpl-link')).click();
39037         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
39038       });
39039     </file>
39040   </example>
39041  */
39042 var scriptDirective = ['$templateCache', function($templateCache) {
39043   return {
39044     restrict: 'E',
39045     terminal: true,
39046     compile: function(element, attr) {
39047       if (attr.type == 'text/ng-template') {
39048         var templateUrl = attr.id,
39049             text = element[0].text;
39050
39051         $templateCache.put(templateUrl, text);
39052       }
39053     }
39054   };
39055 }];
39056
39057 var noopNgModelController = { $setViewValue: noop, $render: noop };
39058
39059 function chromeHack(optionElement) {
39060   // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
39061   // Adding an <option selected="selected"> element to a <select required="required"> should
39062   // automatically select the new element
39063   if (optionElement[0].hasAttribute('selected')) {
39064     optionElement[0].selected = true;
39065   }
39066 }
39067
39068 /**
39069  * @ngdoc type
39070  * @name  select.SelectController
39071  * @description
39072  * The controller for the `<select>` directive. This provides support for reading
39073  * and writing the selected value(s) of the control and also coordinates dynamically
39074  * added `<option>` elements, perhaps by an `ngRepeat` directive.
39075  */
39076 var SelectController =
39077         ['$element', '$scope', function($element, $scope) {
39078
39079   var self = this,
39080       optionsMap = new HashMap();
39081
39082   // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
39083   self.ngModelCtrl = noopNgModelController;
39084
39085   // The "unknown" option is one that is prepended to the list if the viewValue
39086   // does not match any of the options. When it is rendered the value of the unknown
39087   // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
39088   //
39089   // We can't just jqLite('<option>') since jqLite is not smart enough
39090   // to create it in <select> and IE barfs otherwise.
39091   self.unknownOption = jqLite(window.document.createElement('option'));
39092   self.renderUnknownOption = function(val) {
39093     var unknownVal = '? ' + hashKey(val) + ' ?';
39094     self.unknownOption.val(unknownVal);
39095     $element.prepend(self.unknownOption);
39096     $element.val(unknownVal);
39097   };
39098
39099   $scope.$on('$destroy', function() {
39100     // disable unknown option so that we don't do work when the whole select is being destroyed
39101     self.renderUnknownOption = noop;
39102   });
39103
39104   self.removeUnknownOption = function() {
39105     if (self.unknownOption.parent()) self.unknownOption.remove();
39106   };
39107
39108
39109   // Read the value of the select control, the implementation of this changes depending
39110   // upon whether the select can have multiple values and whether ngOptions is at work.
39111   self.readValue = function readSingleValue() {
39112     self.removeUnknownOption();
39113     return $element.val();
39114   };
39115
39116
39117   // Write the value to the select control, the implementation of this changes depending
39118   // upon whether the select can have multiple values and whether ngOptions is at work.
39119   self.writeValue = function writeSingleValue(value) {
39120     if (self.hasOption(value)) {
39121       self.removeUnknownOption();
39122       $element.val(value);
39123       if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
39124     } else {
39125       if (value == null && self.emptyOption) {
39126         self.removeUnknownOption();
39127         $element.val('');
39128       } else {
39129         self.renderUnknownOption(value);
39130       }
39131     }
39132   };
39133
39134
39135   // Tell the select control that an option, with the given value, has been added
39136   self.addOption = function(value, element) {
39137     // Skip comment nodes, as they only pollute the `optionsMap`
39138     if (element[0].nodeType === NODE_TYPE_COMMENT) return;
39139
39140     assertNotHasOwnProperty(value, '"option value"');
39141     if (value === '') {
39142       self.emptyOption = element;
39143     }
39144     var count = optionsMap.get(value) || 0;
39145     optionsMap.put(value, count + 1);
39146     self.ngModelCtrl.$render();
39147     chromeHack(element);
39148   };
39149
39150   // Tell the select control that an option, with the given value, has been removed
39151   self.removeOption = function(value) {
39152     var count = optionsMap.get(value);
39153     if (count) {
39154       if (count === 1) {
39155         optionsMap.remove(value);
39156         if (value === '') {
39157           self.emptyOption = undefined;
39158         }
39159       } else {
39160         optionsMap.put(value, count - 1);
39161       }
39162     }
39163   };
39164
39165   // Check whether the select control has an option matching the given value
39166   self.hasOption = function(value) {
39167     return !!optionsMap.get(value);
39168   };
39169
39170
39171   self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
39172
39173     if (interpolateValueFn) {
39174       // The value attribute is interpolated
39175       var oldVal;
39176       optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
39177         if (isDefined(oldVal)) {
39178           self.removeOption(oldVal);
39179         }
39180         oldVal = newVal;
39181         self.addOption(newVal, optionElement);
39182       });
39183     } else if (interpolateTextFn) {
39184       // The text content is interpolated
39185       optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
39186         optionAttrs.$set('value', newVal);
39187         if (oldVal !== newVal) {
39188           self.removeOption(oldVal);
39189         }
39190         self.addOption(newVal, optionElement);
39191       });
39192     } else {
39193       // The value attribute is static
39194       self.addOption(optionAttrs.value, optionElement);
39195     }
39196
39197     optionElement.on('$destroy', function() {
39198       self.removeOption(optionAttrs.value);
39199       self.ngModelCtrl.$render();
39200     });
39201   };
39202 }];
39203
39204 /**
39205  * @ngdoc directive
39206  * @name select
39207  * @restrict E
39208  *
39209  * @description
39210  * HTML `SELECT` element with angular data-binding.
39211  *
39212  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
39213  * between the scope and the `<select>` control (including setting default values).
39214  * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
39215  * {@link ngOptions `ngOptions`} directives.
39216  *
39217  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
39218  * to the model identified by the `ngModel` directive. With static or repeated options, this is
39219  * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
39220  * If you want dynamic value attributes, you can use interpolation inside the value attribute.
39221  *
39222  * <div class="alert alert-warning">
39223  * Note that the value of a `select` directive used without `ngOptions` is always a string.
39224  * When the model needs to be bound to a non-string value, you must either explicitly convert it
39225  * using a directive (see example below) or use `ngOptions` to specify the set of options.
39226  * This is because an option element can only be bound to string values at present.
39227  * </div>
39228  *
39229  * If the viewValue of `ngModel` does not match any of the options, then the control
39230  * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
39231  *
39232  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
39233  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
39234  * option. See example below for demonstration.
39235  *
39236  * <div class="alert alert-info">
39237  * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
39238  * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
39239  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
39240  * comprehension expression, and additionally in reducing memory and increasing speed by not creating
39241  * a new scope for each repeated instance.
39242  * </div>
39243  *
39244  *
39245  * @param {string} ngModel Assignable angular expression to data-bind to.
39246  * @param {string=} name Property name of the form under which the control is published.
39247  * @param {string=} multiple Allows multiple options to be selected. The selected values will be
39248  *     bound to the model as an array.
39249  * @param {string=} required Sets `required` validation error key if the value is not entered.
39250  * @param {string=} ngRequired Adds required attribute and required validation constraint to
39251  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
39252  * when you want to data-bind to the required attribute.
39253  * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
39254  *    interaction with the select element.
39255  * @param {string=} ngOptions sets the options that the select is populated with and defines what is
39256  * set on the model on selection. See {@link ngOptions `ngOptions`}.
39257  *
39258  * @example
39259  * ### Simple `select` elements with static options
39260  *
39261  * <example name="static-select" module="staticSelect">
39262  * <file name="index.html">
39263  * <div ng-controller="ExampleController">
39264  *   <form name="myForm">
39265  *     <label for="singleSelect"> Single select: </label><br>
39266  *     <select name="singleSelect" ng-model="data.singleSelect">
39267  *       <option value="option-1">Option 1</option>
39268  *       <option value="option-2">Option 2</option>
39269  *     </select><br>
39270  *
39271  *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
39272  *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
39273  *       <option value="">---Please select---</option> <!-- not selected / blank option -->
39274  *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
39275  *       <option value="option-2">Option 2</option>
39276  *     </select><br>
39277  *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
39278  *     <tt>singleSelect = {{data.singleSelect}}</tt>
39279  *
39280  *     <hr>
39281  *     <label for="multipleSelect"> Multiple select: </label><br>
39282  *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
39283  *       <option value="option-1">Option 1</option>
39284  *       <option value="option-2">Option 2</option>
39285  *       <option value="option-3">Option 3</option>
39286  *     </select><br>
39287  *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
39288  *   </form>
39289  * </div>
39290  * </file>
39291  * <file name="app.js">
39292  *  angular.module('staticSelect', [])
39293  *    .controller('ExampleController', ['$scope', function($scope) {
39294  *      $scope.data = {
39295  *       singleSelect: null,
39296  *       multipleSelect: [],
39297  *       option1: 'option-1',
39298  *      };
39299  *
39300  *      $scope.forceUnknownOption = function() {
39301  *        $scope.data.singleSelect = 'nonsense';
39302  *      };
39303  *   }]);
39304  * </file>
39305  *</example>
39306  *
39307  * ### Using `ngRepeat` to generate `select` options
39308  * <example name="ngrepeat-select" module="ngrepeatSelect">
39309  * <file name="index.html">
39310  * <div ng-controller="ExampleController">
39311  *   <form name="myForm">
39312  *     <label for="repeatSelect"> Repeat select: </label>
39313  *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
39314  *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
39315  *     </select>
39316  *   </form>
39317  *   <hr>
39318  *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
39319  * </div>
39320  * </file>
39321  * <file name="app.js">
39322  *  angular.module('ngrepeatSelect', [])
39323  *    .controller('ExampleController', ['$scope', function($scope) {
39324  *      $scope.data = {
39325  *       repeatSelect: null,
39326  *       availableOptions: [
39327  *         {id: '1', name: 'Option A'},
39328  *         {id: '2', name: 'Option B'},
39329  *         {id: '3', name: 'Option C'}
39330  *       ],
39331  *      };
39332  *   }]);
39333  * </file>
39334  *</example>
39335  *
39336  *
39337  * ### Using `select` with `ngOptions` and setting a default value
39338  * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
39339  *
39340  * <example name="select-with-default-values" module="defaultValueSelect">
39341  * <file name="index.html">
39342  * <div ng-controller="ExampleController">
39343  *   <form name="myForm">
39344  *     <label for="mySelect">Make a choice:</label>
39345  *     <select name="mySelect" id="mySelect"
39346  *       ng-options="option.name for option in data.availableOptions track by option.id"
39347  *       ng-model="data.selectedOption"></select>
39348  *   </form>
39349  *   <hr>
39350  *   <tt>option = {{data.selectedOption}}</tt><br/>
39351  * </div>
39352  * </file>
39353  * <file name="app.js">
39354  *  angular.module('defaultValueSelect', [])
39355  *    .controller('ExampleController', ['$scope', function($scope) {
39356  *      $scope.data = {
39357  *       availableOptions: [
39358  *         {id: '1', name: 'Option A'},
39359  *         {id: '2', name: 'Option B'},
39360  *         {id: '3', name: 'Option C'}
39361  *       ],
39362  *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
39363  *       };
39364  *   }]);
39365  * </file>
39366  *</example>
39367  *
39368  *
39369  * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
39370  *
39371  * <example name="select-with-non-string-options" module="nonStringSelect">
39372  *   <file name="index.html">
39373  *     <select ng-model="model.id" convert-to-number>
39374  *       <option value="0">Zero</option>
39375  *       <option value="1">One</option>
39376  *       <option value="2">Two</option>
39377  *     </select>
39378  *     {{ model }}
39379  *   </file>
39380  *   <file name="app.js">
39381  *     angular.module('nonStringSelect', [])
39382  *       .run(function($rootScope) {
39383  *         $rootScope.model = { id: 2 };
39384  *       })
39385  *       .directive('convertToNumber', function() {
39386  *         return {
39387  *           require: 'ngModel',
39388  *           link: function(scope, element, attrs, ngModel) {
39389  *             ngModel.$parsers.push(function(val) {
39390  *               return parseInt(val, 10);
39391  *             });
39392  *             ngModel.$formatters.push(function(val) {
39393  *               return '' + val;
39394  *             });
39395  *           }
39396  *         };
39397  *       });
39398  *   </file>
39399  *   <file name="protractor.js" type="protractor">
39400  *     it('should initialize to model', function() {
39401  *       var select = element(by.css('select'));
39402  *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
39403  *     });
39404  *   </file>
39405  * </example>
39406  *
39407  */
39408 var selectDirective = function() {
39409
39410   return {
39411     restrict: 'E',
39412     require: ['select', '?ngModel'],
39413     controller: SelectController,
39414     priority: 1,
39415     link: {
39416       pre: selectPreLink,
39417       post: selectPostLink
39418     }
39419   };
39420
39421   function selectPreLink(scope, element, attr, ctrls) {
39422
39423       // if ngModel is not defined, we don't need to do anything
39424       var ngModelCtrl = ctrls[1];
39425       if (!ngModelCtrl) return;
39426
39427       var selectCtrl = ctrls[0];
39428
39429       selectCtrl.ngModelCtrl = ngModelCtrl;
39430
39431       // When the selected item(s) changes we delegate getting the value of the select control
39432       // to the `readValue` method, which can be changed if the select can have multiple
39433       // selected values or if the options are being generated by `ngOptions`
39434       element.on('change', function() {
39435         scope.$apply(function() {
39436           ngModelCtrl.$setViewValue(selectCtrl.readValue());
39437         });
39438       });
39439
39440       // If the select allows multiple values then we need to modify how we read and write
39441       // values from and to the control; also what it means for the value to be empty and
39442       // we have to add an extra watch since ngModel doesn't work well with arrays - it
39443       // doesn't trigger rendering if only an item in the array changes.
39444       if (attr.multiple) {
39445
39446         // Read value now needs to check each option to see if it is selected
39447         selectCtrl.readValue = function readMultipleValue() {
39448           var array = [];
39449           forEach(element.find('option'), function(option) {
39450             if (option.selected) {
39451               array.push(option.value);
39452             }
39453           });
39454           return array;
39455         };
39456
39457         // Write value now needs to set the selected property of each matching option
39458         selectCtrl.writeValue = function writeMultipleValue(value) {
39459           var items = new HashMap(value);
39460           forEach(element.find('option'), function(option) {
39461             option.selected = isDefined(items.get(option.value));
39462           });
39463         };
39464
39465         // we have to do it on each watch since ngModel watches reference, but
39466         // we need to work of an array, so we need to see if anything was inserted/removed
39467         var lastView, lastViewRef = NaN;
39468         scope.$watch(function selectMultipleWatch() {
39469           if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
39470             lastView = shallowCopy(ngModelCtrl.$viewValue);
39471             ngModelCtrl.$render();
39472           }
39473           lastViewRef = ngModelCtrl.$viewValue;
39474         });
39475
39476         // If we are a multiple select then value is now a collection
39477         // so the meaning of $isEmpty changes
39478         ngModelCtrl.$isEmpty = function(value) {
39479           return !value || value.length === 0;
39480         };
39481
39482       }
39483     }
39484
39485     function selectPostLink(scope, element, attrs, ctrls) {
39486       // if ngModel is not defined, we don't need to do anything
39487       var ngModelCtrl = ctrls[1];
39488       if (!ngModelCtrl) return;
39489
39490       var selectCtrl = ctrls[0];
39491
39492       // We delegate rendering to the `writeValue` method, which can be changed
39493       // if the select can have multiple selected values or if the options are being
39494       // generated by `ngOptions`.
39495       // This must be done in the postLink fn to prevent $render to be called before
39496       // all nodes have been linked correctly.
39497       ngModelCtrl.$render = function() {
39498         selectCtrl.writeValue(ngModelCtrl.$viewValue);
39499       };
39500     }
39501 };
39502
39503
39504 // The option directive is purely designed to communicate the existence (or lack of)
39505 // of dynamically created (and destroyed) option elements to their containing select
39506 // directive via its controller.
39507 var optionDirective = ['$interpolate', function($interpolate) {
39508   return {
39509     restrict: 'E',
39510     priority: 100,
39511     compile: function(element, attr) {
39512       if (isDefined(attr.value)) {
39513         // If the value attribute is defined, check if it contains an interpolation
39514         var interpolateValueFn = $interpolate(attr.value, true);
39515       } else {
39516         // If the value attribute is not defined then we fall back to the
39517         // text content of the option element, which may be interpolated
39518         var interpolateTextFn = $interpolate(element.text(), true);
39519         if (!interpolateTextFn) {
39520           attr.$set('value', element.text());
39521         }
39522       }
39523
39524       return function(scope, element, attr) {
39525         // This is an optimization over using ^^ since we don't want to have to search
39526         // all the way to the root of the DOM for every single option element
39527         var selectCtrlName = '$selectController',
39528             parent = element.parent(),
39529             selectCtrl = parent.data(selectCtrlName) ||
39530               parent.parent().data(selectCtrlName); // in case we are in optgroup
39531
39532         if (selectCtrl) {
39533           selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
39534         }
39535       };
39536     }
39537   };
39538 }];
39539
39540 var styleDirective = valueFn({
39541   restrict: 'E',
39542   terminal: false
39543 });
39544
39545 /**
39546  * @ngdoc directive
39547  * @name ngRequired
39548  *
39549  * @description
39550  *
39551  * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39552  * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
39553  * applied to custom controls.
39554  *
39555  * The directive sets the `required` attribute on the element if the Angular expression inside
39556  * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
39557  * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
39558  * for more info.
39559  *
39560  * The validator will set the `required` error key to true if the `required` attribute is set and
39561  * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
39562  * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
39563  * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
39564  * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
39565  *
39566  * @example
39567  * <example name="ngRequiredDirective" module="ngRequiredExample">
39568  *   <file name="index.html">
39569  *     <script>
39570  *       angular.module('ngRequiredExample', [])
39571  *         .controller('ExampleController', ['$scope', function($scope) {
39572  *           $scope.required = true;
39573  *         }]);
39574  *     </script>
39575  *     <div ng-controller="ExampleController">
39576  *       <form name="form">
39577  *         <label for="required">Toggle required: </label>
39578  *         <input type="checkbox" ng-model="required" id="required" />
39579  *         <br>
39580  *         <label for="input">This input must be filled if `required` is true: </label>
39581  *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
39582  *         <hr>
39583  *         required error set? = <code>{{form.input.$error.required}}</code><br>
39584  *         model = <code>{{model}}</code>
39585  *       </form>
39586  *     </div>
39587  *   </file>
39588  *   <file name="protractor.js" type="protractor">
39589        var required = element(by.binding('form.input.$error.required'));
39590        var model = element(by.binding('model'));
39591        var input = element(by.id('input'));
39592
39593        it('should set the required error', function() {
39594          expect(required.getText()).toContain('true');
39595
39596          input.sendKeys('123');
39597          expect(required.getText()).not.toContain('true');
39598          expect(model.getText()).toContain('123');
39599        });
39600  *   </file>
39601  * </example>
39602  */
39603 var requiredDirective = function() {
39604   return {
39605     restrict: 'A',
39606     require: '?ngModel',
39607     link: function(scope, elm, attr, ctrl) {
39608       if (!ctrl) return;
39609       attr.required = true; // force truthy in case we are on non input element
39610
39611       ctrl.$validators.required = function(modelValue, viewValue) {
39612         return !attr.required || !ctrl.$isEmpty(viewValue);
39613       };
39614
39615       attr.$observe('required', function() {
39616         ctrl.$validate();
39617       });
39618     }
39619   };
39620 };
39621
39622 /**
39623  * @ngdoc directive
39624  * @name ngPattern
39625  *
39626  * @description
39627  *
39628  * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39629  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39630  *
39631  * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39632  * does not match a RegExp which is obtained by evaluating the Angular expression given in the
39633  * `ngPattern` attribute value:
39634  * * If the expression evaluates to a RegExp object, then this is used directly.
39635  * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
39636  * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
39637  *
39638  * <div class="alert alert-info">
39639  * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
39640  * start at the index of the last search's match, thus not taking the whole input value into
39641  * account.
39642  * </div>
39643  *
39644  * <div class="alert alert-info">
39645  * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
39646  * differences:
39647  * <ol>
39648  *   <li>
39649  *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
39650  *     not available.
39651  *   </li>
39652  *   <li>
39653  *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
39654  *     interpolated.
39655  *   </li>
39656  * </ol>
39657  * </div>
39658  *
39659  * @example
39660  * <example name="ngPatternDirective" module="ngPatternExample">
39661  *   <file name="index.html">
39662  *     <script>
39663  *       angular.module('ngPatternExample', [])
39664  *         .controller('ExampleController', ['$scope', function($scope) {
39665  *           $scope.regex = '\\d+';
39666  *         }]);
39667  *     </script>
39668  *     <div ng-controller="ExampleController">
39669  *       <form name="form">
39670  *         <label for="regex">Set a pattern (regex string): </label>
39671  *         <input type="text" ng-model="regex" id="regex" />
39672  *         <br>
39673  *         <label for="input">This input is restricted by the current pattern: </label>
39674  *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
39675  *         <hr>
39676  *         input valid? = <code>{{form.input.$valid}}</code><br>
39677  *         model = <code>{{model}}</code>
39678  *       </form>
39679  *     </div>
39680  *   </file>
39681  *   <file name="protractor.js" type="protractor">
39682        var model = element(by.binding('model'));
39683        var input = element(by.id('input'));
39684
39685        it('should validate the input with the default pattern', function() {
39686          input.sendKeys('aaa');
39687          expect(model.getText()).not.toContain('aaa');
39688
39689          input.clear().then(function() {
39690            input.sendKeys('123');
39691            expect(model.getText()).toContain('123');
39692          });
39693        });
39694  *   </file>
39695  * </example>
39696  */
39697 var patternDirective = function() {
39698   return {
39699     restrict: 'A',
39700     require: '?ngModel',
39701     link: function(scope, elm, attr, ctrl) {
39702       if (!ctrl) return;
39703
39704       var regexp, patternExp = attr.ngPattern || attr.pattern;
39705       attr.$observe('pattern', function(regex) {
39706         if (isString(regex) && regex.length > 0) {
39707           regex = new RegExp('^' + regex + '$');
39708         }
39709
39710         if (regex && !regex.test) {
39711           throw minErr('ngPattern')('noregexp',
39712             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
39713             regex, startingTag(elm));
39714         }
39715
39716         regexp = regex || undefined;
39717         ctrl.$validate();
39718       });
39719
39720       ctrl.$validators.pattern = function(modelValue, viewValue) {
39721         // HTML5 pattern constraint validates the input value, so we validate the viewValue
39722         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
39723       };
39724     }
39725   };
39726 };
39727
39728 /**
39729  * @ngdoc directive
39730  * @name ngMaxlength
39731  *
39732  * @description
39733  *
39734  * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39735  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39736  *
39737  * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39738  * is longer than the integer obtained by evaluating the Angular expression given in the
39739  * `ngMaxlength` attribute value.
39740  *
39741  * <div class="alert alert-info">
39742  * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
39743  * differences:
39744  * <ol>
39745  *   <li>
39746  *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
39747  *     validation is not available.
39748  *   </li>
39749  *   <li>
39750  *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
39751  *     interpolated.
39752  *   </li>
39753  * </ol>
39754  * </div>
39755  *
39756  * @example
39757  * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
39758  *   <file name="index.html">
39759  *     <script>
39760  *       angular.module('ngMaxlengthExample', [])
39761  *         .controller('ExampleController', ['$scope', function($scope) {
39762  *           $scope.maxlength = 5;
39763  *         }]);
39764  *     </script>
39765  *     <div ng-controller="ExampleController">
39766  *       <form name="form">
39767  *         <label for="maxlength">Set a maxlength: </label>
39768  *         <input type="number" ng-model="maxlength" id="maxlength" />
39769  *         <br>
39770  *         <label for="input">This input is restricted by the current maxlength: </label>
39771  *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
39772  *         <hr>
39773  *         input valid? = <code>{{form.input.$valid}}</code><br>
39774  *         model = <code>{{model}}</code>
39775  *       </form>
39776  *     </div>
39777  *   </file>
39778  *   <file name="protractor.js" type="protractor">
39779        var model = element(by.binding('model'));
39780        var input = element(by.id('input'));
39781
39782        it('should validate the input with the default maxlength', function() {
39783          input.sendKeys('abcdef');
39784          expect(model.getText()).not.toContain('abcdef');
39785
39786          input.clear().then(function() {
39787            input.sendKeys('abcde');
39788            expect(model.getText()).toContain('abcde');
39789          });
39790        });
39791  *   </file>
39792  * </example>
39793  */
39794 var maxlengthDirective = function() {
39795   return {
39796     restrict: 'A',
39797     require: '?ngModel',
39798     link: function(scope, elm, attr, ctrl) {
39799       if (!ctrl) return;
39800
39801       var maxlength = -1;
39802       attr.$observe('maxlength', function(value) {
39803         var intVal = toInt(value);
39804         maxlength = isNaN(intVal) ? -1 : intVal;
39805         ctrl.$validate();
39806       });
39807       ctrl.$validators.maxlength = function(modelValue, viewValue) {
39808         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
39809       };
39810     }
39811   };
39812 };
39813
39814 /**
39815  * @ngdoc directive
39816  * @name ngMinlength
39817  *
39818  * @description
39819  *
39820  * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39821  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39822  *
39823  * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39824  * is shorter than the integer obtained by evaluating the Angular expression given in the
39825  * `ngMinlength` attribute value.
39826  *
39827  * <div class="alert alert-info">
39828  * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
39829  * differences:
39830  * <ol>
39831  *   <li>
39832  *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
39833  *     validation is not available.
39834  *   </li>
39835  *   <li>
39836  *     The `ngMinlength` value must be an expression, while the `minlength` value must be
39837  *     interpolated.
39838  *   </li>
39839  * </ol>
39840  * </div>
39841  *
39842  * @example
39843  * <example name="ngMinlengthDirective" module="ngMinlengthExample">
39844  *   <file name="index.html">
39845  *     <script>
39846  *       angular.module('ngMinlengthExample', [])
39847  *         .controller('ExampleController', ['$scope', function($scope) {
39848  *           $scope.minlength = 3;
39849  *         }]);
39850  *     </script>
39851  *     <div ng-controller="ExampleController">
39852  *       <form name="form">
39853  *         <label for="minlength">Set a minlength: </label>
39854  *         <input type="number" ng-model="minlength" id="minlength" />
39855  *         <br>
39856  *         <label for="input">This input is restricted by the current minlength: </label>
39857  *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
39858  *         <hr>
39859  *         input valid? = <code>{{form.input.$valid}}</code><br>
39860  *         model = <code>{{model}}</code>
39861  *       </form>
39862  *     </div>
39863  *   </file>
39864  *   <file name="protractor.js" type="protractor">
39865        var model = element(by.binding('model'));
39866        var input = element(by.id('input'));
39867
39868        it('should validate the input with the default minlength', function() {
39869          input.sendKeys('ab');
39870          expect(model.getText()).not.toContain('ab');
39871
39872          input.sendKeys('abc');
39873          expect(model.getText()).toContain('abc');
39874        });
39875  *   </file>
39876  * </example>
39877  */
39878 var minlengthDirective = function() {
39879   return {
39880     restrict: 'A',
39881     require: '?ngModel',
39882     link: function(scope, elm, attr, ctrl) {
39883       if (!ctrl) return;
39884
39885       var minlength = 0;
39886       attr.$observe('minlength', function(value) {
39887         minlength = toInt(value) || 0;
39888         ctrl.$validate();
39889       });
39890       ctrl.$validators.minlength = function(modelValue, viewValue) {
39891         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
39892       };
39893     }
39894   };
39895 };
39896
39897 if (window.angular.bootstrap) {
39898   //AngularJS is already loaded, so we can return here...
39899   if (window.console) {
39900     console.log('WARNING: Tried to load angular more than once.');
39901   }
39902   return;
39903 }
39904
39905 //try to bind to jquery now so that one can write jqLite(document).ready()
39906 //but we will rebind on bootstrap again.
39907 bindJQuery();
39908
39909 publishExternalAPI(angular);
39910
39911 angular.module("ngLocale", [], ["$provide", function($provide) {
39912 var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
39913 function getDecimals(n) {
39914   n = n + '';
39915   var i = n.indexOf('.');
39916   return (i == -1) ? 0 : n.length - i - 1;
39917 }
39918
39919 function getVF(n, opt_precision) {
39920   var v = opt_precision;
39921
39922   if (undefined === v) {
39923     v = Math.min(getDecimals(n), 3);
39924   }
39925
39926   var base = Math.pow(10, v);
39927   var f = ((n * base) | 0) % base;
39928   return {v: v, f: f};
39929 }
39930
39931 $provide.value("$locale", {
39932   "DATETIME_FORMATS": {
39933     "AMPMS": [
39934       "AM",
39935       "PM"
39936     ],
39937     "DAY": [
39938       "Sunday",
39939       "Monday",
39940       "Tuesday",
39941       "Wednesday",
39942       "Thursday",
39943       "Friday",
39944       "Saturday"
39945     ],
39946     "ERANAMES": [
39947       "Before Christ",
39948       "Anno Domini"
39949     ],
39950     "ERAS": [
39951       "BC",
39952       "AD"
39953     ],
39954     "FIRSTDAYOFWEEK": 6,
39955     "MONTH": [
39956       "January",
39957       "February",
39958       "March",
39959       "April",
39960       "May",
39961       "June",
39962       "July",
39963       "August",
39964       "September",
39965       "October",
39966       "November",
39967       "December"
39968     ],
39969     "SHORTDAY": [
39970       "Sun",
39971       "Mon",
39972       "Tue",
39973       "Wed",
39974       "Thu",
39975       "Fri",
39976       "Sat"
39977     ],
39978     "SHORTMONTH": [
39979       "Jan",
39980       "Feb",
39981       "Mar",
39982       "Apr",
39983       "May",
39984       "Jun",
39985       "Jul",
39986       "Aug",
39987       "Sep",
39988       "Oct",
39989       "Nov",
39990       "Dec"
39991     ],
39992     "STANDALONEMONTH": [
39993       "January",
39994       "February",
39995       "March",
39996       "April",
39997       "May",
39998       "June",
39999       "July",
40000       "August",
40001       "September",
40002       "October",
40003       "November",
40004       "December"
40005     ],
40006     "WEEKENDRANGE": [
40007       5,
40008       6
40009     ],
40010     "fullDate": "EEEE, MMMM d, y",
40011     "longDate": "MMMM d, y",
40012     "medium": "MMM d, y h:mm:ss a",
40013     "mediumDate": "MMM d, y",
40014     "mediumTime": "h:mm:ss a",
40015     "short": "M/d/yy h:mm a",
40016     "shortDate": "M/d/yy",
40017     "shortTime": "h:mm a"
40018   },
40019   "NUMBER_FORMATS": {
40020     "CURRENCY_SYM": "$",
40021     "DECIMAL_SEP": ".",
40022     "GROUP_SEP": ",",
40023     "PATTERNS": [
40024       {
40025         "gSize": 3,
40026         "lgSize": 3,
40027         "maxFrac": 3,
40028         "minFrac": 0,
40029         "minInt": 1,
40030         "negPre": "-",
40031         "negSuf": "",
40032         "posPre": "",
40033         "posSuf": ""
40034       },
40035       {
40036         "gSize": 3,
40037         "lgSize": 3,
40038         "maxFrac": 2,
40039         "minFrac": 2,
40040         "minInt": 1,
40041         "negPre": "-\u00a4",
40042         "negSuf": "",
40043         "posPre": "\u00a4",
40044         "posSuf": ""
40045       }
40046     ]
40047   },
40048   "id": "en-us",
40049   "localeID": "en_US",
40050   "pluralCat": function(n, opt_precision) {  var i = n | 0;  var vf = getVF(n, opt_precision);  if (i == 1 && vf.v == 0) {    return PLURAL_CATEGORY.ONE;  }  return PLURAL_CATEGORY.OTHER;}
40051 });
40052 }]);
40053
40054 /**
40055  * Setup file for the Scenario.
40056  * Must be first in the compilation/bootstrap list.
40057  */
40058
40059 // Public namespace
40060 angular.scenario = angular.scenario || {};
40061
40062 /**
40063  * Expose jQuery (e.g. for custom dsl extensions).
40064  */
40065 angular.scenario.jQuery = _jQuery;
40066
40067 /**
40068  * Defines a new output format.
40069  *
40070  * @param {string} name the name of the new output format
40071  * @param {function()} fn function(context, runner) that generates the output
40072  */
40073 angular.scenario.output = angular.scenario.output || function(name, fn) {
40074   angular.scenario.output[name] = fn;
40075 };
40076
40077 /**
40078  * Defines a new DSL statement. If your factory function returns a Future
40079  * it's returned, otherwise the result is assumed to be a map of functions
40080  * for chaining. Chained functions are subject to the same rules.
40081  *
40082  * Note: All functions on the chain are bound to the chain scope so values
40083  *   set on "this" in your statement function are available in the chained
40084  *   functions.
40085  *
40086  * @param {string} name The name of the statement
40087  * @param {function()} fn Factory function(), return a function for
40088  *  the statement.
40089  */
40090 angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
40091   angular.scenario.dsl[name] = function() {
40092     /* jshint -W040 *//* The dsl binds `this` for us when calling chained functions */
40093     function executeStatement(statement, args) {
40094       var result = statement.apply(this, args);
40095       if (angular.isFunction(result) || result instanceof angular.scenario.Future) {
40096         return result;
40097       }
40098       var self = this;
40099       var chain = angular.extend({}, result);
40100       angular.forEach(chain, function(value, name) {
40101         if (angular.isFunction(value)) {
40102           chain[name] = function() {
40103             return executeStatement.call(self, value, arguments);
40104           };
40105         } else {
40106           chain[name] = value;
40107         }
40108       });
40109       return chain;
40110     }
40111     var statement = fn.apply(this, arguments);
40112     return function() {
40113       return executeStatement.call(this, statement, arguments);
40114     };
40115   };
40116 };
40117
40118 /**
40119  * Defines a new matcher for use with the expects() statement. The value
40120  * this.actual (like in Jasmine) is available in your matcher to compare
40121  * against. Your function should return a boolean. The future is automatically
40122  * created for you.
40123  *
40124  * @param {string} name The name of the matcher
40125  * @param {function()} fn The matching function(expected).
40126  */
40127 angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
40128   angular.scenario.matcher[name] = function(expected) {
40129     var description = this.future.name +
40130                       (this.inverse ? ' not ' : ' ') + name +
40131                       ' ' + angular.toJson(expected);
40132     var self = this;
40133     this.addFuture('expect ' + description,
40134       function(done) {
40135         var error;
40136         self.actual = self.future.value;
40137         if ((self.inverse && fn.call(self, expected)) ||
40138             (!self.inverse && !fn.call(self, expected))) {
40139           error = 'expected ' + description +
40140             ' but was ' + angular.toJson(self.actual);
40141         }
40142         done(error);
40143     });
40144   };
40145 };
40146
40147 /**
40148  * Initialize the scenario runner and run !
40149  *
40150  * Access global window and document object
40151  * Access $runner through closure
40152  *
40153  * @param {Object=} config Config options
40154  */
40155 angular.scenario.setUpAndRun = function(config) {
40156   var href = window.location.href;
40157   var body = _jQuery(window.document.body);
40158   var output = [];
40159   var objModel = new angular.scenario.ObjectModel($runner);
40160
40161   if (config && config.scenario_output) {
40162     output = config.scenario_output.split(',');
40163   }
40164
40165   angular.forEach(angular.scenario.output, function(fn, name) {
40166     if (!output.length || output.indexOf(name) != -1) {
40167       var context = body.append('<div></div>').find('div:last');
40168       context.attr('id', name);
40169       fn.call({}, context, $runner, objModel);
40170     }
40171   });
40172
40173   if (!/^http/.test(href) && !/^https/.test(href)) {
40174     body.append('<p id="system-error"></p>');
40175     body.find('#system-error').text(
40176       'Scenario runner must be run using http or https. The protocol ' +
40177       href.split(':')[0] + ':// is not supported.'
40178     );
40179     return;
40180   }
40181
40182   var appFrame = body.append('<div id="application"></div>').find('#application');
40183   var application = new angular.scenario.Application(appFrame);
40184
40185   $runner.on('RunnerEnd', function() {
40186     appFrame.css('display', 'none');
40187     appFrame.find('iframe').attr('src', 'about:blank');
40188   });
40189
40190   $runner.on('RunnerError', function(error) {
40191     if (window.console) {
40192       console.log(formatException(error));
40193     } else {
40194       // Do something for IE
40195       alert(error);
40196     }
40197   });
40198
40199   $runner.run(application);
40200 };
40201
40202 /**
40203  * Iterates through list with iterator function that must call the
40204  * continueFunction to continue iterating.
40205  *
40206  * @param {Array} list list to iterate over
40207  * @param {function()} iterator Callback function(value, continueFunction)
40208  * @param {function()} done Callback function(error, result) called when
40209  *   iteration finishes or an error occurs.
40210  */
40211 function asyncForEach(list, iterator, done) {
40212   var i = 0;
40213   function loop(error, index) {
40214     if (index && index > i) {
40215       i = index;
40216     }
40217     if (error || i >= list.length) {
40218       done(error);
40219     } else {
40220       try {
40221         iterator(list[i++], loop);
40222       } catch (e) {
40223         done(e);
40224       }
40225     }
40226   }
40227   loop();
40228 }
40229
40230 /**
40231  * Formats an exception into a string with the stack trace, but limits
40232  * to a specific line length.
40233  *
40234  * @param {Object} error The exception to format, can be anything throwable
40235  * @param {Number=} [maxStackLines=5] max lines of the stack trace to include
40236  *  default is 5.
40237  */
40238 function formatException(error, maxStackLines) {
40239   maxStackLines = maxStackLines || 5;
40240   var message = error.toString();
40241   if (error.stack) {
40242     var stack = error.stack.split('\n');
40243     if (stack[0].indexOf(message) === -1) {
40244       maxStackLines++;
40245       stack.unshift(error.message);
40246     }
40247     message = stack.slice(0, maxStackLines).join('\n');
40248   }
40249   return message;
40250 }
40251
40252 /**
40253  * Returns a function that gets the file name and line number from a
40254  * location in the stack if available based on the call site.
40255  *
40256  * Note: this returns another function because accessing .stack is very
40257  * expensive in Chrome.
40258  *
40259  * @param {Number} offset Number of stack lines to skip
40260  */
40261 function callerFile(offset) {
40262   var error = new Error();
40263
40264   return function() {
40265     var line = (error.stack || '').split('\n')[offset];
40266
40267     // Clean up the stack trace line
40268     if (line) {
40269       if (line.indexOf('@') !== -1) {
40270         // Firefox
40271         line = line.substring(line.indexOf('@') + 1);
40272       } else {
40273         // Chrome
40274         line = line.substring(line.indexOf('(') + 1).replace(')', '');
40275       }
40276     }
40277
40278     return line || '';
40279   };
40280 }
40281
40282
40283 /**
40284  * Don't use the jQuery trigger method since it works incorrectly.
40285  *
40286  * jQuery notifies listeners and then changes the state of a checkbox and
40287  * does not create a real browser event. A real click changes the state of
40288  * the checkbox and then notifies listeners.
40289  *
40290  * To work around this we instead use our own handler that fires a real event.
40291  */
40292 (function(fn) {
40293   // We need a handle to the original trigger function for input tests.
40294   var parentTrigger = fn._originalTrigger = fn.trigger;
40295   fn.trigger = function(type) {
40296     if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
40297       var processDefaults = [];
40298       this.each(function(index, node) {
40299         processDefaults.push(browserTrigger(node, type));
40300       });
40301
40302       // this is not compatible with jQuery - we return an array of returned values,
40303       // so that scenario runner know whether JS code has preventDefault() of the event or not...
40304       return processDefaults;
40305     }
40306     return parentTrigger.apply(this, arguments);
40307   };
40308 })(_jQuery.fn);
40309
40310 /**
40311  * Finds all bindings with the substring match of name and returns an
40312  * array of their values.
40313  *
40314  * @param {string} bindExp The name to match
40315  * @return {Array.<string>} String of binding values
40316  */
40317 _jQuery.fn.bindings = function(windowJquery, bindExp) {
40318   var result = [], match,
40319       bindSelector = '.ng-binding:visible';
40320   if (angular.isString(bindExp)) {
40321     bindExp = bindExp.replace(/\s/g, '');
40322     match = function(actualExp) {
40323       if (actualExp) {
40324         actualExp = actualExp.replace(/\s/g, '');
40325         if (actualExp == bindExp) return true;
40326         if (actualExp.indexOf(bindExp) === 0) {
40327           return actualExp.charAt(bindExp.length) == '|';
40328         }
40329       }
40330     };
40331   } else if (bindExp) {
40332     match = function(actualExp) {
40333       return actualExp && bindExp.exec(actualExp);
40334     };
40335   } else {
40336     match = function(actualExp) {
40337       return !!actualExp;
40338     };
40339   }
40340   var selection = this.find(bindSelector);
40341   if (this.is(bindSelector)) {
40342     selection = selection.add(this);
40343   }
40344
40345   function push(value) {
40346     if (angular.isUndefined(value)) {
40347       value = '';
40348     } else if (typeof value !== 'string') {
40349       value = angular.toJson(value);
40350     }
40351     result.push('' + value);
40352   }
40353
40354   selection.each(function() {
40355     var element = windowJquery(this),
40356         bindings;
40357     if (bindings = element.data('$binding')) {
40358       for (var expressions = [], binding, j=0, jj=bindings.length; j < jj; j++) {
40359         binding = bindings[j];
40360
40361         if (binding.expressions) {
40362           expressions = binding.expressions;
40363         } else {
40364           expressions = [binding];
40365         }
40366         for (var scope, expression, i = 0, ii = expressions.length; i < ii; i++) {
40367           expression = expressions[i];
40368           if (match(expression)) {
40369             scope = scope || element.scope();
40370             push(scope.$eval(expression));
40371           }
40372         }
40373       }
40374     }
40375   });
40376   return result;
40377 };
40378
40379 (function() {
40380   /**
40381    * Triggers a browser event. Attempts to choose the right event if one is
40382    * not specified.
40383    *
40384    * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
40385    * @param {string} eventType Optional event type
40386    * @param {Object=} eventData An optional object which contains additional event data (such as x,y
40387    * coordinates, keys, etc...) that are passed into the event when triggered
40388    */
40389   window.browserTrigger = function browserTrigger(element, eventType, eventData) {
40390     if (element && !element.nodeName) element = element[0];
40391     if (!element) return;
40392
40393     eventData = eventData || {};
40394     var relatedTarget = eventData.relatedTarget || element;
40395     var keys = eventData.keys;
40396     var x = eventData.x;
40397     var y = eventData.y;
40398
40399     var inputType = (element.type) ? element.type.toLowerCase() : null,
40400         nodeName = element.nodeName.toLowerCase();
40401     if (!eventType) {
40402       eventType = {
40403         'text':            'change',
40404         'textarea':        'change',
40405         'hidden':          'change',
40406         'password':        'change',
40407         'button':          'click',
40408         'submit':          'click',
40409         'reset':           'click',
40410         'image':           'click',
40411         'checkbox':        'click',
40412         'radio':           'click',
40413         'select-one':      'change',
40414         'select-multiple': 'change',
40415         '_default_':       'click'
40416       }[inputType || '_default_'];
40417     }
40418
40419     if (nodeName == 'option') {
40420       element.parentNode.value = element.value;
40421       element = element.parentNode;
40422       eventType = 'change';
40423     }
40424
40425     keys = keys || [];
40426     function pressed(key) {
40427       return keys.indexOf(key) !== -1;
40428     }
40429
40430     var evnt;
40431     if (/transitionend/.test(eventType)) {
40432       if (window.WebKitTransitionEvent) {
40433         evnt = new WebKitTransitionEvent(eventType, eventData);
40434         evnt.initEvent(eventType, false, true);
40435       } else {
40436         try {
40437           evnt = new TransitionEvent(eventType, eventData);
40438         }
40439         catch (e) {
40440           evnt = window.document.createEvent('TransitionEvent');
40441           evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
40442         }
40443       }
40444     } else if (/animationend/.test(eventType)) {
40445       if (window.WebKitAnimationEvent) {
40446         evnt = new WebKitAnimationEvent(eventType, eventData);
40447         evnt.initEvent(eventType, false, true);
40448       } else {
40449         try {
40450           evnt = new AnimationEvent(eventType, eventData);
40451         }
40452         catch (e) {
40453           evnt = window.document.createEvent('AnimationEvent');
40454           evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
40455         }
40456       }
40457     } else if (/touch/.test(eventType) && supportsTouchEvents()) {
40458       evnt = createTouchEvent(element, eventType, x, y);
40459     } else {
40460       evnt = window.document.createEvent('MouseEvents');
40461       x = x || 0;
40462       y = y || 0;
40463       evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
40464           pressed('alt'), pressed('shift'), pressed('meta'), 0, relatedTarget);
40465     }
40466
40467     /* we're unable to change the timeStamp value directly so this
40468      * is only here to allow for testing where the timeStamp value is
40469      * read */
40470     evnt.$manualTimeStamp = eventData.timeStamp;
40471
40472     if (!evnt) return;
40473
40474     var originalPreventDefault = evnt.preventDefault,
40475         appWindow = element.ownerDocument.defaultView,
40476         fakeProcessDefault = true,
40477         finalProcessDefault,
40478         angular = appWindow.angular || {};
40479
40480     // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
40481     angular['ff-684208-preventDefault'] = false;
40482     evnt.preventDefault = function() {
40483       fakeProcessDefault = false;
40484       return originalPreventDefault.apply(evnt, arguments);
40485     };
40486
40487     element.dispatchEvent(evnt);
40488     finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
40489
40490     delete angular['ff-684208-preventDefault'];
40491
40492     return finalProcessDefault;
40493   };
40494
40495   function supportsTouchEvents() {
40496     if ('_cached' in supportsTouchEvents) {
40497       return supportsTouchEvents._cached;
40498     }
40499     if (!window.document.createTouch || !window.document.createTouchList) {
40500       supportsTouchEvents._cached = false;
40501       return false;
40502     }
40503     try {
40504       window.document.createEvent('TouchEvent');
40505     } catch (e) {
40506       supportsTouchEvents._cached = false;
40507       return false;
40508     }
40509     supportsTouchEvents._cached = true;
40510     return true;
40511   }
40512
40513   function createTouchEvent(element, eventType, x, y) {
40514     var evnt = new window.Event(eventType);
40515     x = x || 0;
40516     y = y || 0;
40517
40518     var touch = window.document.createTouch(window, element, Date.now(), x, y, x, y);
40519     var touches = window.document.createTouchList(touch);
40520
40521     evnt.touches = touches;
40522
40523     return evnt;
40524   }
40525 }());
40526
40527 /**
40528  * Represents the application currently being tested and abstracts usage
40529  * of iframes or separate windows.
40530  *
40531  * @param {Object} context jQuery wrapper around HTML context.
40532  */
40533 angular.scenario.Application = function(context) {
40534   this.context = context;
40535   context.append(
40536     '<h2>Current URL: <a href="about:blank">None</a></h2>' +
40537     '<div id="test-frames"></div>'
40538   );
40539 };
40540
40541 /**
40542  * Gets the jQuery collection of frames. Don't use this directly because
40543  * frames may go stale.
40544  *
40545  * @private
40546  * @return {Object} jQuery collection
40547  */
40548 angular.scenario.Application.prototype.getFrame_ = function() {
40549   return this.context.find('#test-frames iframe:last');
40550 };
40551
40552 /**
40553  * Gets the window of the test runner frame. Always favor executeAction()
40554  * instead of this method since it prevents you from getting a stale window.
40555  *
40556  * @private
40557  * @return {Object} the window of the frame
40558  */
40559 angular.scenario.Application.prototype.getWindow_ = function() {
40560   var contentWindow = this.getFrame_().prop('contentWindow');
40561   if (!contentWindow) {
40562     throw 'Frame window is not accessible.';
40563   }
40564   return contentWindow;
40565 };
40566
40567 /**
40568  * Changes the location of the frame.
40569  *
40570  * @param {string} url The URL. If it begins with a # then only the
40571  *   hash of the page is changed.
40572  * @param {function()} loadFn function($window, $document) Called when frame loads.
40573  * @param {function()} errorFn function(error) Called if any error when loading.
40574  */
40575 angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorFn) {
40576   var self = this;
40577   var frame = self.getFrame_();
40578   //TODO(esprehn): Refactor to use rethrow()
40579   errorFn = errorFn || function(e) { throw e; };
40580   if (url === 'about:blank') {
40581     errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
40582   } else if (url.charAt(0) === '#') {
40583     url = frame.attr('src').split('#')[0] + url;
40584     frame.attr('src', url);
40585     self.executeAction(loadFn);
40586   } else {
40587     frame.remove();
40588     self.context.find('#test-frames').append('<iframe>');
40589     frame = self.getFrame_();
40590
40591     frame.on('load', function() {
40592       frame.off();
40593       try {
40594         var $window = self.getWindow_();
40595
40596         if (!$window.angular) {
40597           self.executeAction(loadFn);
40598           return;
40599         }
40600
40601         if (!$window.angular.resumeBootstrap) {
40602           $window.angular.resumeDeferredBootstrap = resumeDeferredBootstrap;
40603         } else {
40604           resumeDeferredBootstrap();
40605         }
40606
40607       } catch (e) {
40608         errorFn(e);
40609       }
40610
40611       function resumeDeferredBootstrap() {
40612         // Disable animations
40613         var $injector = $window.angular.resumeBootstrap([['$provide', function($provide) {
40614           return ['$animate', function($animate) {
40615             $animate.enabled(false);
40616           }];
40617         }]]);
40618         self.rootElement = $injector.get('$rootElement')[0];
40619         self.executeAction(loadFn);
40620       }
40621     }).attr('src', url);
40622
40623     // for IE compatibility set the name *after* setting the frame url
40624     frame[0].contentWindow.name = "NG_DEFER_BOOTSTRAP!";
40625   }
40626   self.context.find('> h2 a').attr('href', url).text(url);
40627 };
40628
40629 /**
40630  * Executes a function in the context of the tested application. Will wait
40631  * for all pending angular xhr requests before executing.
40632  *
40633  * @param {function()} action The callback to execute. function($window, $document)
40634  *  $document is a jQuery wrapped document.
40635  */
40636 angular.scenario.Application.prototype.executeAction = function(action) {
40637   var self = this;
40638   var $window = this.getWindow_();
40639   if (!$window.document) {
40640     throw 'Sandbox Error: Application document not accessible.';
40641   }
40642   if (!$window.angular) {
40643     return action.call(this, $window, _jQuery($window.document));
40644   }
40645
40646   if (!!this.rootElement) {
40647     executeWithElement(this.rootElement);
40648   } else {
40649     angularInit($window.document, angular.bind(this, executeWithElement));
40650   }
40651
40652   function executeWithElement(element) {
40653     var $injector = $window.angular.element(element).injector();
40654     var $element = _jQuery(element);
40655
40656     $element.injector = function() {
40657       return $injector;
40658     };
40659
40660     $injector.invoke(function($browser) {
40661       $browser.notifyWhenNoOutstandingRequests(function() {
40662         action.call(self, $window, $element);
40663       });
40664     });
40665   }
40666 };
40667
40668 /**
40669  * The representation of define blocks. Don't used directly, instead use
40670  * define() in your tests.
40671  *
40672  * @param {string} descName Name of the block
40673  * @param {Object} parent describe or undefined if the root.
40674  */
40675 angular.scenario.Describe = function(descName, parent) {
40676   this.only = parent && parent.only;
40677   this.beforeEachFns = [];
40678   this.afterEachFns = [];
40679   this.its = [];
40680   this.children = [];
40681   this.name = descName;
40682   this.parent = parent;
40683   this.id = angular.scenario.Describe.id++;
40684
40685   /**
40686    * Calls all before functions.
40687    */
40688   var beforeEachFns = this.beforeEachFns;
40689   this.setupBefore = function() {
40690     if (parent) parent.setupBefore.call(this);
40691     angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
40692   };
40693
40694   /**
40695    * Calls all after functions.
40696    */
40697   var afterEachFns = this.afterEachFns;
40698   this.setupAfter  = function() {
40699     angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
40700     if (parent) parent.setupAfter.call(this);
40701   };
40702 };
40703
40704 // Shared Unique ID generator for every describe block
40705 angular.scenario.Describe.id = 0;
40706
40707 // Shared Unique ID generator for every it (spec)
40708 angular.scenario.Describe.specId = 0;
40709
40710 /**
40711  * Defines a block to execute before each it or nested describe.
40712  *
40713  * @param {function()} body Body of the block.
40714  */
40715 angular.scenario.Describe.prototype.beforeEach = function(body) {
40716   this.beforeEachFns.push(body);
40717 };
40718
40719 /**
40720  * Defines a block to execute after each it or nested describe.
40721  *
40722  * @param {function()} body Body of the block.
40723  */
40724 angular.scenario.Describe.prototype.afterEach = function(body) {
40725   this.afterEachFns.push(body);
40726 };
40727
40728 /**
40729  * Creates a new describe block that's a child of this one.
40730  *
40731  * @param {string} name Name of the block. Appended to the parent block's name.
40732  * @param {function()} body Body of the block.
40733  */
40734 angular.scenario.Describe.prototype.describe = function(name, body) {
40735   var child = new angular.scenario.Describe(name, this);
40736   this.children.push(child);
40737   body.call(child);
40738 };
40739
40740 /**
40741  * Same as describe() but makes ddescribe blocks the only to run.
40742  *
40743  * @param {string} name Name of the test.
40744  * @param {function()} body Body of the block.
40745  */
40746 angular.scenario.Describe.prototype.ddescribe = function(name, body) {
40747   var child = new angular.scenario.Describe(name, this);
40748   child.only = true;
40749   this.children.push(child);
40750   body.call(child);
40751 };
40752
40753 /**
40754  * Use to disable a describe block.
40755  */
40756 angular.scenario.Describe.prototype.xdescribe = angular.noop;
40757
40758 /**
40759  * Defines a test.
40760  *
40761  * @param {string} name Name of the test.
40762  * @param {function()} body Body of the block.
40763  */
40764 angular.scenario.Describe.prototype.it = function(name, body) {
40765   this.its.push({
40766     id: angular.scenario.Describe.specId++,
40767     definition: this,
40768     only: this.only,
40769     name: name,
40770     before: this.setupBefore,
40771     body: body,
40772     after: this.setupAfter
40773   });
40774 };
40775
40776 /**
40777  * Same as it() but makes iit tests the only test to run.
40778  *
40779  * @param {string} name Name of the test.
40780  * @param {function()} body Body of the block.
40781  */
40782 angular.scenario.Describe.prototype.iit = function(name, body) {
40783   this.it.apply(this, arguments);
40784   this.its[this.its.length - 1].only = true;
40785 };
40786
40787 /**
40788  * Use to disable a test block.
40789  */
40790 angular.scenario.Describe.prototype.xit = angular.noop;
40791
40792 /**
40793  * Gets an array of functions representing all the tests (recursively).
40794  * that can be executed with SpecRunner's.
40795  *
40796  * @return {Array<Object>} Array of it blocks {
40797  *   definition : Object // parent Describe
40798  *   only: boolean
40799  *   name: string
40800  *   before: Function
40801  *   body: Function
40802  *   after: Function
40803  *  }
40804  */
40805 angular.scenario.Describe.prototype.getSpecs = function() {
40806   var specs = arguments[0] || [];
40807   angular.forEach(this.children, function(child) {
40808     child.getSpecs(specs);
40809   });
40810   angular.forEach(this.its, function(it) {
40811     specs.push(it);
40812   });
40813   var only = [];
40814   angular.forEach(specs, function(it) {
40815     if (it.only) {
40816       only.push(it);
40817     }
40818   });
40819   return (only.length && only) || specs;
40820 };
40821
40822 /**
40823  * A future action in a spec.
40824  *
40825  * @param {string} name name of the future action
40826  * @param {function()} behavior future callback(error, result)
40827  * @param {function()} line Optional. function that returns the file/line number.
40828  */
40829 angular.scenario.Future = function(name, behavior, line) {
40830   this.name = name;
40831   this.behavior = behavior;
40832   this.fulfilled = false;
40833   this.value = undefined;
40834   this.parser = angular.identity;
40835   this.line = line || function() { return ''; };
40836 };
40837
40838 /**
40839  * Executes the behavior of the closure.
40840  *
40841  * @param {function()} doneFn Callback function(error, result)
40842  */
40843 angular.scenario.Future.prototype.execute = function(doneFn) {
40844   var self = this;
40845   this.behavior(function(error, result) {
40846     self.fulfilled = true;
40847     if (result) {
40848       try {
40849         result = self.parser(result);
40850       } catch (e) {
40851         error = e;
40852       }
40853     }
40854     self.value = error || result;
40855     doneFn(error, result);
40856   });
40857 };
40858
40859 /**
40860  * Configures the future to convert its final with a function fn(value)
40861  *
40862  * @param {function()} fn function(value) that returns the parsed value
40863  */
40864 angular.scenario.Future.prototype.parsedWith = function(fn) {
40865   this.parser = fn;
40866   return this;
40867 };
40868
40869 /**
40870  * Configures the future to parse its final value from JSON
40871  * into objects.
40872  */
40873 angular.scenario.Future.prototype.fromJson = function() {
40874   return this.parsedWith(angular.fromJson);
40875 };
40876
40877 /**
40878  * Configures the future to convert its final value from objects
40879  * into JSON.
40880  */
40881 angular.scenario.Future.prototype.toJson = function() {
40882   return this.parsedWith(angular.toJson);
40883 };
40884
40885 /**
40886  * Maintains an object tree from the runner events.
40887  *
40888  * @param {Object} runner The scenario Runner instance to connect to.
40889  *
40890  * TODO(esprehn): Every output type creates one of these, but we probably
40891  *  want one global shared instance. Need to handle events better too
40892  *  so the HTML output doesn't need to do spec model.getSpec(spec.id)
40893  *  silliness.
40894  *
40895  * TODO(vojta) refactor on, emit methods (from all objects) - use inheritance
40896  */
40897 angular.scenario.ObjectModel = function(runner) {
40898   var self = this;
40899
40900   this.specMap = {};
40901   this.listeners = [];
40902   this.value = {
40903     name: '',
40904     children: {}
40905   };
40906
40907   runner.on('SpecBegin', function(spec) {
40908     var block = self.value,
40909         definitions = [];
40910
40911     angular.forEach(self.getDefinitionPath(spec), function(def) {
40912       if (!block.children[def.name]) {
40913         block.children[def.name] = {
40914           id: def.id,
40915           name: def.name,
40916           children: {},
40917           specs: {}
40918         };
40919       }
40920       block = block.children[def.name];
40921       definitions.push(def.name);
40922     });
40923
40924     var it = self.specMap[spec.id] =
40925              block.specs[spec.name] =
40926              new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions);
40927
40928     // forward the event
40929     self.emit('SpecBegin', it);
40930   });
40931
40932   runner.on('SpecError', function(spec, error) {
40933     var it = self.getSpec(spec.id);
40934     it.status = 'error';
40935     it.error = error;
40936
40937     // forward the event
40938     self.emit('SpecError', it, error);
40939   });
40940
40941   runner.on('SpecEnd', function(spec) {
40942     var it = self.getSpec(spec.id);
40943     complete(it);
40944
40945     // forward the event
40946     self.emit('SpecEnd', it);
40947   });
40948
40949   runner.on('StepBegin', function(spec, step) {
40950     var it = self.getSpec(spec.id);
40951     step = new angular.scenario.ObjectModel.Step(step.name);
40952     it.steps.push(step);
40953
40954     // forward the event
40955     self.emit('StepBegin', it, step);
40956   });
40957
40958   runner.on('StepEnd', function(spec) {
40959     var it = self.getSpec(spec.id);
40960     var step = it.getLastStep();
40961     if (step.name !== step.name) {
40962       throw 'Events fired in the wrong order. Step names don\'t match.';
40963     }
40964     complete(step);
40965
40966     // forward the event
40967     self.emit('StepEnd', it, step);
40968   });
40969
40970   runner.on('StepFailure', function(spec, step, error) {
40971     var it = self.getSpec(spec.id),
40972         modelStep = it.getLastStep();
40973
40974     modelStep.setErrorStatus('failure', error, step.line());
40975     it.setStatusFromStep(modelStep);
40976
40977     // forward the event
40978     self.emit('StepFailure', it, modelStep, error);
40979   });
40980
40981   runner.on('StepError', function(spec, step, error) {
40982     var it = self.getSpec(spec.id),
40983         modelStep = it.getLastStep();
40984
40985     modelStep.setErrorStatus('error', error, step.line());
40986     it.setStatusFromStep(modelStep);
40987
40988     // forward the event
40989     self.emit('StepError', it, modelStep, error);
40990   });
40991
40992   runner.on('RunnerBegin', function() {
40993     self.emit('RunnerBegin');
40994   });
40995   runner.on('RunnerEnd', function() {
40996     self.emit('RunnerEnd');
40997   });
40998
40999   function complete(item) {
41000     item.endTime = Date.now();
41001     item.duration = item.endTime - item.startTime;
41002     item.status = item.status || 'success';
41003   }
41004 };
41005
41006 /**
41007  * Adds a listener for an event.
41008  *
41009  * @param {string} eventName Name of the event to add a handler for
41010  * @param {function()} listener Function that will be called when event is fired
41011  */
41012 angular.scenario.ObjectModel.prototype.on = function(eventName, listener) {
41013   eventName = eventName.toLowerCase();
41014   this.listeners[eventName] = this.listeners[eventName] || [];
41015   this.listeners[eventName].push(listener);
41016 };
41017
41018 /**
41019  * Emits an event which notifies listeners and passes extra
41020  * arguments.
41021  *
41022  * @param {string} eventName Name of the event to fire.
41023  */
41024 angular.scenario.ObjectModel.prototype.emit = function(eventName) {
41025   var self = this,
41026       args = Array.prototype.slice.call(arguments, 1);
41027
41028   eventName = eventName.toLowerCase();
41029
41030   if (this.listeners[eventName]) {
41031     angular.forEach(this.listeners[eventName], function(listener) {
41032       listener.apply(self, args);
41033     });
41034   }
41035 };
41036
41037 /**
41038  * Computes the path of definition describe blocks that wrap around
41039  * this spec.
41040  *
41041  * @param spec Spec to compute the path for.
41042  * @return {Array<Describe>} The describe block path
41043  */
41044 angular.scenario.ObjectModel.prototype.getDefinitionPath = function(spec) {
41045   var path = [];
41046   var currentDefinition = spec.definition;
41047   while (currentDefinition && currentDefinition.name) {
41048     path.unshift(currentDefinition);
41049     currentDefinition = currentDefinition.parent;
41050   }
41051   return path;
41052 };
41053
41054 /**
41055  * Gets a spec by id.
41056  *
41057  * @param {string} id The id of the spec to get the object for.
41058  * @return {Object} the Spec instance
41059  */
41060 angular.scenario.ObjectModel.prototype.getSpec = function(id) {
41061   return this.specMap[id];
41062 };
41063
41064 /**
41065  * A single it block.
41066  *
41067  * @param {string} id Id of the spec
41068  * @param {string} name Name of the spec
41069  * @param {Array<string>=} definitionNames List of all describe block names that wrap this spec
41070  */
41071 angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) {
41072   this.id = id;
41073   this.name = name;
41074   this.startTime = Date.now();
41075   this.steps = [];
41076   this.fullDefinitionName = (definitionNames || []).join(' ');
41077 };
41078
41079 /**
41080  * Adds a new step to the Spec.
41081  *
41082  * @param {string} name Name of the step (really name of the future)
41083  * @return {Object} the added step
41084  */
41085 angular.scenario.ObjectModel.Spec.prototype.addStep = function(name) {
41086   var step = new angular.scenario.ObjectModel.Step(name);
41087   this.steps.push(step);
41088   return step;
41089 };
41090
41091 /**
41092  * Gets the most recent step.
41093  *
41094  * @return {Object} the step
41095  */
41096 angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() {
41097   return this.steps[this.steps.length - 1];
41098 };
41099
41100 /**
41101  * Set status of the Spec from given Step
41102  *
41103  * @param {angular.scenario.ObjectModel.Step} step
41104  */
41105 angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) {
41106   if (!this.status || step.status == 'error') {
41107     this.status = step.status;
41108     this.error = step.error;
41109     this.line = step.line;
41110   }
41111 };
41112
41113 /**
41114  * A single step inside a Spec.
41115  *
41116  * @param {string} name Name of the step
41117  */
41118 angular.scenario.ObjectModel.Step = function(name) {
41119   this.name = name;
41120   this.startTime = Date.now();
41121 };
41122
41123 /**
41124  * Helper method for setting all error status related properties
41125  *
41126  * @param {string} status
41127  * @param {string} error
41128  * @param {string} line
41129  */
41130 angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) {
41131   this.status = status;
41132   this.error = error;
41133   this.line = line;
41134 };
41135
41136 /**
41137  * Runner for scenarios
41138  *
41139  * Has to be initialized before any test is loaded,
41140  * because it publishes the API into window (global space).
41141  */
41142 angular.scenario.Runner = function($window) {
41143   this.listeners = [];
41144   this.$window = $window;
41145   this.rootDescribe = new angular.scenario.Describe();
41146   this.currentDescribe = this.rootDescribe;
41147   this.api = {
41148     it: this.it,
41149     iit: this.iit,
41150     xit: angular.noop,
41151     describe: this.describe,
41152     ddescribe: this.ddescribe,
41153     xdescribe: angular.noop,
41154     beforeEach: this.beforeEach,
41155     afterEach: this.afterEach
41156   };
41157   angular.forEach(this.api, angular.bind(this, function(fn, key) {
41158     this.$window[key] = angular.bind(this, fn);
41159   }));
41160 };
41161
41162 /**
41163  * Emits an event which notifies listeners and passes extra
41164  * arguments.
41165  *
41166  * @param {string} eventName Name of the event to fire.
41167  */
41168 angular.scenario.Runner.prototype.emit = function(eventName) {
41169   var self = this;
41170   var args = Array.prototype.slice.call(arguments, 1);
41171   eventName = eventName.toLowerCase();
41172   if (!this.listeners[eventName]) {
41173     return;
41174   }
41175   angular.forEach(this.listeners[eventName], function(listener) {
41176     listener.apply(self, args);
41177   });
41178 };
41179
41180 /**
41181  * Adds a listener for an event.
41182  *
41183  * @param {string} eventName The name of the event to add a handler for
41184  * @param {string} listener The fn(...) that takes the extra arguments from emit()
41185  */
41186 angular.scenario.Runner.prototype.on = function(eventName, listener) {
41187   eventName = eventName.toLowerCase();
41188   this.listeners[eventName] = this.listeners[eventName] || [];
41189   this.listeners[eventName].push(listener);
41190 };
41191
41192 /**
41193  * Defines a describe block of a spec.
41194  *
41195  * @see Describe.js
41196  *
41197  * @param {string} name Name of the block
41198  * @param {function()} body Body of the block
41199  */
41200 angular.scenario.Runner.prototype.describe = function(name, body) {
41201   var self = this;
41202   this.currentDescribe.describe(name, function() {
41203     var parentDescribe = self.currentDescribe;
41204     self.currentDescribe = this;
41205     try {
41206       body.call(this);
41207     } finally {
41208       self.currentDescribe = parentDescribe;
41209     }
41210   });
41211 };
41212
41213 /**
41214  * Same as describe, but makes ddescribe the only blocks to run.
41215  *
41216  * @see Describe.js
41217  *
41218  * @param {string} name Name of the block
41219  * @param {function()} body Body of the block
41220  */
41221 angular.scenario.Runner.prototype.ddescribe = function(name, body) {
41222   var self = this;
41223   this.currentDescribe.ddescribe(name, function() {
41224     var parentDescribe = self.currentDescribe;
41225     self.currentDescribe = this;
41226     try {
41227       body.call(this);
41228     } finally {
41229       self.currentDescribe = parentDescribe;
41230     }
41231   });
41232 };
41233
41234 /**
41235  * Defines a test in a describe block of a spec.
41236  *
41237  * @see Describe.js
41238  *
41239  * @param {string} name Name of the block
41240  * @param {function()} body Body of the block
41241  */
41242 angular.scenario.Runner.prototype.it = function(name, body) {
41243   this.currentDescribe.it(name, body);
41244 };
41245
41246 /**
41247  * Same as it, but makes iit tests the only tests to run.
41248  *
41249  * @see Describe.js
41250  *
41251  * @param {string} name Name of the block
41252  * @param {function()} body Body of the block
41253  */
41254 angular.scenario.Runner.prototype.iit = function(name, body) {
41255   this.currentDescribe.iit(name, body);
41256 };
41257
41258 /**
41259  * Defines a function to be called before each it block in the describe
41260  * (and before all nested describes).
41261  *
41262  * @see Describe.js
41263  *
41264  * @param {function()} Callback to execute
41265  */
41266 angular.scenario.Runner.prototype.beforeEach = function(body) {
41267   this.currentDescribe.beforeEach(body);
41268 };
41269
41270 /**
41271  * Defines a function to be called after each it block in the describe
41272  * (and before all nested describes).
41273  *
41274  * @see Describe.js
41275  *
41276  * @param {function()} Callback to execute
41277  */
41278 angular.scenario.Runner.prototype.afterEach = function(body) {
41279   this.currentDescribe.afterEach(body);
41280 };
41281
41282 /**
41283  * Creates a new spec runner.
41284  *
41285  * @private
41286  * @param {Object} scope parent scope
41287  */
41288 angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
41289   var child = scope.$new();
41290   var Cls = angular.scenario.SpecRunner;
41291
41292   // Export all the methods to child scope manually as now we don't mess controllers with scopes
41293   // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
41294   for (var name in Cls.prototype) {
41295     child[name] = angular.bind(child, Cls.prototype[name]);
41296   }
41297
41298   Cls.call(child);
41299   return child;
41300 };
41301
41302 /**
41303  * Runs all the loaded tests with the specified runner class on the
41304  * provided application.
41305  *
41306  * @param {angular.scenario.Application} application App to remote control.
41307  */
41308 angular.scenario.Runner.prototype.run = function(application) {
41309   var self = this;
41310   var $root = angular.injector(['ng']).get('$rootScope');
41311   angular.extend($root, this);
41312   angular.forEach(angular.scenario.Runner.prototype, function(fn, name) {
41313     $root[name] = angular.bind(self, fn);
41314   });
41315   $root.application = application;
41316   $root.emit('RunnerBegin');
41317   asyncForEach(this.rootDescribe.getSpecs(), function(spec, specDone) {
41318     var dslCache = {};
41319     var runner = self.createSpecRunner_($root);
41320     angular.forEach(angular.scenario.dsl, function(fn, key) {
41321       dslCache[key] = fn.call($root);
41322     });
41323     angular.forEach(angular.scenario.dsl, function(fn, key) {
41324       self.$window[key] = function() {
41325         var line = callerFile(3);
41326         var scope = runner.$new();
41327
41328         // Make the dsl accessible on the current chain
41329         scope.dsl = {};
41330         angular.forEach(dslCache, function(fn, key) {
41331           scope.dsl[key] = function() {
41332             return dslCache[key].apply(scope, arguments);
41333           };
41334         });
41335
41336         // Make these methods work on the current chain
41337         scope.addFuture = function() {
41338           Array.prototype.push.call(arguments, line);
41339           return angular.scenario.SpecRunner.
41340             prototype.addFuture.apply(scope, arguments);
41341         };
41342         scope.addFutureAction = function() {
41343           Array.prototype.push.call(arguments, line);
41344           return angular.scenario.SpecRunner.
41345             prototype.addFutureAction.apply(scope, arguments);
41346         };
41347
41348         return scope.dsl[key].apply(scope, arguments);
41349       };
41350     });
41351     runner.run(spec, function() {
41352       runner.$destroy();
41353       specDone.apply(this, arguments);
41354     });
41355   },
41356   function(error) {
41357     if (error) {
41358       self.emit('RunnerError', error);
41359     }
41360     self.emit('RunnerEnd');
41361   });
41362 };
41363
41364 /**
41365  * This class is the "this" of the it/beforeEach/afterEach method.
41366  * Responsibilities:
41367  *   - "this" for it/beforeEach/afterEach
41368  *   - keep state for single it/beforeEach/afterEach execution
41369  *   - keep track of all of the futures to execute
41370  *   - run single spec (execute each future)
41371  */
41372 angular.scenario.SpecRunner = function() {
41373   this.futures = [];
41374   this.afterIndex = 0;
41375 };
41376
41377 /**
41378  * Executes a spec which is an it block with associated before/after functions
41379  * based on the describe nesting.
41380  *
41381  * @param {Object} spec A spec object
41382  * @param {function()} specDone function that is called when the spec finishes,
41383  *                              of the form `Function(error, index)`
41384  */
41385 angular.scenario.SpecRunner.prototype.run = function(spec, specDone) {
41386   var self = this;
41387   this.spec = spec;
41388
41389   this.emit('SpecBegin', spec);
41390
41391   try {
41392     spec.before.call(this);
41393     spec.body.call(this);
41394     this.afterIndex = this.futures.length;
41395     spec.after.call(this);
41396   } catch (e) {
41397     this.emit('SpecError', spec, e);
41398     this.emit('SpecEnd', spec);
41399     specDone();
41400     return;
41401   }
41402
41403   var handleError = function(error, done) {
41404     if (self.error) {
41405       return done();
41406     }
41407     self.error = true;
41408     done(null, self.afterIndex);
41409   };
41410
41411   asyncForEach(
41412     this.futures,
41413     function(future, futureDone) {
41414       self.step = future;
41415       self.emit('StepBegin', spec, future);
41416       try {
41417         future.execute(function(error) {
41418           if (error) {
41419             self.emit('StepFailure', spec, future, error);
41420             self.emit('StepEnd', spec, future);
41421             return handleError(error, futureDone);
41422           }
41423           self.emit('StepEnd', spec, future);
41424           self.$window.setTimeout(function() { futureDone(); }, 0);
41425         });
41426       } catch (e) {
41427         self.emit('StepError', spec, future, e);
41428         self.emit('StepEnd', spec, future);
41429         handleError(e, futureDone);
41430       }
41431     },
41432     function(e) {
41433       if (e) {
41434         self.emit('SpecError', spec, e);
41435       }
41436       self.emit('SpecEnd', spec);
41437       // Call done in a timeout so exceptions don't recursively
41438       // call this function
41439       self.$window.setTimeout(function() { specDone(); }, 0);
41440     }
41441   );
41442 };
41443
41444 /**
41445  * Adds a new future action.
41446  *
41447  * Note: Do not pass line manually. It happens automatically.
41448  *
41449  * @param {string} name Name of the future
41450  * @param {function()} behavior Behavior of the future
41451  * @param {function()} line fn() that returns file/line number
41452  */
41453 angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line) {
41454   var future = new angular.scenario.Future(name, angular.bind(this, behavior), line);
41455   this.futures.push(future);
41456   return future;
41457 };
41458
41459 /**
41460  * Adds a new future action to be executed on the application window.
41461  *
41462  * Note: Do not pass line manually. It happens automatically.
41463  *
41464  * @param {string} name Name of the future
41465  * @param {function()} behavior Behavior of the future
41466  * @param {function()} line fn() that returns file/line number
41467  */
41468 angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) {
41469   var self = this;
41470   var NG = /\[ng\\\:/;
41471   return this.addFuture(name, function(done) {
41472     this.application.executeAction(function($window, $document) {
41473
41474       //TODO(esprehn): Refactor this so it doesn't need to be in here.
41475       $document.elements = function(selector) {
41476         var args = Array.prototype.slice.call(arguments, 1);
41477         selector = (self.selector || '') + ' ' + (selector || '');
41478         selector = _jQuery.trim(selector) || '*';
41479         angular.forEach(args, function(value, index) {
41480           selector = selector.replace('$' + (index + 1), value);
41481         });
41482         var result = $document.find(selector);
41483         if (selector.match(NG)) {
41484           angular.forEach(['[ng-','[data-ng-','[x-ng-'], function(value, index) {
41485             result = result.add(selector.replace(NG, value), $document);
41486           });
41487         }
41488         if (!result.length) {
41489           throw {
41490             type: 'selector',
41491             message: 'Selector ' + selector + ' did not match any elements.'
41492           };
41493         }
41494
41495         return result;
41496       };
41497
41498       try {
41499         behavior.call(self, $window, $document, done);
41500       } catch (e) {
41501         if (e.type && e.type === 'selector') {
41502           done(e.message);
41503         } else {
41504           throw e;
41505         }
41506       }
41507     });
41508   }, line);
41509 };
41510
41511 /**
41512  * Shared DSL statements that are useful to all scenarios.
41513  */
41514
41515  /**
41516  * Usage:
41517  *    pause() pauses until you call resume() in the console
41518  */
41519 angular.scenario.dsl('pause', function() {
41520   return function() {
41521     return this.addFuture('pausing for you to resume', function(done) {
41522       this.emit('InteractivePause', this.spec, this.step);
41523       this.$window.resume = function() { done(); };
41524     });
41525   };
41526 });
41527
41528 /**
41529  * Usage:
41530  *    sleep(seconds) pauses the test for specified number of seconds
41531  */
41532 angular.scenario.dsl('sleep', function() {
41533   return function(time) {
41534     return this.addFuture('sleep for ' + time + ' seconds', function(done) {
41535       this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000);
41536     });
41537   };
41538 });
41539
41540 /**
41541  * Usage:
41542  *    browser().navigateTo(url) Loads the url into the frame
41543  *    browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to
41544  *    browser().reload() refresh the page (reload the same URL)
41545  *    browser().window.href() window.location.href
41546  *    browser().window.path() window.location.pathname
41547  *    browser().window.search() window.location.search
41548  *    browser().window.hash() window.location.hash without # prefix
41549  *    browser().location().url() see ng.$location#url
41550  *    browser().location().path() see ng.$location#path
41551  *    browser().location().search() see ng.$location#search
41552  *    browser().location().hash() see ng.$location#hash
41553  */
41554 angular.scenario.dsl('browser', function() {
41555   var chain = {};
41556
41557   chain.navigateTo = function(url, delegate) {
41558     var application = this.application;
41559     return this.addFuture("browser navigate to '" + url + "'", function(done) {
41560       if (delegate) {
41561         url = delegate.call(this, url);
41562       }
41563       application.navigateTo(url, function() {
41564         done(null, url);
41565       }, done);
41566     });
41567   };
41568
41569   chain.reload = function() {
41570     var application = this.application;
41571     return this.addFutureAction('browser reload', function($window, $document, done) {
41572       var href = $window.location.href;
41573       application.navigateTo(href, function() {
41574         done(null, href);
41575       }, done);
41576     });
41577   };
41578
41579   chain.window = function() {
41580     var api = {};
41581
41582     api.href = function() {
41583       return this.addFutureAction('window.location.href', function($window, $document, done) {
41584         done(null, $window.location.href);
41585       });
41586     };
41587
41588     api.path = function() {
41589       return this.addFutureAction('window.location.path', function($window, $document, done) {
41590         done(null, $window.location.pathname);
41591       });
41592     };
41593
41594     api.search = function() {
41595       return this.addFutureAction('window.location.search', function($window, $document, done) {
41596         done(null, $window.location.search);
41597       });
41598     };
41599
41600     api.hash = function() {
41601       return this.addFutureAction('window.location.hash', function($window, $document, done) {
41602         done(null, $window.location.hash.replace('#', ''));
41603       });
41604     };
41605
41606     return api;
41607   };
41608
41609   chain.location = function() {
41610     var api = {};
41611
41612     api.url = function() {
41613       return this.addFutureAction('$location.url()', function($window, $document, done) {
41614         done(null, $document.injector().get('$location').url());
41615       });
41616     };
41617
41618     api.path = function() {
41619       return this.addFutureAction('$location.path()', function($window, $document, done) {
41620         done(null, $document.injector().get('$location').path());
41621       });
41622     };
41623
41624     api.search = function() {
41625       return this.addFutureAction('$location.search()', function($window, $document, done) {
41626         done(null, $document.injector().get('$location').search());
41627       });
41628     };
41629
41630     api.hash = function() {
41631       return this.addFutureAction('$location.hash()', function($window, $document, done) {
41632         done(null, $document.injector().get('$location').hash());
41633       });
41634     };
41635
41636     return api;
41637   };
41638
41639   return function() {
41640     return chain;
41641   };
41642 });
41643
41644 /**
41645  * Usage:
41646  *    expect(future).{matcher} where matcher is one of the matchers defined
41647  *    with angular.scenario.matcher
41648  *
41649  * ex. expect(binding("name")).toEqual("Elliott")
41650  */
41651 angular.scenario.dsl('expect', function() {
41652   var chain = angular.extend({}, angular.scenario.matcher);
41653
41654   chain.not = function() {
41655     this.inverse = true;
41656     return chain;
41657   };
41658
41659   return function(future) {
41660     this.future = future;
41661     return chain;
41662   };
41663 });
41664
41665 /**
41666  * Usage:
41667  *    using(selector, label) scopes the next DSL element selection
41668  *
41669  * ex.
41670  *   using('#foo', "'Foo' text field").input('bar')
41671  */
41672 angular.scenario.dsl('using', function() {
41673   return function(selector, label) {
41674     this.selector = _jQuery.trim((this.selector || '') + ' ' + selector);
41675     if (angular.isString(label) && label.length) {
41676       this.label = label + ' ( ' + this.selector + ' )';
41677     } else {
41678       this.label = this.selector;
41679     }
41680     return this.dsl;
41681   };
41682 });
41683
41684 /**
41685  * Usage:
41686  *    binding(name) returns the value of the first matching binding
41687  */
41688 angular.scenario.dsl('binding', function() {
41689   return function(name) {
41690     return this.addFutureAction("select binding '" + name + "'",
41691       function($window, $document, done) {
41692         var values = $document.elements().bindings($window.angular.element, name);
41693         if (!values.length) {
41694           return done("Binding selector '" + name + "' did not match.");
41695         }
41696         done(null, values[0]);
41697     });
41698   };
41699 });
41700
41701 /**
41702  * Usage:
41703  *    input(name).enter(value) enters value in input with specified name
41704  *    input(name).check() checks checkbox
41705  *    input(name).select(value) selects the radio button with specified name/value
41706  *    input(name).val() returns the value of the input.
41707  */
41708 angular.scenario.dsl('input', function() {
41709   var chain = {};
41710   var supportInputEvent = 'oninput' in window.document.createElement('div') && !msie;
41711
41712   chain.enter = function(value, event) {
41713     return this.addFutureAction("input '" + this.name + "' enter '" + value + "'",
41714       function($window, $document, done) {
41715         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
41716         input.val(value);
41717         input.trigger(event || (supportInputEvent ? 'input' : 'change'));
41718         done();
41719     });
41720   };
41721
41722   chain.check = function() {
41723     return this.addFutureAction("checkbox '" + this.name + "' toggle",
41724       function($window, $document, done) {
41725         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
41726         input.trigger('click');
41727         done();
41728     });
41729   };
41730
41731   chain.select = function(value) {
41732     return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'",
41733       function($window, $document, done) {
41734         var input = $document.
41735           elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
41736         input.trigger('click');
41737         done();
41738     });
41739   };
41740
41741   chain.val = function() {
41742     return this.addFutureAction("return input val", function($window, $document, done) {
41743       var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
41744       done(null,input.val());
41745     });
41746   };
41747
41748   return function(name) {
41749     this.name = name;
41750     return chain;
41751   };
41752 });
41753
41754
41755 /**
41756  * Usage:
41757  *    repeater('#products table', 'Product List').count() number of rows
41758  *    repeater('#products table', 'Product List').row(1) all bindings in row as an array
41759  *    repeater('#products table', 'Product List').column('product.name') all values across all rows
41760  *    in an array
41761  */
41762 angular.scenario.dsl('repeater', function() {
41763   var chain = {};
41764
41765   chain.count = function() {
41766     return this.addFutureAction("repeater '" + this.label + "' count",
41767       function($window, $document, done) {
41768         try {
41769           done(null, $document.elements().length);
41770         } catch (e) {
41771           done(null, 0);
41772         }
41773     });
41774   };
41775
41776   chain.column = function(binding) {
41777     return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'",
41778       function($window, $document, done) {
41779         done(null, $document.elements().bindings($window.angular.element, binding));
41780     });
41781   };
41782
41783   chain.row = function(index) {
41784     return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'",
41785       function($window, $document, done) {
41786         var matches = $document.elements().slice(index, index + 1);
41787         if (!matches.length) {
41788           return done('row ' + index + ' out of bounds');
41789         }
41790         done(null, matches.bindings($window.angular.element));
41791     });
41792   };
41793
41794   return function(selector, label) {
41795     this.dsl.using(selector, label);
41796     return chain;
41797   };
41798 });
41799
41800 /**
41801  * Usage:
41802  *    select(name).option('value') select one option
41803  *    select(name).options('value1', 'value2', ...) select options from a multi select
41804  */
41805 angular.scenario.dsl('select', function() {
41806   var chain = {};
41807
41808   chain.option = function(value) {
41809     return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
41810       function($window, $document, done) {
41811         var select = $document.elements('select[ng\\:model="$1"]', this.name);
41812         var option = select.find('option[value="' + value + '"]');
41813         if (option.length) {
41814           select.val(value);
41815         } else {
41816           option = select.find('option').filter(function() {
41817             return _jQuery(this).text() === value;
41818           });
41819           if (!option.length) {
41820             option = select.find('option:contains("' + value + '")');
41821           }
41822           if (option.length) {
41823             select.val(option.val());
41824           } else {
41825               return done("option '" + value + "' not found");
41826           }
41827         }
41828         select.trigger('change');
41829         done();
41830     });
41831   };
41832
41833   chain.options = function() {
41834     var values = arguments;
41835     return this.addFutureAction("select '" + this.name + "' options '" + values + "'",
41836       function($window, $document, done) {
41837         var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
41838         select.val(values);
41839         select.trigger('change');
41840         done();
41841     });
41842   };
41843
41844   return function(name) {
41845     this.name = name;
41846     return chain;
41847   };
41848 });
41849
41850 /**
41851  * Usage:
41852  *    element(selector, label).count() get the number of elements that match selector
41853  *    element(selector, label).click() clicks an element
41854  *    element(selector, label).mouseover() mouseover an element
41855  *    element(selector, label).mousedown() mousedown an element
41856  *    element(selector, label).mouseup() mouseup an element
41857  *    element(selector, label).query(fn) executes fn(selectedElements, done)
41858  *    element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
41859  *    element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
41860  *    element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
41861  *    element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
41862  */
41863 angular.scenario.dsl('element', function() {
41864   var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
41865   var VALUE_METHODS = [
41866     'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
41867     'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
41868   ];
41869   var chain = {};
41870
41871   chain.count = function() {
41872     return this.addFutureAction("element '" + this.label + "' count",
41873       function($window, $document, done) {
41874         try {
41875           done(null, $document.elements().length);
41876         } catch (e) {
41877           done(null, 0);
41878         }
41879     });
41880   };
41881
41882   chain.click = function() {
41883     return this.addFutureAction("element '" + this.label + "' click",
41884       function($window, $document, done) {
41885         var elements = $document.elements();
41886         var href = elements.attr('href');
41887         var eventProcessDefault = elements.trigger('click')[0];
41888
41889         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
41890           this.application.navigateTo(href, function() {
41891             done();
41892           }, done);
41893         } else {
41894           done();
41895         }
41896     });
41897   };
41898
41899   chain.dblclick = function() {
41900     return this.addFutureAction("element '" + this.label + "' dblclick",
41901       function($window, $document, done) {
41902         var elements = $document.elements();
41903         var href = elements.attr('href');
41904         var eventProcessDefault = elements.trigger('dblclick')[0];
41905
41906         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
41907           this.application.navigateTo(href, function() {
41908             done();
41909           }, done);
41910         } else {
41911           done();
41912         }
41913     });
41914   };
41915
41916   chain.mouseover = function() {
41917     return this.addFutureAction("element '" + this.label + "' mouseover",
41918       function($window, $document, done) {
41919         var elements = $document.elements();
41920         elements.trigger('mouseover');
41921         done();
41922     });
41923   };
41924
41925   chain.mousedown = function() {
41926       return this.addFutureAction("element '" + this.label + "' mousedown",
41927         function($window, $document, done) {
41928           var elements = $document.elements();
41929           elements.trigger('mousedown');
41930           done();
41931       });
41932     };
41933
41934   chain.mouseup = function() {
41935       return this.addFutureAction("element '" + this.label + "' mouseup",
41936         function($window, $document, done) {
41937           var elements = $document.elements();
41938           elements.trigger('mouseup');
41939           done();
41940       });
41941     };
41942
41943   chain.query = function(fn) {
41944     return this.addFutureAction('element ' + this.label + ' custom query',
41945       function($window, $document, done) {
41946         fn.call(this, $document.elements(), done);
41947     });
41948   };
41949
41950   angular.forEach(KEY_VALUE_METHODS, function(methodName) {
41951     chain[methodName] = function(name, value) {
41952       var args = arguments,
41953           futureName = (args.length == 1)
41954               ? "element '" + this.label + "' get " + methodName + " '" + name + "'"
41955               : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" +
41956                 value + "'";
41957
41958       return this.addFutureAction(futureName, function($window, $document, done) {
41959         var element = $document.elements();
41960         done(null, element[methodName].apply(element, args));
41961       });
41962     };
41963   });
41964
41965   angular.forEach(VALUE_METHODS, function(methodName) {
41966     chain[methodName] = function(value) {
41967       var args = arguments,
41968           futureName = (args.length === 0)
41969               ? "element '" + this.label + "' " + methodName
41970               : "element '" + this.label + "' set " + methodName + " to '" + value + "'";
41971
41972       return this.addFutureAction(futureName, function($window, $document, done) {
41973         var element = $document.elements();
41974         done(null, element[methodName].apply(element, args));
41975       });
41976     };
41977   });
41978
41979   return function(selector, label) {
41980     this.dsl.using(selector, label);
41981     return chain;
41982   };
41983 });
41984
41985 /**
41986  * Matchers for implementing specs. Follows the Jasmine spec conventions.
41987  */
41988
41989 angular.scenario.matcher('toEqual', function(expected) {
41990   return angular.equals(this.actual, expected);
41991 });
41992
41993 angular.scenario.matcher('toBe', function(expected) {
41994   return this.actual === expected;
41995 });
41996
41997 angular.scenario.matcher('toBeDefined', function() {
41998   return angular.isDefined(this.actual);
41999 });
42000
42001 angular.scenario.matcher('toBeTruthy', function() {
42002   return this.actual;
42003 });
42004
42005 angular.scenario.matcher('toBeFalsy', function() {
42006   return !this.actual;
42007 });
42008
42009 angular.scenario.matcher('toMatch', function(expected) {
42010   return new RegExp(expected).test(this.actual);
42011 });
42012
42013 angular.scenario.matcher('toBeNull', function() {
42014   return this.actual === null;
42015 });
42016
42017 angular.scenario.matcher('toContain', function(expected) {
42018   return includes(this.actual, expected);
42019 });
42020
42021 angular.scenario.matcher('toBeLessThan', function(expected) {
42022   return this.actual < expected;
42023 });
42024
42025 angular.scenario.matcher('toBeGreaterThan', function(expected) {
42026   return this.actual > expected;
42027 });
42028
42029 /**
42030  * User Interface for the Scenario Runner.
42031  *
42032  * TODO(esprehn): This should be refactored now that ObjectModel exists
42033  *  to use angular bindings for the UI.
42034  */
42035 angular.scenario.output('html', function(context, runner, model) {
42036   var specUiMap = {},
42037       lastStepUiMap = {};
42038
42039   context.append(
42040     '<div id="header">' +
42041     '  <h1><span class="angular">AngularJS</span>: Scenario Test Runner</h1>' +
42042     '  <ul id="status-legend" class="status-display">' +
42043     '    <li class="status-error">0 Errors</li>' +
42044     '    <li class="status-failure">0 Failures</li>' +
42045     '    <li class="status-success">0 Passed</li>' +
42046     '  </ul>' +
42047     '</div>' +
42048     '<div id="specs">' +
42049     '  <div class="test-children"></div>' +
42050     '</div>'
42051   );
42052
42053   runner.on('InteractivePause', function(spec) {
42054     var ui = lastStepUiMap[spec.id];
42055     ui.find('.test-title').
42056       html('paused... <a href="javascript:resume()">resume</a> when ready.');
42057   });
42058
42059   runner.on('SpecBegin', function(spec) {
42060     var ui = findContext(spec);
42061     ui.find('> .tests').append(
42062       '<li class="status-pending test-it"></li>'
42063     );
42064     ui = ui.find('> .tests li:last');
42065     ui.append(
42066       '<div class="test-info">' +
42067       '  <p class="test-title">' +
42068       '    <span class="timer-result"></span>' +
42069       '    <span class="test-name"></span>' +
42070       '  </p>' +
42071       '</div>' +
42072       '<div class="scrollpane">' +
42073       '  <ol class="test-actions"></ol>' +
42074       '</div>'
42075     );
42076     ui.find('> .test-info .test-name').text(spec.name);
42077     ui.find('> .test-info').click(function() {
42078       var scrollpane = ui.find('> .scrollpane');
42079       var actions = scrollpane.find('> .test-actions');
42080       var name = context.find('> .test-info .test-name');
42081       if (actions.find(':visible').length) {
42082         actions.hide();
42083         name.removeClass('open').addClass('closed');
42084       } else {
42085         actions.show();
42086         scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
42087         name.removeClass('closed').addClass('open');
42088       }
42089     });
42090
42091     specUiMap[spec.id] = ui;
42092   });
42093
42094   runner.on('SpecError', function(spec, error) {
42095     var ui = specUiMap[spec.id];
42096     ui.append('<pre></pre>');
42097     ui.find('> pre').text(formatException(error));
42098   });
42099
42100   runner.on('SpecEnd', function(spec) {
42101     var ui = specUiMap[spec.id];
42102     spec = model.getSpec(spec.id);
42103     ui.removeClass('status-pending');
42104     ui.addClass('status-' + spec.status);
42105     ui.find("> .test-info .timer-result").text(spec.duration + "ms");
42106     if (spec.status === 'success') {
42107       ui.find('> .test-info .test-name').addClass('closed');
42108       ui.find('> .scrollpane .test-actions').hide();
42109     }
42110     updateTotals(spec.status);
42111   });
42112
42113   runner.on('StepBegin', function(spec, step) {
42114     var ui = specUiMap[spec.id];
42115     spec = model.getSpec(spec.id);
42116     step = spec.getLastStep();
42117     ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
42118     var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
42119     stepUi.append(
42120       '<div class="timer-result"></div>' +
42121       '<div class="test-title"></div>'
42122     );
42123     stepUi.find('> .test-title').text(step.name);
42124     var scrollpane = stepUi.parents('.scrollpane');
42125     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
42126   });
42127
42128   runner.on('StepFailure', function(spec, step, error) {
42129     var ui = lastStepUiMap[spec.id];
42130     addError(ui, step.line, error);
42131   });
42132
42133   runner.on('StepError', function(spec, step, error) {
42134     var ui = lastStepUiMap[spec.id];
42135     addError(ui, step.line, error);
42136   });
42137
42138   runner.on('StepEnd', function(spec, step) {
42139     var stepUi = lastStepUiMap[spec.id];
42140     spec = model.getSpec(spec.id);
42141     step = spec.getLastStep();
42142     stepUi.find('.timer-result').text(step.duration + 'ms');
42143     stepUi.removeClass('status-pending');
42144     stepUi.addClass('status-' + step.status);
42145     var scrollpane = specUiMap[spec.id].find('> .scrollpane');
42146     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
42147   });
42148
42149   /**
42150    * Finds the context of a spec block defined by the passed definition.
42151    *
42152    * @param {Object} The definition created by the Describe object.
42153    */
42154   function findContext(spec) {
42155     var currentContext = context.find('#specs');
42156     angular.forEach(model.getDefinitionPath(spec), function(defn) {
42157       var id = 'describe-' + defn.id;
42158       if (!context.find('#' + id).length) {
42159         currentContext.find('> .test-children').append(
42160           '<div class="test-describe" id="' + id + '">' +
42161           '  <h2></h2>' +
42162           '  <div class="test-children"></div>' +
42163           '  <ul class="tests"></ul>' +
42164           '</div>'
42165         );
42166         context.find('#' + id).find('> h2').text('describe: ' + defn.name);
42167       }
42168       currentContext = context.find('#' + id);
42169     });
42170     return context.find('#describe-' + spec.definition.id);
42171   }
42172
42173   /**
42174    * Updates the test counter for the status.
42175    *
42176    * @param {string} the status.
42177    */
42178   function updateTotals(status) {
42179     var legend = context.find('#status-legend .status-' + status);
42180     var parts = legend.text().split(' ');
42181     var value = (parts[0] * 1) + 1;
42182     legend.text(value + ' ' + parts[1]);
42183   }
42184
42185   /**
42186    * Add an error to a step.
42187    *
42188    * @param {Object} The JQuery wrapped context
42189    * @param {function()} fn() that should return the file/line number of the error
42190    * @param {Object} the error.
42191    */
42192   function addError(context, line, error) {
42193     context.find('.test-title').append('<pre></pre>');
42194     var message = _jQuery.trim(line() + '\n\n' + formatException(error));
42195     context.find('.test-title pre:last').text(message);
42196   }
42197 });
42198
42199 /**
42200  * Generates JSON output into a context.
42201  */
42202 angular.scenario.output('json', function(context, runner, model) {
42203   model.on('RunnerEnd', function() {
42204     context.text(angular.toJson(model.value));
42205   });
42206 });
42207
42208 /**
42209  * Generates XML output into a context.
42210  */
42211 angular.scenario.output('xml', function(context, runner, model) {
42212   var $ = function(args) {return new context.init(args);};
42213   model.on('RunnerEnd', function() {
42214     var scenario = $('<scenario></scenario>');
42215     context.append(scenario);
42216     serializeXml(scenario, model.value);
42217   });
42218
42219   /**
42220    * Convert the tree into XML.
42221    *
42222    * @param {Object} context jQuery context to add the XML to.
42223    * @param {Object} tree node to serialize
42224    */
42225   function serializeXml(context, tree) {
42226      angular.forEach(tree.children, function(child) {
42227        var describeContext = $('<describe></describe>');
42228        describeContext.attr('id', child.id);
42229        describeContext.attr('name', child.name);
42230        context.append(describeContext);
42231        serializeXml(describeContext, child);
42232      });
42233      var its = $('<its></its>');
42234      context.append(its);
42235      angular.forEach(tree.specs, function(spec) {
42236        var it = $('<it></it>');
42237        it.attr('id', spec.id);
42238        it.attr('name', spec.name);
42239        it.attr('duration', spec.duration);
42240        it.attr('status', spec.status);
42241        its.append(it);
42242        angular.forEach(spec.steps, function(step) {
42243          var stepContext = $('<step></step>');
42244          stepContext.attr('name', step.name);
42245          stepContext.attr('duration', step.duration);
42246          stepContext.attr('status', step.status);
42247          it.append(stepContext);
42248          if (step.error) {
42249            var error = $('<error></error>');
42250            stepContext.append(error);
42251            error.text(formatException(step.error));
42252          }
42253        });
42254      });
42255    }
42256 });
42257
42258 /**
42259  * Creates a global value $result with the result of the runner.
42260  */
42261 angular.scenario.output('object', function(context, runner, model) {
42262   runner.$window.$result = model.value;
42263 });
42264
42265 bindJQuery();
42266 publishExternalAPI(angular);
42267
42268 var $runner = new angular.scenario.Runner(window),
42269     scripts = window.document.getElementsByTagName('script'),
42270     script = scripts[scripts.length - 1],
42271     config = {};
42272
42273 angular.forEach(script.attributes, function(attr) {
42274   var match = attr.name.match(/ng[:\-](.*)/);
42275   if (match) {
42276     config[match[1]] = attr.value || true;
42277   }
42278 });
42279
42280 if (config.autotest) {
42281   JQLite(window.document).ready(function() {
42282     angular.scenario.setUpAndRun(config);
42283   });
42284 }
42285 })(window);
42286
42287
42288 !window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide:not(.ng-hide-animate) {\n  display: none !important;\n}\n\nng\\:form {\n  display: block;\n}\n\n.ng-animate-shim {\n  visibility:hidden;\n}\n\n.ng-anchor {\n  position:absolute;\n}\n</style>');
42289 !window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n  font-family: Arial, sans-serif;\n  margin: 0;\n  font-size: 14px;\n}\n\n#system-error {\n  font-size: 1.5em;\n  text-align: center;\n}\n\n#json, #xml {\n  display: none;\n}\n\n#header {\n  position: fixed;\n  width: 100%;\n}\n\n#specs {\n  padding-top: 50px;\n}\n\n#header .angular {\n  font-family: Courier New, monospace;\n  font-weight: bold;\n}\n\n#header h1 {\n  font-weight: normal;\n  float: left;\n  font-size: 30px;\n  line-height: 30px;\n  margin: 0;\n  padding: 10px 10px;\n  height: 30px;\n}\n\n#application h2,\n#specs h2 {\n  margin: 0;\n  padding: 0.5em;\n  font-size: 1.1em;\n}\n\n#status-legend {\n  margin-top: 10px;\n  margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n  overflow: hidden;\n}\n\n#application {\n  margin: 10px;\n}\n\n#application iframe {\n  width: 100%;\n  height: 758px;\n}\n\n#application .popout {\n  float: right;\n}\n\n#application iframe {\n  border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n  list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n  margin: 0;\n  padding: 0;\n}\n\n.test-info {\n  margin-left: 1em;\n  margin-top: 0.5em;\n  border-radius: 8px 0 0 8px;\n  -webkit-border-radius: 8px 0 0 8px;\n  -moz-border-radius: 8px 0 0 8px;\n  cursor: pointer;\n}\n\n.test-info:hover .test-name {\n  text-decoration: underline;\n}\n\n.test-info .closed:before {\n  content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n  content: \'\\25be\\00A0\';\n  font-weight: bold;\n}\n\n.test-it ol {\n  margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n  float: right;\n}\n\n.status-display li {\n  padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n  display: inline-block;\n  margin: 0;\n  padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n  display: table-cell;\n  padding-left: 0.5em;\n  padding-right: 0.5em;\n}\n\n.test-actions {\n  display: table;\n}\n\n.test-actions li {\n  display: table-row;\n}\n\n.timer-result {\n  width: 4em;\n  padding: 0 10px;\n  text-align: right;\n  font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n  clear: left;\n  color: black;\n  margin-left: 6em;\n}\n\n.test-describe {\n  padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n  margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n  content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n   max-height: 20em;\n   overflow: auto;\n}\n\n/** Colors */\n\n#header {\n  background-color: #F2C200;\n}\n\n#specs h2 {\n  border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n  background-color: #efefef;\n}\n\n#application {\n  border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n  border-left: 1px solid #BABAD1;\n  border-right: 1px solid #BABAD1;\n  border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n  border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n  background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n  background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n  background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n  background-color: black;\n  color: white;\n}\n\n.test-actions .status-success .test-title {\n  color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n  color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n  color: black;\n}\n\n.test-actions .timer-result {\n  color: #888;\n}\n</style>');